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 <utils/threads.h> 26 27 #include "jni.h" 28 #include "JNIHelp.h" 29 #include "android_runtime/AndroidRuntime.h" 30 #include "private/android_filesystem_config.h" 31 32 #include "MtpServer.h" 33 #include "MtpStorage.h" 34 35 using namespace android; 36 37 // MtpServer fields 38 static jfieldID field_MtpServer_nativeContext; 39 40 // MtpStorage fields 41 static jfieldID field_MtpStorage_storageId; 42 static jfieldID field_MtpStorage_path; 43 static jfieldID field_MtpStorage_description; 44 static jfieldID field_MtpStorage_reserveSpace; 45 static jfieldID field_MtpStorage_removable; 46 static jfieldID field_MtpStorage_maxFileSize; 47 48 static Mutex sMutex; 49 50 // ---------------------------------------------------------------------------- 51 52 // in android_mtp_MtpDatabase.cpp 53 extern MtpDatabase* getMtpDatabase(JNIEnv *env, jobject database); 54 55 static inline MtpServer* getMtpServer(JNIEnv *env, jobject thiz) { 56 return (MtpServer*)env->GetIntField(thiz, field_MtpServer_nativeContext); 57 } 58 59 static void 60 android_mtp_MtpServer_setup(JNIEnv *env, jobject thiz, jobject javaDatabase, jboolean usePtp) 61 { 62 int fd = open("/dev/mtp_usb", O_RDWR); 63 if (fd >= 0) { 64 MtpServer* server = new MtpServer(fd, getMtpDatabase(env, javaDatabase), 65 usePtp, AID_MEDIA_RW, 0664, 0775); 66 env->SetIntField(thiz, field_MtpServer_nativeContext, (int)server); 67 } else { 68 ALOGE("could not open MTP driver, errno: %d", errno); 69 } 70 } 71 72 static void 73 android_mtp_MtpServer_run(JNIEnv *env, jobject thiz) 74 { 75 MtpServer* server = getMtpServer(env, thiz); 76 if (server) 77 server->run(); 78 else 79 ALOGE("server is null in run"); 80 } 81 82 static void 83 android_mtp_MtpServer_cleanup(JNIEnv *env, jobject thiz) 84 { 85 Mutex::Autolock autoLock(sMutex); 86 87 MtpServer* server = getMtpServer(env, thiz); 88 if (server) { 89 delete server; 90 env->SetIntField(thiz, field_MtpServer_nativeContext, 0); 91 } else { 92 ALOGE("server is null in cleanup"); 93 } 94 } 95 96 static void 97 android_mtp_MtpServer_send_object_added(JNIEnv *env, jobject thiz, jint handle) 98 { 99 Mutex::Autolock autoLock(sMutex); 100 101 MtpServer* server = getMtpServer(env, thiz); 102 if (server) 103 server->sendObjectAdded(handle); 104 else 105 ALOGE("server is null in send_object_added"); 106 } 107 108 static void 109 android_mtp_MtpServer_send_object_removed(JNIEnv *env, jobject thiz, jint handle) 110 { 111 Mutex::Autolock autoLock(sMutex); 112 113 MtpServer* server = getMtpServer(env, thiz); 114 if (server) 115 server->sendObjectRemoved(handle); 116 else 117 ALOGE("server is null in send_object_removed"); 118 } 119 120 static void 121 android_mtp_MtpServer_add_storage(JNIEnv *env, jobject thiz, jobject jstorage) 122 { 123 Mutex::Autolock autoLock(sMutex); 124 125 MtpServer* server = getMtpServer(env, thiz); 126 if (server) { 127 jint storageID = env->GetIntField(jstorage, field_MtpStorage_storageId); 128 jstring path = (jstring)env->GetObjectField(jstorage, field_MtpStorage_path); 129 jstring description = (jstring)env->GetObjectField(jstorage, field_MtpStorage_description); 130 jlong reserveSpace = env->GetLongField(jstorage, field_MtpStorage_reserveSpace); 131 jboolean removable = env->GetBooleanField(jstorage, field_MtpStorage_removable); 132 jlong maxFileSize = env->GetLongField(jstorage, field_MtpStorage_maxFileSize); 133 134 const char *pathStr = env->GetStringUTFChars(path, NULL); 135 if (pathStr != NULL) { 136 const char *descriptionStr = env->GetStringUTFChars(description, NULL); 137 if (descriptionStr != NULL) { 138 MtpStorage* storage = new MtpStorage(storageID, pathStr, descriptionStr, 139 reserveSpace, removable, maxFileSize); 140 server->addStorage(storage); 141 env->ReleaseStringUTFChars(path, pathStr); 142 env->ReleaseStringUTFChars(description, descriptionStr); 143 } else { 144 env->ReleaseStringUTFChars(path, pathStr); 145 } 146 } 147 } else { 148 ALOGE("server is null in add_storage"); 149 } 150 } 151 152 static void 153 android_mtp_MtpServer_remove_storage(JNIEnv *env, jobject thiz, jint storageId) 154 { 155 Mutex::Autolock autoLock(sMutex); 156 157 MtpServer* server = getMtpServer(env, thiz); 158 if (server) { 159 MtpStorage* storage = server->getStorage(storageId); 160 if (storage) { 161 server->removeStorage(storage); 162 delete storage; 163 } 164 } else 165 ALOGE("server is null in remove_storage"); 166 } 167 168 // ---------------------------------------------------------------------------- 169 170 static JNINativeMethod gMethods[] = { 171 {"native_setup", "(Landroid/mtp/MtpDatabase;Z)V", 172 (void *)android_mtp_MtpServer_setup}, 173 {"native_run", "()V", (void *)android_mtp_MtpServer_run}, 174 {"native_cleanup", "()V", (void *)android_mtp_MtpServer_cleanup}, 175 {"native_send_object_added", "(I)V", (void *)android_mtp_MtpServer_send_object_added}, 176 {"native_send_object_removed", "(I)V", (void *)android_mtp_MtpServer_send_object_removed}, 177 {"native_add_storage", "(Landroid/mtp/MtpStorage;)V", 178 (void *)android_mtp_MtpServer_add_storage}, 179 {"native_remove_storage", "(I)V", (void *)android_mtp_MtpServer_remove_storage}, 180 }; 181 182 static const char* const kClassPathName = "android/mtp/MtpServer"; 183 184 int register_android_mtp_MtpServer(JNIEnv *env) 185 { 186 jclass clazz; 187 188 clazz = env->FindClass("android/mtp/MtpStorage"); 189 if (clazz == NULL) { 190 ALOGE("Can't find android/mtp/MtpStorage"); 191 return -1; 192 } 193 field_MtpStorage_storageId = env->GetFieldID(clazz, "mStorageId", "I"); 194 if (field_MtpStorage_storageId == NULL) { 195 ALOGE("Can't find MtpStorage.mStorageId"); 196 return -1; 197 } 198 field_MtpStorage_path = env->GetFieldID(clazz, "mPath", "Ljava/lang/String;"); 199 if (field_MtpStorage_path == NULL) { 200 ALOGE("Can't find MtpStorage.mPath"); 201 return -1; 202 } 203 field_MtpStorage_description = env->GetFieldID(clazz, "mDescription", "Ljava/lang/String;"); 204 if (field_MtpStorage_description == NULL) { 205 ALOGE("Can't find MtpStorage.mDescription"); 206 return -1; 207 } 208 field_MtpStorage_reserveSpace = env->GetFieldID(clazz, "mReserveSpace", "J"); 209 if (field_MtpStorage_reserveSpace == NULL) { 210 ALOGE("Can't find MtpStorage.mReserveSpace"); 211 return -1; 212 } 213 field_MtpStorage_removable = env->GetFieldID(clazz, "mRemovable", "Z"); 214 if (field_MtpStorage_removable == NULL) { 215 ALOGE("Can't find MtpStorage.mRemovable"); 216 return -1; 217 } 218 field_MtpStorage_maxFileSize = env->GetFieldID(clazz, "mMaxFileSize", "J"); 219 if (field_MtpStorage_maxFileSize == NULL) { 220 ALOGE("Can't find MtpStorage.mMaxFileSize"); 221 return -1; 222 } 223 224 clazz = env->FindClass("android/mtp/MtpServer"); 225 if (clazz == NULL) { 226 ALOGE("Can't find android/mtp/MtpServer"); 227 return -1; 228 } 229 field_MtpServer_nativeContext = env->GetFieldID(clazz, "mNativeContext", "I"); 230 if (field_MtpServer_nativeContext == NULL) { 231 ALOGE("Can't find MtpServer.mNativeContext"); 232 return -1; 233 } 234 235 return AndroidRuntime::registerNativeMethods(env, 236 "android/mtp/MtpServer", gMethods, NELEM(gMethods)); 237 } 238