xref: /aosp_15_r20/frameworks/base/services/core/jni/com_android_server_UsbDeviceManager.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "UsbDeviceManagerJNI"
18 #include <android-base/properties.h>
19 #include <android-base/unique_fd.h>
20 #include <core_jni_helpers.h>
21 #include <fcntl.h>
22 #include <linux/usb/f_accessory.h>
23 #include <nativehelper/JNIPlatformHelp.h>
24 #include <nativehelper/ScopedUtfChars.h>
25 #include <stdio.h>
26 #include <sys/epoll.h>
27 #include <sys/ioctl.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 
31 #include <thread>
32 
33 #include "MtpDescriptors.h"
34 #include "android_runtime/AndroidRuntime.h"
35 #include "android_runtime/Log.h"
36 #include "jni.h"
37 #include "utils/Log.h"
38 
39 #define DRIVER_NAME "/dev/usb_accessory"
40 #define EPOLL_MAX_EVENTS 4
41 #define USB_STATE_MAX_LEN 20
42 
43 namespace android
44 {
45 
46 static JavaVM *gvm = nullptr;
47 static jmethodID gUpdateGadgetStateMethod;
48 
49 static struct parcel_file_descriptor_offsets_t
50 {
51     jclass mClass;
52     jmethodID mConstructor;
53 } gParcelFileDescriptorOffsets;
54 
55 /*
56  * NativeGadgetMonitorThread starts a new thread to monitor udc state by epoll,
57  * convert and update the state to UsbDeviceManager.
58  */
59 class NativeGadgetMonitorThread {
60     android::base::unique_fd mMonitorFd;
61     int mPipefd[2];
62     std::thread mThread;
63     jobject mCallbackObj;
64     std::string mGadgetState;
65 
handleStateUpdate(const char * state)66     void handleStateUpdate(const char *state) {
67         JNIEnv *env = AndroidRuntime::getJNIEnv();
68         std::string gadgetState;
69 
70         if (!std::strcmp(state, "not attached\n")) {
71             gadgetState = "DISCONNECTED";
72         } else if (!std::strcmp(state, "attached\n") || !std::strcmp(state, "powered\n") ||
73                    !std::strcmp(state, "default\n") || !std::strcmp(state, "addressed\n")) {
74             gadgetState = "CONNECTED";
75         } else if (!std::strcmp(state, "configured\n")) {
76             gadgetState = "CONFIGURED";
77         } else if (!std::strcmp(state, "suspended\n")) {
78             return;
79         } else {
80             ALOGE("Unknown gadget state %s", state);
81             return;
82         }
83 
84         if (mGadgetState.compare(gadgetState)) {
85             mGadgetState = gadgetState;
86             jstring obj = env->NewStringUTF(gadgetState.c_str());
87             env->CallVoidMethod(mCallbackObj, gUpdateGadgetStateMethod, obj);
88         }
89     }
90 
setupEpoll(android::base::unique_fd & epollFd)91     int setupEpoll(android::base::unique_fd &epollFd) {
92         struct epoll_event ev;
93 
94         ev.data.fd = mMonitorFd.get();
95         ev.events = EPOLLPRI;
96         if (epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, mMonitorFd.get(), &ev) != 0) {
97             ALOGE("epoll_ctl failed for monitor fd; errno=%d", errno);
98             return errno;
99         }
100 
101         ev.data.fd = mPipefd[0];
102         ev.events = EPOLLIN;
103         if (epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, mPipefd[0], &ev) != 0) {
104             ALOGE("epoll_ctl failed for pipe fd; errno=%d", errno);
105             return errno;
106         }
107 
108         return 0;
109     }
110 
monitorLoop()111     void monitorLoop() {
112         android::base::unique_fd epollFd(epoll_create(EPOLL_MAX_EVENTS));
113         if (epollFd.get() == -1) {
114             ALOGE("epoll_create failed; errno=%d", errno);
115             return;
116         }
117         if (setupEpoll(epollFd) != 0) return;
118 
119         JNIEnv *env = nullptr;
120         JavaVMAttachArgs aargs = {JNI_VERSION_1_4, "NativeGadgetMonitorThread", nullptr};
121         if (gvm->AttachCurrentThread(&env, &aargs) != JNI_OK || env == nullptr) {
122             ALOGE("Couldn't attach thread");
123             return;
124         }
125 
126         struct epoll_event events[EPOLL_MAX_EVENTS];
127         int nevents = 0;
128         while (true) {
129             nevents = epoll_wait(epollFd.get(), events, EPOLL_MAX_EVENTS, -1);
130             if (nevents < 0) {
131                 ALOGE("usb epoll_wait failed; errno=%d", errno);
132                 continue;
133             }
134             for (int i = 0; i < nevents; ++i) {
135                 int fd = events[i].data.fd;
136                 if (fd == mPipefd[0]) {
137                     goto exit;
138                 } else if (fd == mMonitorFd.get()) {
139                     char state[USB_STATE_MAX_LEN] = {0};
140                     lseek(fd, 0, SEEK_SET);
141                     read(fd, &state, USB_STATE_MAX_LEN);
142                     handleStateUpdate(state);
143                 }
144             }
145         }
146 
147     exit:
148         auto res = gvm->DetachCurrentThread();
149         ALOGE_IF(res != JNI_OK, "Couldn't detach thread");
150         return;
151     }
152 
stop()153     void stop() {
154         if (mThread.joinable()) {
155             int c = 'q';
156             write(mPipefd[1], &c, 1);
157             mThread.join();
158         }
159     }
160 
161     DISALLOW_COPY_AND_ASSIGN(NativeGadgetMonitorThread);
162 
163 public:
NativeGadgetMonitorThread(jobject obj,android::base::unique_fd monitorFd)164     explicit NativeGadgetMonitorThread(jobject obj, android::base::unique_fd monitorFd)
165           : mMonitorFd(std::move(monitorFd)), mGadgetState("") {
166         mCallbackObj = AndroidRuntime::getJNIEnv()->NewGlobalRef(obj);
167         pipe(mPipefd);
168         mThread = std::thread(&NativeGadgetMonitorThread::monitorLoop, this);
169     }
170 
~NativeGadgetMonitorThread()171     ~NativeGadgetMonitorThread() {
172         stop();
173         close(mPipefd[0]);
174         close(mPipefd[1]);
175         AndroidRuntime::getJNIEnv()->DeleteGlobalRef(mCallbackObj);
176     }
177 };
178 static std::unique_ptr<NativeGadgetMonitorThread> sGadgetMonitorThread;
179 
set_accessory_string(JNIEnv * env,int fd,int cmd,jobjectArray strArray,int index)180 static void set_accessory_string(JNIEnv *env, int fd, int cmd, jobjectArray strArray, int index)
181 {
182     char buffer[256];
183 
184     buffer[0] = 0;
185     ioctl(fd, cmd, buffer);
186     if (buffer[0]) {
187         jstring obj = env->NewStringUTF(buffer);
188         env->SetObjectArrayElement(strArray, index, obj);
189         env->DeleteLocalRef(obj);
190     }
191 }
192 
193 
android_server_UsbDeviceManager_getAccessoryStrings(JNIEnv * env,jobject)194 static jobjectArray android_server_UsbDeviceManager_getAccessoryStrings(JNIEnv *env,
195                                                                         jobject /* thiz */)
196 {
197     int fd = open(DRIVER_NAME, O_RDWR);
198     if (fd < 0) {
199         ALOGE("could not open %s", DRIVER_NAME);
200         return NULL;
201     }
202     jclass stringClass = env->FindClass("java/lang/String");
203     jobjectArray strArray = env->NewObjectArray(6, stringClass, NULL);
204     if (!strArray) goto out;
205     set_accessory_string(env, fd, ACCESSORY_GET_STRING_MANUFACTURER, strArray, 0);
206     set_accessory_string(env, fd, ACCESSORY_GET_STRING_MODEL, strArray, 1);
207     set_accessory_string(env, fd, ACCESSORY_GET_STRING_DESCRIPTION, strArray, 2);
208     set_accessory_string(env, fd, ACCESSORY_GET_STRING_VERSION, strArray, 3);
209     set_accessory_string(env, fd, ACCESSORY_GET_STRING_URI, strArray, 4);
210     set_accessory_string(env, fd, ACCESSORY_GET_STRING_SERIAL, strArray, 5);
211 
212 out:
213     close(fd);
214     return strArray;
215 }
216 
android_server_UsbDeviceManager_openAccessory(JNIEnv * env,jobject)217 static jobject android_server_UsbDeviceManager_openAccessory(JNIEnv *env, jobject /* thiz */)
218 {
219     int fd = open(DRIVER_NAME, O_RDWR);
220     if (fd < 0) {
221         ALOGE("could not open %s", DRIVER_NAME);
222         return NULL;
223     }
224     jobject fileDescriptor = jniCreateFileDescriptor(env, fd);
225     if (fileDescriptor == NULL) {
226         close(fd);
227         return NULL;
228     }
229     return env->NewObject(gParcelFileDescriptorOffsets.mClass,
230         gParcelFileDescriptorOffsets.mConstructor, fileDescriptor);
231 }
232 
android_server_UsbDeviceManager_isStartRequested(JNIEnv *,jobject)233 static jboolean android_server_UsbDeviceManager_isStartRequested(JNIEnv* /* env */,
234                                                                  jobject /* thiz */)
235 {
236     int fd = open(DRIVER_NAME, O_RDWR);
237     if (fd < 0) {
238         ALOGE("could not open %s", DRIVER_NAME);
239         return false;
240     }
241     int result = ioctl(fd, ACCESSORY_IS_START_REQUESTED);
242     close(fd);
243     return (result == 1);
244 }
245 
android_server_UsbDeviceManager_openControl(JNIEnv * env,jobject,jstring jFunction)246 static jobject android_server_UsbDeviceManager_openControl(JNIEnv *env, jobject /* thiz */, jstring jFunction) {
247     ScopedUtfChars function(env, jFunction);
248     bool ptp = false;
249     int fd = -1;
250     if (!strcmp(function.c_str(), "ptp")) {
251         ptp = true;
252     }
253     if (!strcmp(function.c_str(), "mtp") || ptp) {
254         fd = TEMP_FAILURE_RETRY(open(ptp ? FFS_PTP_EP0 : FFS_MTP_EP0, O_RDWR));
255         if (fd < 0) {
256             ALOGE("could not open control for %s %s", function.c_str(), strerror(errno));
257             return NULL;
258         }
259         if (!writeDescriptors(fd, ptp)) {
260             close(fd);
261             return NULL;
262         }
263     }
264 
265     jobject jifd = jniCreateFileDescriptor(env, fd);
266     if (jifd == NULL) {
267         // OutOfMemoryError will be pending.
268         close(fd);
269     }
270     return jifd;
271 }
272 
android_server_UsbDeviceManager_startGadgetMonitor(JNIEnv * env,jobject thiz,jstring jUdcName)273 static jboolean android_server_UsbDeviceManager_startGadgetMonitor(JNIEnv *env, jobject thiz,
274                                                                    jstring jUdcName) {
275     std::string filePath;
276     ScopedUtfChars udcName(env, jUdcName);
277 
278     filePath = "/sys/class/udc/" + std::string(udcName.c_str()) + "/state";
279     android::base::unique_fd fd(open(filePath.c_str(), O_RDONLY));
280 
281     if (fd.get() == -1) {
282         ALOGE("Cannot open %s", filePath.c_str());
283         return JNI_FALSE;
284     }
285 
286     ALOGI("Start monitoring %s", filePath.c_str());
287     sGadgetMonitorThread.reset(new NativeGadgetMonitorThread(thiz, std::move(fd)));
288 
289     return JNI_TRUE;
290 }
291 
android_server_UsbDeviceManager_stopGadgetMonitor(JNIEnv * env,jobject)292 static void android_server_UsbDeviceManager_stopGadgetMonitor(JNIEnv *env, jobject /* thiz */) {
293     sGadgetMonitorThread.reset();
294     return;
295 }
296 
android_server_UsbDeviceManager_waitAndGetProperty(JNIEnv * env,jobject thiz,jstring jPropName)297 static jstring android_server_UsbDeviceManager_waitAndGetProperty(JNIEnv *env, jobject thiz,
298                                                                   jstring jPropName) {
299     ScopedUtfChars propName(env, jPropName);
300     std::string propValue;
301 
302     while (!android::base::WaitForPropertyCreation(propName.c_str()));
303     propValue = android::base::GetProperty(propName.c_str(), "" /* default */);
304 
305     return env->NewStringUTF(propValue.c_str());
306 }
307 
308 static const JNINativeMethod method_table[] = {
309         {"nativeGetAccessoryStrings", "()[Ljava/lang/String;",
310          (void *)android_server_UsbDeviceManager_getAccessoryStrings},
311         {"nativeOpenAccessory", "()Landroid/os/ParcelFileDescriptor;",
312          (void *)android_server_UsbDeviceManager_openAccessory},
313         {"nativeIsStartRequested", "()Z", (void *)android_server_UsbDeviceManager_isStartRequested},
314         {"nativeOpenControl", "(Ljava/lang/String;)Ljava/io/FileDescriptor;",
315          (void *)android_server_UsbDeviceManager_openControl},
316         {"nativeStartGadgetMonitor", "(Ljava/lang/String;)Z",
317          (void *)android_server_UsbDeviceManager_startGadgetMonitor},
318         {"nativeStopGadgetMonitor", "()V",
319          (void *)android_server_UsbDeviceManager_stopGadgetMonitor},
320         {"nativeWaitAndGetProperty", "(Ljava/lang/String;)Ljava/lang/String;",
321          (void *)android_server_UsbDeviceManager_waitAndGetProperty},
322 };
323 
register_android_server_UsbDeviceManager(JavaVM * vm,JNIEnv * env)324 int register_android_server_UsbDeviceManager(JavaVM *vm, JNIEnv *env) {
325     gvm = vm;
326 
327     jclass clazz = env->FindClass("com/android/server/usb/UsbDeviceManager");
328     if (clazz == NULL) {
329         ALOGE("Can't find com/android/server/usb/UsbDeviceManager");
330         return -1;
331     }
332 
333     gUpdateGadgetStateMethod =
334             GetMethodIDOrDie(env, clazz, "updateGadgetState", "(Ljava/lang/String;)V");
335 
336     clazz = env->FindClass("android/os/ParcelFileDescriptor");
337     LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor");
338     gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
339     gParcelFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "(Ljava/io/FileDescriptor;)V");
340     LOG_FATAL_IF(gParcelFileDescriptorOffsets.mConstructor == NULL,
341                  "Unable to find constructor for android.os.ParcelFileDescriptor");
342 
343     return jniRegisterNativeMethods(env, "com/android/server/usb/UsbDeviceManager",
344             method_table, NELEM(method_table));
345 }
346 };
347