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    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
58binder::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
69binder::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
80binder::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
90status_t VirtualTouchpadService::dump(
91    int fd, const Vector<String16>& args[[gnu::unused]]) {
92  String8 result;
93  const android::IPCThreadState* ipc = android::IPCThreadState::self();
94  const pid_t pid = ipc->getCallingPid();
95  const uid_t uid = ipc->getCallingUid();
96  if ((uid != AID_SHELL) &&
97      !PermissionCache::checkPermission(kDumpPermission, pid, uid)) {
98    result.appendFormat("Permission denial: can't dump " LOG_TAG
99                        " from pid=%ld, uid=%ld\n",
100                        static_cast<long>(pid), static_cast<long>(uid));
101  } else {
102    result.appendFormat("[service]\nclient_pid = %ld\n\n",
103                        static_cast<long>(client_pid_));
104    touchpad_->dumpInternal(result);
105  }
106  write(fd, result.string(), result.size());
107  return OK;
108}
109
110bool VirtualTouchpadService::CheckPermissions() {
111  pid_t pid;
112  if (!CheckTouchPermission(&pid)) {
113    return false;
114  }
115  if (client_pid_ != pid) {
116    ALOGE("pid=%ld is not owner", static_cast<long>(pid));
117    return false;
118  }
119  return true;
120}
121
122bool VirtualTouchpadService::CheckTouchPermission(pid_t* out_pid) {
123  const android::IPCThreadState* ipc = android::IPCThreadState::self();
124  *out_pid = ipc->getCallingPid();
125  const uid_t uid = ipc->getCallingUid();
126  const bool permission = PermissionCache::checkPermission(kTouchPermission, *out_pid, uid);
127  if (!permission) {
128    ALOGE("permission denied to pid=%ld uid=%ld", static_cast<long>(*out_pid),
129          static_cast<long>(uid));
130  }
131  return permission;
132}
133
134}  // namespace dvr
135}  // namespace android
136