blob: c55189f3491da822b98e2b2b3589666f6797a5d2 [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;
50
51static Mutex sMutex;
52
Mike Lockwood98ef64e2010-06-29 16:42:13 -040053// ----------------------------------------------------------------------------
54
Mike Lockwood0cd01362010-12-30 11:54:33 -050055// in android_mtp_MtpDatabase.cpp
Mike Lockwoodd21eac92010-07-03 00:44:05 -040056extern MtpDatabase* getMtpDatabase(JNIEnv *env, jobject database);
Mike Lockwood98ef64e2010-06-29 16:42:13 -040057
58// ----------------------------------------------------------------------------
59
Mike Lockwoodff164a72010-07-15 15:01:17 -040060#ifdef HAVE_ANDROID_OS
61
Mike Lockwood98ef64e2010-06-29 16:42:13 -040062static bool ExceptionCheck(void* env)
63{
64 return ((JNIEnv *)env)->ExceptionCheck();
65}
66
67class MtpThread : public Thread {
68private:
Mike Lockwoodd21eac92010-07-03 00:44:05 -040069 MtpDatabase* mDatabase;
Mike Lockwoodbe125a52010-07-12 18:54:16 -040070 MtpServer* mServer;
Mike Lockwood7ae938be2011-04-05 10:21:27 -040071 MtpStorageList mStorageList;
Mike Lockwood071b2b62011-01-25 09:29:27 -080072 bool mUsePtp;
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -040073 int mFd;
Mike Lockwood98ef64e2010-06-29 16:42:13 -040074
75public:
Mike Lockwood7ae938be2011-04-05 10:21:27 -040076 MtpThread(MtpDatabase* database)
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -040077 : mDatabase(database),
Mike Lockwood23ee42f2010-08-03 15:17:55 -040078 mServer(NULL),
Mike Lockwood66e57f62011-02-18 13:24:01 -050079 mUsePtp(false),
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -040080 mFd(-1)
Mike Lockwood98ef64e2010-06-29 16:42:13 -040081 {
82 }
83
Mike Lockwood467ca0d2011-02-18 09:07:14 -050084 virtual ~MtpThread() {
Mike Lockwood467ca0d2011-02-18 09:07:14 -050085 }
86
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -040087 void setPtpMode(bool usePtp) {
Mike Lockwood071b2b62011-01-25 09:29:27 -080088 mUsePtp = usePtp;
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -040089 }
90
Mike Lockwood7ae938be2011-04-05 10:21:27 -040091 void addStorage(MtpStorage *storage) {
92 mStorageList.push(storage);
93 if (mServer)
94 mServer->addStorage(storage);
95 }
96
97 void removeStorage(MtpStorageID id) {
98 MtpStorage* storage = mServer->getStorage(id);
99 if (storage) {
100 for (int i = 0; i < mStorageList.size(); i++) {
101 if (mStorageList[i] == storage) {
102 mStorageList.removeAt(i);
103 break;
104 }
Mike Lockwood66e57f62011-02-18 13:24:01 -0500105 }
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400106 if (mServer)
107 mServer->removeStorage(storage);
108 delete storage;
Mike Lockwood66e57f62011-02-18 13:24:01 -0500109 }
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400110 }
111
112 void start() {
113 run("MtpThread");
Mike Lockwood66e57f62011-02-18 13:24:01 -0500114 }
115
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400116 virtual bool threadLoop() {
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400117 sMutex.lock();
118
Mike Lockwood071b2b62011-01-25 09:29:27 -0800119 mFd = open("/dev/mtp_usb", O_RDWR);
120 if (mFd >= 0) {
121 ioctl(mFd, MTP_SET_INTERFACE_MODE,
122 (mUsePtp ? MTP_INTERFACE_MODE_PTP : MTP_INTERFACE_MODE_MTP));
Mike Lockwood897f8942011-01-19 10:11:28 -0800123
124 mServer = new MtpServer(mFd, mDatabase, AID_MEDIA_RW, 0664, 0775);
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400125 for (int i = 0; i < mStorageList.size(); i++) {
126 mServer->addStorage(mStorageList[i]);
127 }
Mike Lockwood071b2b62011-01-25 09:29:27 -0800128 } else {
129 LOGE("could not open MTP driver, errno: %d", errno);
130 }
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400131
132 sMutex.unlock();
133 mServer->run();
134 sMutex.lock();
135
136 close(mFd);
137 mFd = -1;
138 delete mServer;
139 mServer = NULL;
140
141 sMutex.unlock();
Mike Lockwood071b2b62011-01-25 09:29:27 -0800142 // delay a bit before retrying to avoid excessive spin
143 if (!exitPending()) {
144 sleep(1);
Mike Lockwood897f8942011-01-19 10:11:28 -0800145 }
Mike Lockwood2b2bff52010-08-18 12:32:26 -0400146
Mike Lockwood071b2b62011-01-25 09:29:27 -0800147 return true;
Mike Lockwooda1c91802011-01-18 20:11:29 -0800148 }
149
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400150 void sendObjectAdded(MtpObjectHandle handle) {
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400151 if (mServer)
152 mServer->sendObjectAdded(handle);
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400153 }
154
155 void sendObjectRemoved(MtpObjectHandle handle) {
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400156 if (mServer)
157 mServer->sendObjectRemoved(handle);
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400158 }
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400159};
160
Mike Lockwood071b2b62011-01-25 09:29:27 -0800161// This smart pointer is necessary for preventing MtpThread from exiting too early
162static sp<MtpThread> sThread;
163
Mike Lockwoodff164a72010-07-15 15:01:17 -0400164#endif // HAVE_ANDROID_OS
165
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400166static void
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400167android_mtp_MtpServer_setup(JNIEnv *env, jobject thiz, jobject javaDatabase)
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400168{
Mike Lockwoodff164a72010-07-15 15:01:17 -0400169#ifdef HAVE_ANDROID_OS
Mike Lockwood071b2b62011-01-25 09:29:27 -0800170 // create the thread and assign it to the smart pointer
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400171 sThread = new MtpThread(getMtpDatabase(env, javaDatabase));
Mike Lockwoodff164a72010-07-15 15:01:17 -0400172#endif
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400173}
174
175static void
Mike Lockwood0cd01362010-12-30 11:54:33 -0500176android_mtp_MtpServer_start(JNIEnv *env, jobject thiz)
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400177{
Mike Lockwoodff164a72010-07-15 15:01:17 -0400178#ifdef HAVE_ANDROID_OS
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400179 sMutex.lock();
Mike Lockwood071b2b62011-01-25 09:29:27 -0800180 MtpThread *thread = sThread.get();
181 if (thread)
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400182 thread->start();
183 sMutex.unlock();
Mike Lockwoodff164a72010-07-15 15:01:17 -0400184#endif // HAVE_ANDROID_OS
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400185}
186
187static void
Mike Lockwood0cd01362010-12-30 11:54:33 -0500188android_mtp_MtpServer_stop(JNIEnv *env, jobject thiz)
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400189{
Mike Lockwoodff164a72010-07-15 15:01:17 -0400190#ifdef HAVE_ANDROID_OS
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400191 sMutex.lock();
Mike Lockwood071b2b62011-01-25 09:29:27 -0800192 MtpThread *thread = sThread.get();
193 if (thread) {
194 thread->requestExitAndWait();
195 sThread = NULL;
196 }
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400197 sMutex.unlock();
Mike Lockwoodff164a72010-07-15 15:01:17 -0400198#endif
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400199}
200
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400201static void
Mike Lockwood0cd01362010-12-30 11:54:33 -0500202android_mtp_MtpServer_send_object_added(JNIEnv *env, jobject thiz, jint handle)
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400203{
Mike Lockwoodff164a72010-07-15 15:01:17 -0400204#ifdef HAVE_ANDROID_OS
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400205 sMutex.lock();
Mike Lockwood071b2b62011-01-25 09:29:27 -0800206 MtpThread *thread = sThread.get();
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400207 if (thread)
208 thread->sendObjectAdded(handle);
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400209 sMutex.unlock();
Mike Lockwoodff164a72010-07-15 15:01:17 -0400210#endif
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400211}
212
213static void
Mike Lockwood0cd01362010-12-30 11:54:33 -0500214android_mtp_MtpServer_send_object_removed(JNIEnv *env, jobject thiz, jint handle)
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400215{
Mike Lockwoodff164a72010-07-15 15:01:17 -0400216#ifdef HAVE_ANDROID_OS
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400217 sMutex.lock();
Mike Lockwood071b2b62011-01-25 09:29:27 -0800218 MtpThread *thread = sThread.get();
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400219 if (thread)
220 thread->sendObjectRemoved(handle);
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400221 sMutex.unlock();
Mike Lockwoodff164a72010-07-15 15:01:17 -0400222#endif
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400223}
224
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -0400225static void
Mike Lockwood0cd01362010-12-30 11:54:33 -0500226android_mtp_MtpServer_set_ptp_mode(JNIEnv *env, jobject thiz, jboolean usePtp)
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -0400227{
228#ifdef HAVE_ANDROID_OS
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400229 sMutex.lock();
Mike Lockwood071b2b62011-01-25 09:29:27 -0800230 MtpThread *thread = sThread.get();
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -0400231 if (thread)
232 thread->setPtpMode(usePtp);
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400233 sMutex.unlock();
Mike Lockwooda1c91802011-01-18 20:11:29 -0800234#endif
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -0400235}
236
Mike Lockwood66e57f62011-02-18 13:24:01 -0500237static void
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400238android_mtp_MtpServer_add_storage(JNIEnv *env, jobject thiz, jobject jstorage)
Mike Lockwood66e57f62011-02-18 13:24:01 -0500239{
240#ifdef HAVE_ANDROID_OS
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400241 sMutex.lock();
242 MtpThread *thread = sThread.get();
243 if (thread) {
244 jint storageID = env->GetIntField(jstorage, field_MtpStorage_storageId);
245 jstring path = (jstring)env->GetObjectField(jstorage, field_MtpStorage_path);
246 jstring description = (jstring)env->GetObjectField(jstorage, field_MtpStorage_description);
247 jlong reserveSpace = env->GetLongField(jstorage, field_MtpStorage_reserveSpace);
248
249 const char *pathStr = env->GetStringUTFChars(path, NULL);
250 const char *descriptionStr = env->GetStringUTFChars(description, NULL);
251
252 MtpStorage* storage = new MtpStorage(storageID, pathStr, descriptionStr, reserveSpace);
253 thread->addStorage(storage);
254
255 env->ReleaseStringUTFChars(path, pathStr);
256 env->ReleaseStringUTFChars(description, descriptionStr);
257 } else {
258 LOGE("MtpThread is null in add_storage");
259 }
260 sMutex.unlock();
261#endif
262}
263
264static void
265android_mtp_MtpServer_remove_storage(JNIEnv *env, jobject thiz, jint storageId)
266{
267#ifdef HAVE_ANDROID_OS
268 sMutex.lock();
Mike Lockwood66e57f62011-02-18 13:24:01 -0500269 MtpThread *thread = sThread.get();
270 if (thread)
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400271 thread->removeStorage(storageId);
272 else
273 LOGE("MtpThread is null in remove_storage");
274 sMutex.unlock();
Mike Lockwood66e57f62011-02-18 13:24:01 -0500275#endif
276}
277
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400278// ----------------------------------------------------------------------------
279
280static JNINativeMethod gMethods[] = {
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400281 {"native_setup", "(Landroid/mtp/MtpDatabase;)V",
Mike Lockwood0cd01362010-12-30 11:54:33 -0500282 (void *)android_mtp_MtpServer_setup},
Mike Lockwood0cd01362010-12-30 11:54:33 -0500283 {"native_start", "()V", (void *)android_mtp_MtpServer_start},
284 {"native_stop", "()V", (void *)android_mtp_MtpServer_stop},
285 {"native_send_object_added", "(I)V", (void *)android_mtp_MtpServer_send_object_added},
286 {"native_send_object_removed", "(I)V", (void *)android_mtp_MtpServer_send_object_removed},
287 {"native_set_ptp_mode", "(Z)V", (void *)android_mtp_MtpServer_set_ptp_mode},
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400288 {"native_add_storage", "(Landroid/mtp/MtpStorage;)V",
289 (void *)android_mtp_MtpServer_add_storage},
290 {"native_remove_storage", "(I)V", (void *)android_mtp_MtpServer_remove_storage},
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400291};
292
Mike Lockwood0cd01362010-12-30 11:54:33 -0500293static const char* const kClassPathName = "android/mtp/MtpServer";
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400294
Mike Lockwood0cd01362010-12-30 11:54:33 -0500295int register_android_mtp_MtpServer(JNIEnv *env)
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400296{
297 jclass clazz;
298
Mike Lockwood7ae938be2011-04-05 10:21:27 -0400299 clazz = env->FindClass("android/mtp/MtpStorage");
300 if (clazz == NULL) {
301 LOGE("Can't find android/mtp/MtpStorage");
302 return -1;
303 }
304 field_MtpStorage_storageId = env->GetFieldID(clazz, "mStorageId", "I");
305 if (field_MtpStorage_storageId == NULL) {
306 LOGE("Can't find MtpStorage.mStorageId");
307 return -1;
308 }
309 field_MtpStorage_path = env->GetFieldID(clazz, "mPath", "Ljava/lang/String;");
310 if (field_MtpStorage_path == NULL) {
311 LOGE("Can't find MtpStorage.mPath");
312 return -1;
313 }
314 field_MtpStorage_description = env->GetFieldID(clazz, "mDescription", "Ljava/lang/String;");
315 if (field_MtpStorage_description == NULL) {
316 LOGE("Can't find MtpStorage.mDescription");
317 return -1;
318 }
319 field_MtpStorage_reserveSpace = env->GetFieldID(clazz, "mReserveSpace", "J");
320 if (field_MtpStorage_reserveSpace == NULL) {
321 LOGE("Can't find MtpStorage.mStorageId");
322 return -1;
323 }
324 clazz_MtpStorage = (jclass)env->NewGlobalRef(clazz);
325
Mike Lockwood0cd01362010-12-30 11:54:33 -0500326 clazz = env->FindClass("android/mtp/MtpServer");
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400327 if (clazz == NULL) {
Mike Lockwood0cd01362010-12-30 11:54:33 -0500328 LOGE("Can't find android/mtp/MtpServer");
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400329 return -1;
330 }
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400331
332 return AndroidRuntime::registerNativeMethods(env,
Mike Lockwood0cd01362010-12-30 11:54:33 -0500333 "android/mtp/MtpServer", gMethods, NELEM(gMethods));
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400334}