android_mtp_MtpServer.cpp revision f26a586c86b097f975e26fe526ead564ad011bd0
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 mServer->run(); 115 sleep(1); 116 117 sMutex.lock(); 118 119 close(mFd); 120 mFd = -1; 121 delete mServer; 122 mServer = NULL; 123 } 124 125 JNIEnv* env = AndroidRuntime::getJNIEnv(); 126 env->SetIntField(mJavaServer, field_context, 0); 127 env->DeleteGlobalRef(mJavaServer); 128 sMutex.unlock(); 129 130 return false; 131 } 132 133 void stop() { 134 sMutex.lock(); 135 mDone = true; 136 sMutex.unlock(); 137 } 138 139 void sendObjectAdded(MtpObjectHandle handle) { 140 sMutex.lock(); 141 if (mServer) 142 mServer->sendObjectAdded(handle); 143 sMutex.unlock(); 144 } 145 146 void sendObjectRemoved(MtpObjectHandle handle) { 147 sMutex.lock(); 148 if (mServer) 149 mServer->sendObjectRemoved(handle); 150 sMutex.unlock(); 151 } 152}; 153 154#endif // HAVE_ANDROID_OS 155 156static void 157android_mtp_MtpServer_setup(JNIEnv *env, jobject thiz, jobject javaDatabase, 158 jstring storagePath, jlong reserveSpace) 159{ 160#ifdef HAVE_ANDROID_OS 161 MtpDatabase* database = getMtpDatabase(env, javaDatabase); 162 const char *storagePathStr = env->GetStringUTFChars(storagePath, NULL); 163 164 MtpThread* thread = new MtpThread(database, storagePathStr, 165 reserveSpace, env->NewGlobalRef(thiz)); 166 env->SetIntField(thiz, field_context, (int)thread); 167 168 env->ReleaseStringUTFChars(storagePath, storagePathStr); 169#endif 170} 171 172static void 173android_mtp_MtpServer_start(JNIEnv *env, jobject thiz) 174{ 175#ifdef HAVE_ANDROID_OS 176 MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context); 177 thread->run("MtpThread"); 178#endif // HAVE_ANDROID_OS 179} 180 181static void 182android_mtp_MtpServer_stop(JNIEnv *env, jobject thiz) 183{ 184#ifdef HAVE_ANDROID_OS 185 MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context); 186 if (thread) 187 thread->stop(); 188#endif 189} 190 191static void 192android_mtp_MtpServer_send_object_added(JNIEnv *env, jobject thiz, jint handle) 193{ 194#ifdef HAVE_ANDROID_OS 195 MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context); 196 if (thread) 197 thread->sendObjectAdded(handle); 198#endif 199} 200 201static void 202android_mtp_MtpServer_send_object_removed(JNIEnv *env, jobject thiz, jint handle) 203{ 204#ifdef HAVE_ANDROID_OS 205 MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context); 206 if (thread) 207 thread->sendObjectRemoved(handle); 208#endif 209} 210 211static void 212android_mtp_MtpServer_set_ptp_mode(JNIEnv *env, jobject thiz, jboolean usePtp) 213{ 214#ifdef HAVE_ANDROID_OS 215 MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context); 216 if (thread) 217 thread->setPtpMode(usePtp); 218#endif 219} 220 221// ---------------------------------------------------------------------------- 222 223static JNINativeMethod gMethods[] = { 224 {"native_setup", "(Landroid/mtp/MtpDatabase;Ljava/lang/String;J)V", 225 (void *)android_mtp_MtpServer_setup}, 226 {"native_start", "()V", (void *)android_mtp_MtpServer_start}, 227 {"native_stop", "()V", (void *)android_mtp_MtpServer_stop}, 228 {"native_send_object_added", "(I)V", (void *)android_mtp_MtpServer_send_object_added}, 229 {"native_send_object_removed", "(I)V", (void *)android_mtp_MtpServer_send_object_removed}, 230 {"native_set_ptp_mode", "(Z)V", (void *)android_mtp_MtpServer_set_ptp_mode}, 231}; 232 233static const char* const kClassPathName = "android/mtp/MtpServer"; 234 235int register_android_mtp_MtpServer(JNIEnv *env) 236{ 237 jclass clazz; 238 239 clazz = env->FindClass("android/mtp/MtpServer"); 240 if (clazz == NULL) { 241 LOGE("Can't find android/mtp/MtpServer"); 242 return -1; 243 } 244 field_context = env->GetFieldID(clazz, "mNativeContext", "I"); 245 if (field_context == NULL) { 246 LOGE("Can't find MtpServer.mNativeContext"); 247 return -1; 248 } 249 250 return AndroidRuntime::registerNativeMethods(env, 251 "android/mtp/MtpServer", gMethods, NELEM(gMethods)); 252} 253