blob: 4f6bb153170a583bbea809ca6c00be22b7237ebe [file] [log] [blame]
Mike Lockwood98ef64e2010-06-29 16:42:13 -04001/*
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 "MtpServerJNI"
18#include "utils/Log.h"
19
20#include <stdio.h>
21#include <assert.h>
22#include <limits.h>
23#include <unistd.h>
24#include <fcntl.h>
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -040025#include <sys/ioctl.h>
Mike Lockwood98ef64e2010-06-29 16:42:13 -040026#include <utils/threads.h>
27
Mike Lockwood602bebd2010-09-02 09:58:48 -040028#ifdef HAVE_ANDROID_OS
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -040029#include <linux/usb/f_mtp.h>
Mike Lockwood602bebd2010-09-02 09:58:48 -040030#endif
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -040031
Mike Lockwood98ef64e2010-06-29 16:42:13 -040032#include "jni.h"
33#include "JNIHelp.h"
34#include "android_runtime/AndroidRuntime.h"
Mike Lockwooddad69272010-07-02 15:15:07 -040035#include "private/android_filesystem_config.h"
Mike Lockwood98ef64e2010-06-29 16:42:13 -040036
37#include "MtpServer.h"
Mike Lockwood467ca0d2011-02-18 09:07:14 -050038#include "MtpStorage.h"
Mike Lockwood98ef64e2010-06-29 16:42:13 -040039
Mike Lockwood81ea83d2010-06-30 17:49:41 -040040using namespace android;
Mike Lockwood98ef64e2010-06-29 16:42:13 -040041
Mike Lockwood7ae938be2011-04-05 10:21:27 -040042// MtpStorage class
43jclass clazz_MtpStorage;
44
45// MtpStorage fields
46static jfieldID field_MtpStorage_storageId;
47static jfieldID field_MtpStorage_path;
48static jfieldID field_MtpStorage_description;
49static jfieldID field_MtpStorage_reserveSpace;
Mike Lockwood51690542011-05-09 20:16:05 -070050static jfieldID field_MtpStorage_removable;
Mike Lockwood7ae938be2011-04-05 10:21:27 -040051
52static Mutex sMutex;
53
Mike Lockwood98ef64e2010-06-29 16:42:13 -040054// ----------------------------------------------------------------------------
55
Mike Lockwood0cd01362010-12-30 11:54:33 -050056// in android_mtp_MtpDatabase.cpp
Mike Lockwoodd21eac92010-07-03 00:44:05 -040057extern MtpDatabase* getMtpDatabase(JNIEnv *env, jobject database);
Mike Lockwood98ef64e2010-06-29 16:42:13 -040058
59// ----------------------------------------------------------------------------
60
Mike Lockwoodff164a72010-07-15 15:01:17 -040061#ifdef HAVE_ANDROID_OS
62
Mike Lockwood98ef64e2010-06-29 16:42:13 -040063static bool ExceptionCheck(void* env)
64{
65 return ((JNIEnv *)env)->ExceptionCheck();
66}
67
68class MtpThread : public Thread {
69private:
Mike Lockwoodd21eac92010-07-03 00:44:05 -040070 MtpDatabase* mDatabase;
Mike Lockwoodbe125a52010-07-12 18:54:16 -040071 MtpServer* mServer;
Mike Lockwood7ae938be2011-04-05 10:21:27 -040072 MtpStorageList mStorageList;
Mike Lockwood071b2b62011-01-25 09:29:27 -080073 bool mUsePtp;
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -040074 int mFd;
Mike Lockwood98ef64e2010-06-29 16:42:13 -040075
76public:
Mike Lockwood7ae938be2011-04-05 10:21:27 -040077 MtpThread(MtpDatabase* database)
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -040078 : mDatabase(database),
Mike Lockwood23ee42f2010-08-03 15:17:55 -040079 mServer(NULL),
Mike Lockwood66e57f62011-02-18 13:24:01 -050080 mUsePtp(false),
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -040081 mFd(-1)
Mike Lockwood98ef64e2010-06-29 16:42:13 -040082 {
83 }
84
Mike Lockwood467ca0d2011-02-18 09:07:14 -050085 virtual ~MtpThread() {
Mike Lockwood467ca0d2011-02-18 09:07:14 -050086 }
87
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -040088 void setPtpMode(bool usePtp) {
Mike Lockwood071b2b62011-01-25 09:29:27 -080089 mUsePtp = usePtp;
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -040090 }
91
Mike Lockwood7ae938be2011-04-05 10:21:27 -040092 void addStorage(MtpStorage *storage) {
93 mStorageList.push(storage);
94 if (mServer)
95 mServer->addStorage(storage);
96 }
97
98 void removeStorage(MtpStorageID id) {
99 MtpStorage* storage = mServer->getStorage(id);
100 if (storage) {
101 for (int i = 0; i < mStorageList.size(); i++) {
102 if (mStorageList[i] == storage) {
103 mStorageList.removeAt(i);
104 break;
105 }
Mike Lockwood66e57f62011-02-18 13:24:01 -0500106 }
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400107 if (mServer)
108 mServer->removeStorage(storage);
109 delete storage;
Mike Lockwood66e57f62011-02-18 13:24:01 -0500110 }
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400111 }
112
113 void start() {
114 run("MtpThread");
Mike Lockwood66e57f62011-02-18 13:24:01 -0500115 }
116
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400117 virtual bool threadLoop() {
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400118 sMutex.lock();
119
Mike Lockwood071b2b62011-01-25 09:29:27 -0800120 mFd = open("/dev/mtp_usb", O_RDWR);
121 if (mFd >= 0) {
122 ioctl(mFd, MTP_SET_INTERFACE_MODE,
123 (mUsePtp ? MTP_INTERFACE_MODE_PTP : MTP_INTERFACE_MODE_MTP));
Mike Lockwood897f8942011-01-19 10:11:28 -0800124
125 mServer = new MtpServer(mFd, mDatabase, AID_MEDIA_RW, 0664, 0775);
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400126 for (int i = 0; i < mStorageList.size(); i++) {
127 mServer->addStorage(mStorageList[i]);
128 }
Mike Lockwood071b2b62011-01-25 09:29:27 -0800129 } else {
130 LOGE("could not open MTP driver, errno: %d", errno);
131 }
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400132
133 sMutex.unlock();
134 mServer->run();
135 sMutex.lock();
136
137 close(mFd);
138 mFd = -1;
139 delete mServer;
140 mServer = NULL;
141
142 sMutex.unlock();
Mike Lockwood071b2b62011-01-25 09:29:27 -0800143 // delay a bit before retrying to avoid excessive spin
144 if (!exitPending()) {
145 sleep(1);
Mike Lockwood897f8942011-01-19 10:11:28 -0800146 }
Mike Lockwood2b2bff52010-08-18 12:32:26 -0400147
Mike Lockwood071b2b62011-01-25 09:29:27 -0800148 return true;
Mike Lockwooda1c91802011-01-18 20:11:29 -0800149 }
150
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400151 void sendObjectAdded(MtpObjectHandle handle) {
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400152 if (mServer)
153 mServer->sendObjectAdded(handle);
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400154 }
155
156 void sendObjectRemoved(MtpObjectHandle handle) {
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400157 if (mServer)
158 mServer->sendObjectRemoved(handle);
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400159 }
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400160};
161
Mike Lockwood071b2b62011-01-25 09:29:27 -0800162// This smart pointer is necessary for preventing MtpThread from exiting too early
163static sp<MtpThread> sThread;
164
Mike Lockwoodff164a72010-07-15 15:01:17 -0400165#endif // HAVE_ANDROID_OS
166
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400167static void
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400168android_mtp_MtpServer_setup(JNIEnv *env, jobject thiz, jobject javaDatabase)
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400169{
Mike Lockwoodff164a72010-07-15 15:01:17 -0400170#ifdef HAVE_ANDROID_OS
Mike Lockwood071b2b62011-01-25 09:29:27 -0800171 // create the thread and assign it to the smart pointer
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400172 sThread = new MtpThread(getMtpDatabase(env, javaDatabase));
Mike Lockwoodff164a72010-07-15 15:01:17 -0400173#endif
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400174}
175
176static void
Mike Lockwood0cd01362010-12-30 11:54:33 -0500177android_mtp_MtpServer_start(JNIEnv *env, jobject thiz)
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400178{
Mike Lockwoodff164a72010-07-15 15:01:17 -0400179#ifdef HAVE_ANDROID_OS
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400180 sMutex.lock();
Mike Lockwood071b2b62011-01-25 09:29:27 -0800181 MtpThread *thread = sThread.get();
182 if (thread)
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400183 thread->start();
184 sMutex.unlock();
Mike Lockwoodff164a72010-07-15 15:01:17 -0400185#endif // HAVE_ANDROID_OS
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400186}
187
188static void
Mike Lockwood0cd01362010-12-30 11:54:33 -0500189android_mtp_MtpServer_stop(JNIEnv *env, jobject thiz)
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400190{
Mike Lockwoodff164a72010-07-15 15:01:17 -0400191#ifdef HAVE_ANDROID_OS
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400192 sMutex.lock();
Mike Lockwood071b2b62011-01-25 09:29:27 -0800193 MtpThread *thread = sThread.get();
194 if (thread) {
195 thread->requestExitAndWait();
196 sThread = NULL;
197 }
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400198 sMutex.unlock();
Mike Lockwoodff164a72010-07-15 15:01:17 -0400199#endif
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400200}
201
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400202static void
Mike Lockwood0cd01362010-12-30 11:54:33 -0500203android_mtp_MtpServer_send_object_added(JNIEnv *env, jobject thiz, jint handle)
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400204{
Mike Lockwoodff164a72010-07-15 15:01:17 -0400205#ifdef HAVE_ANDROID_OS
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400206 sMutex.lock();
Mike Lockwood071b2b62011-01-25 09:29:27 -0800207 MtpThread *thread = sThread.get();
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400208 if (thread)
209 thread->sendObjectAdded(handle);
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400210 sMutex.unlock();
Mike Lockwoodff164a72010-07-15 15:01:17 -0400211#endif
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400212}
213
214static void
Mike Lockwood0cd01362010-12-30 11:54:33 -0500215android_mtp_MtpServer_send_object_removed(JNIEnv *env, jobject thiz, jint handle)
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400216{
Mike Lockwoodff164a72010-07-15 15:01:17 -0400217#ifdef HAVE_ANDROID_OS
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400218 sMutex.lock();
Mike Lockwood071b2b62011-01-25 09:29:27 -0800219 MtpThread *thread = sThread.get();
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400220 if (thread)
221 thread->sendObjectRemoved(handle);
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400222 sMutex.unlock();
Mike Lockwoodff164a72010-07-15 15:01:17 -0400223#endif
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400224}
225
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -0400226static void
Mike Lockwood0cd01362010-12-30 11:54:33 -0500227android_mtp_MtpServer_set_ptp_mode(JNIEnv *env, jobject thiz, jboolean usePtp)
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -0400228{
229#ifdef HAVE_ANDROID_OS
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400230 sMutex.lock();
Mike Lockwood071b2b62011-01-25 09:29:27 -0800231 MtpThread *thread = sThread.get();
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -0400232 if (thread)
233 thread->setPtpMode(usePtp);
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400234 sMutex.unlock();
Mike Lockwooda1c91802011-01-18 20:11:29 -0800235#endif
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -0400236}
237
Mike Lockwood66e57f62011-02-18 13:24:01 -0500238static void
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400239android_mtp_MtpServer_add_storage(JNIEnv *env, jobject thiz, jobject jstorage)
Mike Lockwood66e57f62011-02-18 13:24:01 -0500240{
241#ifdef HAVE_ANDROID_OS
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400242 sMutex.lock();
243 MtpThread *thread = sThread.get();
244 if (thread) {
245 jint storageID = env->GetIntField(jstorage, field_MtpStorage_storageId);
246 jstring path = (jstring)env->GetObjectField(jstorage, field_MtpStorage_path);
247 jstring description = (jstring)env->GetObjectField(jstorage, field_MtpStorage_description);
248 jlong reserveSpace = env->GetLongField(jstorage, field_MtpStorage_reserveSpace);
Mike Lockwood51690542011-05-09 20:16:05 -0700249 jboolean removable = env->GetBooleanField(jstorage, field_MtpStorage_removable);
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400250
251 const char *pathStr = env->GetStringUTFChars(path, NULL);
252 const char *descriptionStr = env->GetStringUTFChars(description, NULL);
253
Mike Lockwood51690542011-05-09 20:16:05 -0700254 MtpStorage* storage = new MtpStorage(storageID, pathStr, descriptionStr,
255 reserveSpace, removable);
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400256 thread->addStorage(storage);
257
258 env->ReleaseStringUTFChars(path, pathStr);
259 env->ReleaseStringUTFChars(description, descriptionStr);
260 } else {
261 LOGE("MtpThread is null in add_storage");
262 }
263 sMutex.unlock();
264#endif
265}
266
267static void
268android_mtp_MtpServer_remove_storage(JNIEnv *env, jobject thiz, jint storageId)
269{
270#ifdef HAVE_ANDROID_OS
271 sMutex.lock();
Mike Lockwood66e57f62011-02-18 13:24:01 -0500272 MtpThread *thread = sThread.get();
273 if (thread)
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400274 thread->removeStorage(storageId);
275 else
276 LOGE("MtpThread is null in remove_storage");
277 sMutex.unlock();
Mike Lockwood66e57f62011-02-18 13:24:01 -0500278#endif
279}
280
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400281// ----------------------------------------------------------------------------
282
283static JNINativeMethod gMethods[] = {
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400284 {"native_setup", "(Landroid/mtp/MtpDatabase;)V",
Mike Lockwood0cd01362010-12-30 11:54:33 -0500285 (void *)android_mtp_MtpServer_setup},
Mike Lockwood0cd01362010-12-30 11:54:33 -0500286 {"native_start", "()V", (void *)android_mtp_MtpServer_start},
287 {"native_stop", "()V", (void *)android_mtp_MtpServer_stop},
288 {"native_send_object_added", "(I)V", (void *)android_mtp_MtpServer_send_object_added},
289 {"native_send_object_removed", "(I)V", (void *)android_mtp_MtpServer_send_object_removed},
290 {"native_set_ptp_mode", "(Z)V", (void *)android_mtp_MtpServer_set_ptp_mode},
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400291 {"native_add_storage", "(Landroid/mtp/MtpStorage;)V",
292 (void *)android_mtp_MtpServer_add_storage},
293 {"native_remove_storage", "(I)V", (void *)android_mtp_MtpServer_remove_storage},
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400294};
295
Mike Lockwood0cd01362010-12-30 11:54:33 -0500296static const char* const kClassPathName = "android/mtp/MtpServer";
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400297
Mike Lockwood0cd01362010-12-30 11:54:33 -0500298int register_android_mtp_MtpServer(JNIEnv *env)
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400299{
300 jclass clazz;
301
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400302 clazz = env->FindClass("android/mtp/MtpStorage");
303 if (clazz == NULL) {
304 LOGE("Can't find android/mtp/MtpStorage");
305 return -1;
306 }
307 field_MtpStorage_storageId = env->GetFieldID(clazz, "mStorageId", "I");
308 if (field_MtpStorage_storageId == NULL) {
309 LOGE("Can't find MtpStorage.mStorageId");
310 return -1;
311 }
312 field_MtpStorage_path = env->GetFieldID(clazz, "mPath", "Ljava/lang/String;");
313 if (field_MtpStorage_path == NULL) {
314 LOGE("Can't find MtpStorage.mPath");
315 return -1;
316 }
317 field_MtpStorage_description = env->GetFieldID(clazz, "mDescription", "Ljava/lang/String;");
318 if (field_MtpStorage_description == NULL) {
319 LOGE("Can't find MtpStorage.mDescription");
320 return -1;
321 }
322 field_MtpStorage_reserveSpace = env->GetFieldID(clazz, "mReserveSpace", "J");
323 if (field_MtpStorage_reserveSpace == NULL) {
Mike Lockwood51690542011-05-09 20:16:05 -0700324 LOGE("Can't find MtpStorage.mReserveSpace");
325 return -1;
326 }
327 field_MtpStorage_removable = env->GetFieldID(clazz, "mRemovable", "Z");
328 if (field_MtpStorage_removable == NULL) {
329 LOGE("Can't find MtpStorage.mRemovable");
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400330 return -1;
331 }
332 clazz_MtpStorage = (jclass)env->NewGlobalRef(clazz);
333
Mike Lockwood0cd01362010-12-30 11:54:33 -0500334 clazz = env->FindClass("android/mtp/MtpServer");
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400335 if (clazz == NULL) {
Mike Lockwood0cd01362010-12-30 11:54:33 -0500336 LOGE("Can't find android/mtp/MtpServer");
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400337 return -1;
338 }
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400339
340 return AndroidRuntime::registerNativeMethods(env,
Mike Lockwood0cd01362010-12-30 11:54:33 -0500341 "android/mtp/MtpServer", gMethods, NELEM(gMethods));
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400342}