|  | #include "VirtualTouchpadService.h" | 
|  |  | 
|  | #include <inttypes.h> | 
|  |  | 
|  | #include <binder/IPCThreadState.h> | 
|  | #include <binder/PermissionCache.h> | 
|  | #include <binder/Status.h> | 
|  | #include <cutils/log.h> | 
|  | #include <linux/input.h> | 
|  | #include <private/android_filesystem_config.h> | 
|  | #include <utils/Errors.h> | 
|  |  | 
|  | namespace android { | 
|  | namespace dvr { | 
|  |  | 
|  | namespace { | 
|  | const String16 kDumpPermission("android.permission.DUMP"); | 
|  | const String16 kTouchPermission("android.permission.RESTRICTED_VR_ACCESS"); | 
|  | }  // anonymous namespace | 
|  |  | 
|  | VirtualTouchpadService::~VirtualTouchpadService() { | 
|  | if (client_pid_) { | 
|  | client_pid_ = 0; | 
|  | touchpad_->Detach(); | 
|  | } | 
|  | } | 
|  |  | 
|  | binder::Status VirtualTouchpadService::attach() { | 
|  | pid_t pid; | 
|  | if (!CheckTouchPermission(&pid)) { | 
|  | return binder::Status::fromStatusT(PERMISSION_DENIED); | 
|  | } | 
|  | if (client_pid_ == pid) { | 
|  | // The same client has called attach() twice with no intervening detach(). | 
|  | // This indicates a problem with the client, so return an error. | 
|  | // However, since the client is already attached, any touchpad actions | 
|  | // it takes will still work. | 
|  | ALOGE("pid=%ld attached twice", static_cast<long>(pid)); | 
|  | return binder::Status::fromStatusT(ALREADY_EXISTS); | 
|  | } | 
|  | if (client_pid_ != 0) { | 
|  | // Attach while another client is attached. This can happen if the client | 
|  | // dies without cleaning up after itself, so move ownership to the current | 
|  | // caller. If two actual clients have connected, the problem will be | 
|  | // reported when the previous client performs any touchpad action. | 
|  | ALOGE("pid=%ld replaces %ld", static_cast<long>(pid), | 
|  | static_cast<long>(client_pid_)); | 
|  | client_pid_ = pid; | 
|  | return binder::Status::ok(); | 
|  | } | 
|  | client_pid_ = pid; | 
|  | if (const status_t error = touchpad_->Attach()) { | 
|  | return binder::Status::fromStatusT(error); | 
|  | } | 
|  | return binder::Status::ok(); | 
|  | } | 
|  |  | 
|  | binder::Status VirtualTouchpadService::detach() { | 
|  | if (!CheckPermissions()) { | 
|  | return binder::Status::fromStatusT(PERMISSION_DENIED); | 
|  | } | 
|  | client_pid_ = 0; | 
|  | if (const status_t error = touchpad_->Detach()) { | 
|  | return binder::Status::fromStatusT(error); | 
|  | } | 
|  | return binder::Status::ok(); | 
|  | } | 
|  |  | 
|  | binder::Status VirtualTouchpadService::touch(int touchpad, float x, float y, | 
|  | float pressure) { | 
|  | if (!CheckPermissions()) { | 
|  | return binder::Status::fromStatusT(PERMISSION_DENIED); | 
|  | } | 
|  | if (const status_t error = touchpad_->Touch(touchpad, x, y, pressure)) { | 
|  | return binder::Status::fromStatusT(error); | 
|  | } | 
|  | return binder::Status::ok(); | 
|  | } | 
|  |  | 
|  | binder::Status VirtualTouchpadService::buttonState(int touchpad, int buttons) { | 
|  | if (!CheckPermissions()) { | 
|  | return binder::Status::fromStatusT(PERMISSION_DENIED); | 
|  | } | 
|  | if (const status_t error = touchpad_->ButtonState(touchpad, buttons)) { | 
|  | return binder::Status::fromStatusT(error); | 
|  | } | 
|  | return binder::Status::ok(); | 
|  | } | 
|  |  | 
|  | binder::Status VirtualTouchpadService::scroll(int touchpad, float x, float y) { | 
|  | if (!CheckPermissions()) { | 
|  | return binder::Status::fromStatusT(PERMISSION_DENIED); | 
|  | } | 
|  | if (const status_t error = touchpad_->Scroll(touchpad, x, y)) { | 
|  | return binder::Status::fromStatusT(error); | 
|  | } | 
|  | return binder::Status::ok(); | 
|  | } | 
|  |  | 
|  | status_t VirtualTouchpadService::dump( | 
|  | int fd, const Vector<String16>& args[[gnu::unused]]) { | 
|  | String8 result; | 
|  | const android::IPCThreadState* ipc = android::IPCThreadState::self(); | 
|  | const pid_t pid = ipc->getCallingPid(); | 
|  | const uid_t uid = ipc->getCallingUid(); | 
|  | if ((uid != AID_SHELL) && | 
|  | !PermissionCache::checkPermission(kDumpPermission, pid, uid)) { | 
|  | result.appendFormat("Permission denial: can't dump " LOG_TAG | 
|  | " from pid=%ld, uid=%ld\n", | 
|  | static_cast<long>(pid), static_cast<long>(uid)); | 
|  | } else { | 
|  | result.appendFormat("[service]\nclient_pid = %ld\n\n", | 
|  | static_cast<long>(client_pid_)); | 
|  | touchpad_->dumpInternal(result); | 
|  | } | 
|  | write(fd, result.string(), result.size()); | 
|  | return OK; | 
|  | } | 
|  |  | 
|  | bool VirtualTouchpadService::CheckPermissions() { | 
|  | pid_t pid; | 
|  | if (!CheckTouchPermission(&pid)) { | 
|  | return false; | 
|  | } | 
|  | if (client_pid_ != pid) { | 
|  | ALOGE("pid=%ld is not owner", static_cast<long>(pid)); | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool VirtualTouchpadService::CheckTouchPermission(pid_t* out_pid) { | 
|  | const android::IPCThreadState* ipc = android::IPCThreadState::self(); | 
|  | *out_pid = ipc->getCallingPid(); | 
|  | const uid_t uid = ipc->getCallingUid(); | 
|  | const bool permission = PermissionCache::checkPermission(kTouchPermission, *out_pid, uid); | 
|  | if (!permission) { | 
|  | ALOGE("permission denied to pid=%ld uid=%ld", static_cast<long>(*out_pid), | 
|  | static_cast<long>(uid)); | 
|  | } | 
|  | return permission; | 
|  | } | 
|  |  | 
|  | }  // namespace dvr | 
|  | }  // namespace android |