blob: 4567965c19fb3cf6e31280b2b03f1e37439d3ba2 [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"
38
Mike Lockwood81ea83d2010-06-30 17:49:41 -040039using namespace android;
Mike Lockwood98ef64e2010-06-29 16:42:13 -040040
41// ----------------------------------------------------------------------------
42
43static jfieldID field_context;
Mike Lockwood23ee42f2010-08-03 15:17:55 -040044static Mutex sMutex;
Mike Lockwood98ef64e2010-06-29 16:42:13 -040045
Mike Lockwoodd21eac92010-07-03 00:44:05 -040046// in android_media_MtpDatabase.cpp
47extern MtpDatabase* getMtpDatabase(JNIEnv *env, jobject database);
Mike Lockwood98ef64e2010-06-29 16:42:13 -040048
49// ----------------------------------------------------------------------------
50
Mike Lockwoodff164a72010-07-15 15:01:17 -040051#ifdef HAVE_ANDROID_OS
52
Mike Lockwood98ef64e2010-06-29 16:42:13 -040053static bool ExceptionCheck(void* env)
54{
55 return ((JNIEnv *)env)->ExceptionCheck();
56}
57
58class MtpThread : public Thread {
59private:
Mike Lockwoodd21eac92010-07-03 00:44:05 -040060 MtpDatabase* mDatabase;
Mike Lockwoodbe125a52010-07-12 18:54:16 -040061 MtpServer* mServer;
Mike Lockwood23ee42f2010-08-03 15:17:55 -040062 String8 mStoragePath;
Mike Lockwood23ee42f2010-08-03 15:17:55 -040063 jobject mJavaServer;
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -040064 int mFd;
Mike Lockwood98ef64e2010-06-29 16:42:13 -040065
66public:
Mike Lockwood23ee42f2010-08-03 15:17:55 -040067 MtpThread(MtpDatabase* database, const char* storagePath, jobject javaServer)
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -040068 : mDatabase(database),
Mike Lockwood23ee42f2010-08-03 15:17:55 -040069 mServer(NULL),
70 mStoragePath(storagePath),
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -040071 mJavaServer(javaServer),
72 mFd(-1)
Mike Lockwood98ef64e2010-06-29 16:42:13 -040073 {
74 }
75
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -040076 void setPtpMode(bool usePtp) {
77 sMutex.lock();
78 if (mFd >= 0) {
79 ioctl(mFd, MTP_SET_INTERFACE_MODE,
80 (usePtp ? MTP_INTERFACE_MODE_PTP : MTP_INTERFACE_MODE_MTP));
81 } else {
82 int fd = open("/dev/mtp_usb", O_RDWR);
83 if (fd >= 0) {
84 ioctl(fd, MTP_SET_INTERFACE_MODE,
85 (usePtp ? MTP_INTERFACE_MODE_PTP : MTP_INTERFACE_MODE_MTP));
86 close(fd);
87 }
88 }
89 sMutex.unlock();
90 }
91
Mike Lockwood98ef64e2010-06-29 16:42:13 -040092 virtual bool threadLoop() {
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -040093 sMutex.lock();
94 mFd = open("/dev/mtp_usb", O_RDWR);
95 printf("open returned %d\n", mFd);
96 if (mFd < 0) {
Mike Lockwood2b2bff52010-08-18 12:32:26 -040097 LOGE("could not open MTP driver\n");
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -040098 sMutex.unlock();
Mike Lockwood2b2bff52010-08-18 12:32:26 -040099 return false;
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400100 }
101
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -0400102 mServer = new MtpServer(mFd, mDatabase, AID_SDCARD_RW, 0664, 0775);
Mike Lockwood2b2bff52010-08-18 12:32:26 -0400103 mServer->addStorage(mStoragePath);
104 sMutex.unlock();
105
106 LOGD("MtpThread mServer->run");
107 mServer->run();
Mike Lockwood2b2bff52010-08-18 12:32:26 -0400108
109 sMutex.lock();
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -0400110 close(mFd);
111 mFd = -1;
Mike Lockwood2b2bff52010-08-18 12:32:26 -0400112 delete mServer;
113 mServer = NULL;
114
Mike Lockwood23ee42f2010-08-03 15:17:55 -0400115 JNIEnv* env = AndroidRuntime::getJNIEnv();
116 env->SetIntField(mJavaServer, field_context, 0);
117 env->DeleteGlobalRef(mJavaServer);
118 sMutex.unlock();
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400119
Mike Lockwood23ee42f2010-08-03 15:17:55 -0400120 LOGD("threadLoop returning");
121 return false;
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400122 }
123
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400124 void sendObjectAdded(MtpObjectHandle handle) {
Mike Lockwood23ee42f2010-08-03 15:17:55 -0400125 sMutex.lock();
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400126 if (mServer)
127 mServer->sendObjectAdded(handle);
128 else
129 LOGE("sendObjectAdded called while disconnected\n");
Mike Lockwood23ee42f2010-08-03 15:17:55 -0400130 sMutex.unlock();
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400131 }
132
133 void sendObjectRemoved(MtpObjectHandle handle) {
Mike Lockwood23ee42f2010-08-03 15:17:55 -0400134 sMutex.lock();
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400135 if (mServer)
136 mServer->sendObjectRemoved(handle);
137 else
138 LOGE("sendObjectRemoved called while disconnected\n");
Mike Lockwood23ee42f2010-08-03 15:17:55 -0400139 sMutex.unlock();
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400140 }
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400141};
142
Mike Lockwoodff164a72010-07-15 15:01:17 -0400143#endif // HAVE_ANDROID_OS
144
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400145static void
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400146android_media_MtpServer_setup(JNIEnv *env, jobject thiz, jobject javaDatabase, jstring storagePath)
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400147{
Mike Lockwoodff164a72010-07-15 15:01:17 -0400148#ifdef HAVE_ANDROID_OS
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400149 LOGD("setup\n");
150
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400151 MtpDatabase* database = getMtpDatabase(env, javaDatabase);
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400152 const char *storagePathStr = env->GetStringUTFChars(storagePath, NULL);
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400153
Mike Lockwood23ee42f2010-08-03 15:17:55 -0400154 MtpThread* thread = new MtpThread(database, storagePathStr, env->NewGlobalRef(thiz));
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400155 env->SetIntField(thiz, field_context, (int)thread);
156
157 env->ReleaseStringUTFChars(storagePath, storagePathStr);
Mike Lockwoodff164a72010-07-15 15:01:17 -0400158#endif
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400159}
160
161static void
162android_media_MtpServer_finalize(JNIEnv *env, jobject thiz)
163{
164 LOGD("finalize\n");
165}
166
167
168static void
169android_media_MtpServer_start(JNIEnv *env, jobject thiz)
170{
Mike Lockwoodff164a72010-07-15 15:01:17 -0400171#ifdef HAVE_ANDROID_OS
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400172 LOGD("start\n");
173 MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context);
174 thread->run("MtpThread");
Mike Lockwoodff164a72010-07-15 15:01:17 -0400175#endif // HAVE_ANDROID_OS
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400176}
177
178static void
179android_media_MtpServer_stop(JNIEnv *env, jobject thiz)
180{
Mike Lockwoodff164a72010-07-15 15:01:17 -0400181#ifdef HAVE_ANDROID_OS
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400182 LOGD("stop\n");
Mike Lockwoodff164a72010-07-15 15:01:17 -0400183#endif
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400184}
185
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400186static void
187android_media_MtpServer_send_object_added(JNIEnv *env, jobject thiz, jint handle)
188{
Mike Lockwoodff164a72010-07-15 15:01:17 -0400189#ifdef HAVE_ANDROID_OS
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400190 LOGD("send_object_added %d\n", handle);
191 MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context);
192 if (thread)
193 thread->sendObjectAdded(handle);
194 else
195 LOGE("sendObjectAdded called while disconnected\n");
Mike Lockwoodff164a72010-07-15 15:01:17 -0400196#endif
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400197}
198
199static void
200android_media_MtpServer_send_object_removed(JNIEnv *env, jobject thiz, jint handle)
201{
Mike Lockwoodff164a72010-07-15 15:01:17 -0400202#ifdef HAVE_ANDROID_OS
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400203 LOGD("send_object_removed %d\n", handle);
204 MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context);
205 if (thread)
206 thread->sendObjectRemoved(handle);
207 else
208 LOGE("sendObjectRemoved called while disconnected\n");
Mike Lockwoodff164a72010-07-15 15:01:17 -0400209#endif
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400210}
211
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -0400212static void
213android_media_MtpServer_set_ptp_mode(JNIEnv *env, jobject thiz, jboolean usePtp)
214{
215#ifdef HAVE_ANDROID_OS
216 LOGD("set_ptp_mode\n");
217 MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context);
218 if (thread)
219 thread->setPtpMode(usePtp);
220 #endif
221}
222
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400223// ----------------------------------------------------------------------------
224
225static JNINativeMethod gMethods[] = {
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400226 {"native_setup", "(Landroid/media/MtpDatabase;Ljava/lang/String;)V",
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400227 (void *)android_media_MtpServer_setup},
Mike Lockwoodbe125a52010-07-12 18:54:16 -0400228 {"native_finalize", "()V", (void *)android_media_MtpServer_finalize},
229 {"native_start", "()V", (void *)android_media_MtpServer_start},
230 {"native_stop", "()V", (void *)android_media_MtpServer_stop},
231 {"native_send_object_added", "(I)V", (void *)android_media_MtpServer_send_object_added},
232 {"native_send_object_removed", "(I)V", (void *)android_media_MtpServer_send_object_removed},
Mike Lockwoodeabe8bf2010-08-31 14:35:23 -0400233 {"native_set_ptp_mode", "(Z)V", (void *)android_media_MtpServer_set_ptp_mode},
Mike Lockwood98ef64e2010-06-29 16:42:13 -0400234};
235
236static const char* const kClassPathName = "android/media/MtpServer";
237
238int register_android_media_MtpServer(JNIEnv *env)
239{
240 jclass clazz;
241
242 LOGD("register_android_media_MtpServer\n");
243
244 clazz = env->FindClass("android/media/MtpServer");
245 if (clazz == NULL) {
246 LOGE("Can't find android/media/MtpServer");
247 return -1;
248 }
249 field_context = env->GetFieldID(clazz, "mNativeContext", "I");
250 if (field_context == NULL) {
251 LOGE("Can't find MtpServer.mNativeContext");
252 return -1;
253 }
254
255 return AndroidRuntime::registerNativeMethods(env,
256 "android/media/MtpServer", gMethods, NELEM(gMethods));
257}