Home | History | Annotate | Download | only in virtual_touchpad
      1 #include "VirtualTouchpadService.h"
      2 
      3 #include <inttypes.h>
      4 
      5 #include <binder/IPCThreadState.h>
      6 #include <binder/PermissionCache.h>
      7 #include <binder/Status.h>
      8 #include <cutils/log.h>
      9 #include <linux/input.h>
     10 #include <private/android_filesystem_config.h>
     11 #include <utils/Errors.h>
     12 
     13 namespace android {
     14 namespace dvr {
     15 
     16 namespace {
     17 const String16 kDumpPermission("android.permission.DUMP");
     18 const String16 kTouchPermission("android.permission.RESTRICTED_VR_ACCESS");
     19 }  // anonymous namespace
     20 
     21 VirtualTouchpadService::~VirtualTouchpadService() {
     22   if (client_pid_) {
     23     client_pid_ = 0;
     24     touchpad_->Detach();
     25   }
     26 }
     27 
     28 binder::Status VirtualTouchpadService::attach() {
     29   pid_t pid;
     30   if (!CheckTouchPermission(&pid)) {
     31     return binder::Status::fromStatusT(PERMISSION_DENIED);
     32   }
     33   if (client_pid_ == pid) {
     34     // The same client has called attach() twice with no intervening detach().
     35     // This indicates a problem with the client, so return an error.
     36     // However, since the client is already attached, any touchpad actions
     37     // it takes will still work.
     38     ALOGE("pid=%ld attached twice", static_cast<long>(pid));
     39     return binder::Status::fromStatusT(ALREADY_EXISTS);
     40   }
     41   if (client_pid_ != 0) {
     42     // Attach while another client is attached. This can happen if the client
     43     // dies without cleaning up after itself, so move ownership to the current
     44     // caller. If two actual clients have connected, the problem will be
     45     // reported when the previous client performs any touchpad action.
     46     ALOGE("pid=%ld replaces %ld", static_cast<long>(pid),
     47           static_cast<long>(client_pid_));
     48     client_pid_ = pid;
     49     return binder::Status::ok();
     50   }
     51   client_pid_ = pid;
     52   if (const status_t error = touchpad_->Attach()) {
     53     return binder::Status::fromStatusT(error);
     54   }
     55   return binder::Status::ok();
     56 }
     57 
     58 binder::Status VirtualTouchpadService::detach() {
     59   if (!CheckPermissions()) {
     60     return binder::Status::fromStatusT(PERMISSION_DENIED);
     61   }
     62   client_pid_ = 0;
     63   if (const status_t error = touchpad_->Detach()) {
     64     return binder::Status::fromStatusT(error);
     65   }
     66   return binder::Status::ok();
     67 }
     68 
     69 binder::Status VirtualTouchpadService::touch(int touchpad, float x, float y,
     70                                              float pressure) {
     71   if (!CheckPermissions()) {
     72     return binder::Status::fromStatusT(PERMISSION_DENIED);
     73   }
     74   if (const status_t error = touchpad_->Touch(touchpad, x, y, pressure)) {
     75     return binder::Status::fromStatusT(error);
     76   }
     77   return binder::Status::ok();
     78 }
     79 
     80 binder::Status VirtualTouchpadService::buttonState(int touchpad, int buttons) {
     81   if (!CheckPermissions()) {
     82     return binder::Status::fromStatusT(PERMISSION_DENIED);
     83   }
     84   if (const status_t error = touchpad_->ButtonState(touchpad, buttons)) {
     85     return binder::Status::fromStatusT(error);
     86   }
     87   return binder::Status::ok();
     88 }
     89 
     90 binder::Status VirtualTouchpadService::scroll(int touchpad, float x, float y) {
     91   if (!CheckPermissions()) {
     92     return binder::Status::fromStatusT(PERMISSION_DENIED);
     93   }
     94   if (const status_t error = touchpad_->Scroll(touchpad, x, y)) {
     95     return binder::Status::fromStatusT(error);
     96   }
     97   return binder::Status::ok();
     98 }
     99 
    100 status_t VirtualTouchpadService::dump(
    101     int fd, const Vector<String16>& args[[gnu::unused]]) {
    102   String8 result;
    103   const android::IPCThreadState* ipc = android::IPCThreadState::self();
    104   const pid_t pid = ipc->getCallingPid();
    105   const uid_t uid = ipc->getCallingUid();
    106   if ((uid != AID_SHELL) &&
    107       !PermissionCache::checkPermission(kDumpPermission, pid, uid)) {
    108     result.appendFormat("Permission denial: can't dump " LOG_TAG
    109                         " from pid=%ld, uid=%ld\n",
    110                         static_cast<long>(pid), static_cast<long>(uid));
    111   } else {
    112     result.appendFormat("[service]\nclient_pid = %ld\n\n",
    113                         static_cast<long>(client_pid_));
    114     touchpad_->dumpInternal(result);
    115   }
    116   write(fd, result.string(), result.size());
    117   return OK;
    118 }
    119 
    120 bool VirtualTouchpadService::CheckPermissions() {
    121   pid_t pid;
    122   if (!CheckTouchPermission(&pid)) {
    123     return false;
    124   }
    125   if (client_pid_ != pid) {
    126     ALOGE("pid=%ld is not owner", static_cast<long>(pid));
    127     return false;
    128   }
    129   return true;
    130 }
    131 
    132 bool VirtualTouchpadService::CheckTouchPermission(pid_t* out_pid) {
    133   const android::IPCThreadState* ipc = android::IPCThreadState::self();
    134   *out_pid = ipc->getCallingPid();
    135   const uid_t uid = ipc->getCallingUid();
    136   const bool permission = PermissionCache::checkPermission(kTouchPermission, *out_pid, uid);
    137   if (!permission) {
    138     ALOGE("permission denied to pid=%ld uid=%ld", static_cast<long>(*out_pid),
    139           static_cast<long>(uid));
    140   }
    141   return permission;
    142 }
    143 
    144 }  // namespace dvr
    145 }  // namespace android
    146