android_mtp_MtpServer.cpp revision 897f894e88a3a1c9010309f04c6bf466125ff818
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 "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> 25#include <sys/ioctl.h> 26#include <utils/threads.h> 27 28#ifdef HAVE_ANDROID_OS 29#include <linux/usb/f_mtp.h> 30#endif 31 32#include "jni.h" 33#include "JNIHelp.h" 34#include "android_runtime/AndroidRuntime.h" 35#include "private/android_filesystem_config.h" 36 37#include "MtpServer.h" 38 39using namespace android; 40 41// ---------------------------------------------------------------------------- 42 43static jfieldID field_context; 44static Mutex sMutex; 45 46// in android_mtp_MtpDatabase.cpp 47extern MtpDatabase* getMtpDatabase(JNIEnv *env, jobject database); 48 49// ---------------------------------------------------------------------------- 50 51#ifdef HAVE_ANDROID_OS 52 53static bool ExceptionCheck(void* env) 54{ 55 return ((JNIEnv *)env)->ExceptionCheck(); 56} 57 58class MtpThread : public Thread { 59private: 60 MtpDatabase* mDatabase; 61 MtpServer* mServer; 62 String8 mStoragePath; 63 uint64_t mReserveSpace; 64 jobject mJavaServer; 65 bool mDone; 66 int mFd; 67 68public: 69 MtpThread(MtpDatabase* database, const char* storagePath, uint64_t reserveSpace, 70 jobject javaServer) 71 : mDatabase(database), 72 mServer(NULL), 73 mStoragePath(storagePath), 74 mReserveSpace(reserveSpace), 75 mJavaServer(javaServer), 76 mDone(false), 77 mFd(-1) 78 { 79 } 80 81 void setPtpMode(bool usePtp) { 82 sMutex.lock(); 83 if (mFd >= 0) { 84 ioctl(mFd, MTP_SET_INTERFACE_MODE, 85 (usePtp ? MTP_INTERFACE_MODE_PTP : MTP_INTERFACE_MODE_MTP)); 86 } else { 87 int fd = open("/dev/mtp_usb", O_RDWR); 88 if (fd >= 0) { 89 ioctl(fd, MTP_SET_INTERFACE_MODE, 90 (usePtp ? MTP_INTERFACE_MODE_PTP : MTP_INTERFACE_MODE_MTP)); 91 close(fd); 92 } 93 } 94 sMutex.unlock(); 95 } 96 97 virtual bool threadLoop() { 98 sMutex.lock(); 99 100 while (!mDone) { 101 mFd = open("/dev/mtp_usb", O_RDWR); 102 printf("open returned %d\n", mFd); 103 if (mFd < 0) { 104 LOGE("could not open MTP driver\n"); 105 sMutex.unlock(); 106 return false; 107 } 108 109 mServer = new MtpServer(mFd, mDatabase, AID_MEDIA_RW, 0664, 0775); 110 mServer->addStorage(mStoragePath, mReserveSpace); 111 112 sMutex.unlock(); 113 114 LOGD("MtpThread mServer->run"); 115 mServer->run(); 116 sleep(1); 117 118 sMutex.lock(); 119 120 close(mFd); 121 mFd = -1; 122 delete mServer; 123 mServer = NULL; 124 } 125 126 JNIEnv* env = AndroidRuntime::getJNIEnv(); 127 env->SetIntField(mJavaServer, field_context, 0); 128 env->DeleteGlobalRef(mJavaServer); 129 sMutex.unlock(); 130 131 LOGD("threadLoop returning"); 132 return false; 133 } 134 135 void stop() { 136 sMutex.lock(); 137 mDone = true; 138 sMutex.unlock(); 139 } 140 141 void sendObjectAdded(MtpObjectHandle handle) { 142 sMutex.lock(); 143 if (mServer) 144 mServer->sendObjectAdded(handle); 145 sMutex.unlock(); 146 } 147 148 void sendObjectRemoved(MtpObjectHandle handle) { 149 sMutex.lock(); 150 if (mServer) 151 mServer->sendObjectRemoved(handle); 152 sMutex.unlock(); 153 } 154}; 155 156#endif // HAVE_ANDROID_OS 157 158static void 159android_mtp_MtpServer_setup(JNIEnv *env, jobject thiz, jobject javaDatabase, 160 jstring storagePath, jlong reserveSpace) 161{ 162#ifdef HAVE_ANDROID_OS 163 LOGD("setup\n"); 164 165 MtpDatabase* database = getMtpDatabase(env, javaDatabase); 166 const char *storagePathStr = env->GetStringUTFChars(storagePath, NULL); 167 168 MtpThread* thread = new MtpThread(database, storagePathStr, 169 reserveSpace, env->NewGlobalRef(thiz)); 170 env->SetIntField(thiz, field_context, (int)thread); 171 172 env->ReleaseStringUTFChars(storagePath, storagePathStr); 173#endif 174} 175 176static void 177android_mtp_MtpServer_finalize(JNIEnv *env, jobject thiz) 178{ 179 LOGD("finalize\n"); 180} 181 182 183static void 184android_mtp_MtpServer_start(JNIEnv *env, jobject thiz) 185{ 186#ifdef HAVE_ANDROID_OS 187 LOGD("start\n"); 188 MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context); 189 thread->run("MtpThread"); 190#endif // HAVE_ANDROID_OS 191} 192 193static void 194android_mtp_MtpServer_stop(JNIEnv *env, jobject thiz) 195{ 196#ifdef HAVE_ANDROID_OS 197 LOGD("stop\n"); 198 MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context); 199 if (thread) 200 thread->stop(); 201#endif 202} 203 204static void 205android_mtp_MtpServer_send_object_added(JNIEnv *env, jobject thiz, jint handle) 206{ 207#ifdef HAVE_ANDROID_OS 208 MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context); 209 if (thread) 210 thread->sendObjectAdded(handle); 211#endif 212} 213 214static void 215android_mtp_MtpServer_send_object_removed(JNIEnv *env, jobject thiz, jint handle) 216{ 217#ifdef HAVE_ANDROID_OS 218 MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context); 219 if (thread) 220 thread->sendObjectRemoved(handle); 221#endif 222} 223 224static void 225android_mtp_MtpServer_set_ptp_mode(JNIEnv *env, jobject thiz, jboolean usePtp) 226{ 227#ifdef HAVE_ANDROID_OS 228 LOGD("set_ptp_mode\n"); 229 MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context); 230 if (thread) 231 thread->setPtpMode(usePtp); 232#endif 233} 234 235// ---------------------------------------------------------------------------- 236 237static JNINativeMethod gMethods[] = { 238 {"native_setup", "(Landroid/mtp/MtpDatabase;Ljava/lang/String;J)V", 239 (void *)android_mtp_MtpServer_setup}, 240 {"native_finalize", "()V", (void *)android_mtp_MtpServer_finalize}, 241 {"native_start", "()V", (void *)android_mtp_MtpServer_start}, 242 {"native_stop", "()V", (void *)android_mtp_MtpServer_stop}, 243 {"native_send_object_added", "(I)V", (void *)android_mtp_MtpServer_send_object_added}, 244 {"native_send_object_removed", "(I)V", (void *)android_mtp_MtpServer_send_object_removed}, 245 {"native_set_ptp_mode", "(Z)V", (void *)android_mtp_MtpServer_set_ptp_mode}, 246}; 247 248static const char* const kClassPathName = "android/mtp/MtpServer"; 249 250int register_android_mtp_MtpServer(JNIEnv *env) 251{ 252 jclass clazz; 253 254 LOGD("register_android_mtp_MtpServer\n"); 255 256 clazz = env->FindClass("android/mtp/MtpServer"); 257 if (clazz == NULL) { 258 LOGE("Can't find android/mtp/MtpServer"); 259 return -1; 260 } 261 field_context = env->GetFieldID(clazz, "mNativeContext", "I"); 262 if (field_context == NULL) { 263 LOGE("Can't find MtpServer.mNativeContext"); 264 return -1; 265 } 266 267 return AndroidRuntime::registerNativeMethods(env, 268 "android/mtp/MtpServer", gMethods, NELEM(gMethods)); 269} 270