VirtualTouchpadService.cpp revision 4b64dd48b6896d6b963f0a3a0259d3d2a7076a9e
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 13namespace android { 14namespace dvr { 15 16namespace { 17const String16 kDumpPermission("android.permission.DUMP"); 18const String16 kTouchPermission("android.permission.RESTRICTED_VR_ACCESS"); 19} // anonymous namespace 20 21VirtualTouchpadService::~VirtualTouchpadService() { 22 if (client_pid_) { 23 client_pid_ = 0; 24 touchpad_->Detach(); 25 } 26} 27 28binder::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 } 49 client_pid_ = pid; 50 if (const status_t error = touchpad_->Attach()) { 51 return binder::Status::fromStatusT(error); 52 } 53 return binder::Status::ok(); 54} 55 56binder::Status VirtualTouchpadService::detach() { 57 if (!CheckPermissions()) { 58 return binder::Status::fromStatusT(PERMISSION_DENIED); 59 } 60 client_pid_ = 0; 61 if (const status_t error = touchpad_->Detach()) { 62 return binder::Status::fromStatusT(error); 63 } 64 return binder::Status::ok(); 65} 66 67binder::Status VirtualTouchpadService::touch(int touchpad, float x, float y, 68 float pressure) { 69 if (!CheckPermissions()) { 70 return binder::Status::fromStatusT(PERMISSION_DENIED); 71 } 72 if (const status_t error = touchpad_->Touch(touchpad, x, y, pressure)) { 73 return binder::Status::fromStatusT(error); 74 } 75 return binder::Status::ok(); 76} 77 78binder::Status VirtualTouchpadService::buttonState(int touchpad, int buttons) { 79 if (!CheckPermissions()) { 80 return binder::Status::fromStatusT(PERMISSION_DENIED); 81 } 82 if (const status_t error = touchpad_->ButtonState(touchpad, buttons)) { 83 return binder::Status::fromStatusT(error); 84 } 85 return binder::Status::ok(); 86} 87 88status_t VirtualTouchpadService::dump( 89 int fd, const Vector<String16>& args[[gnu::unused]]) { 90 String8 result; 91 const android::IPCThreadState* ipc = android::IPCThreadState::self(); 92 const pid_t pid = ipc->getCallingPid(); 93 const uid_t uid = ipc->getCallingUid(); 94 if ((uid != AID_SHELL) && 95 !PermissionCache::checkPermission(kDumpPermission, pid, uid)) { 96 result.appendFormat("Permission denial: can't dump " LOG_TAG 97 " from pid=%ld, uid=%ld\n", 98 static_cast<long>(pid), static_cast<long>(uid)); 99 } else { 100 result.appendFormat("[service]\nclient_pid = %ld\n\n", 101 static_cast<long>(client_pid_)); 102 touchpad_->dumpInternal(result); 103 } 104 write(fd, result.string(), result.size()); 105 return OK; 106} 107 108bool VirtualTouchpadService::CheckPermissions() { 109 pid_t pid; 110 if (!CheckTouchPermission(&pid)) { 111 return false; 112 } 113 if (client_pid_ != pid) { 114 ALOGE("pid=%ld is not owner", static_cast<long>(pid)); 115 return false; 116 } 117 return true; 118} 119 120bool VirtualTouchpadService::CheckTouchPermission(pid_t* out_pid) { 121 const android::IPCThreadState* ipc = android::IPCThreadState::self(); 122 *out_pid = ipc->getCallingPid(); 123#ifdef SELINUX_ACCESS_CONTROL 124 return true; 125#else 126 const uid_t uid = ipc->getCallingUid(); 127 const bool permission = PermissionCache::checkPermission(kTouchPermission, *out_pid, uid); 128 if (!permission) { 129 ALOGE("permission denied to pid=%ld uid=%ld", static_cast<long>(*out_pid), 130 static_cast<long>(uid)); 131 } 132 return permission; 133#endif 134} 135 136} // namespace dvr 137} // namespace android 138