File: VirtualTouchpadService.cpp

package info (click to toggle)
android-platform-tools 34.0.5-12
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 150,900 kB
  • sloc: cpp: 805,786; java: 293,500; ansic: 128,288; xml: 127,491; python: 41,481; sh: 14,245; javascript: 9,665; cs: 3,846; asm: 2,049; makefile: 1,917; yacc: 440; awk: 368; ruby: 183; sql: 140; perl: 88; lex: 67
file content (145 lines) | stat: -rw-r--r-- 4,730 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#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.c_str(), 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