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->GetLongField(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->SetLongField(thiz, field_MtpServer_nativeContext, (jlong)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->SetLongField(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_send_device_property_changed(JNIEnv *env, jobject thiz, jint property) 122 { 123 Mutex::Autolock autoLock(sMutex); 124 125 MtpServer* server = getMtpServer(env, thiz); 126 if (server) 127 server->sendDevicePropertyChanged(property); 128 else 129 ALOGE("server is null in send_object_removed"); 130 } 131 132 static void 133 android_mtp_MtpServer_add_storage(JNIEnv *env, jobject thiz, jobject jstorage) 134 { 135 Mutex::Autolock autoLock(sMutex); 136 137 MtpServer* server = getMtpServer(env, thiz); 138 if (server) { 139 jint storageID = env->GetIntField(jstorage, field_MtpStorage_storageId); 140 jstring path = (jstring)env->GetObjectField(jstorage, field_MtpStorage_path); 141 jstring description = (jstring)env->GetObjectField(jstorage, field_MtpStorage_description); 142 jlong reserveSpace = env->GetLongField(jstorage, field_MtpStorage_reserveSpace); 143 jboolean removable = env->GetBooleanField(jstorage, field_MtpStorage_removable); 144 jlong maxFileSize = env->GetLongField(jstorage, field_MtpStorage_maxFileSize); 145 146 const char *pathStr = env->GetStringUTFChars(path, NULL); 147 if (pathStr != NULL) { 148 const char *descriptionStr = env->GetStringUTFChars(description, NULL); 149 if (descriptionStr != NULL) { 150 MtpStorage* storage = new MtpStorage(storageID, pathStr, descriptionStr, 151 reserveSpace, removable, maxFileSize); 152 server->addStorage(storage); 153 env->ReleaseStringUTFChars(path, pathStr); 154 env->ReleaseStringUTFChars(description, descriptionStr); 155 } else { 156 env->ReleaseStringUTFChars(path, pathStr); 157 } 158 } 159 } else { 160 ALOGE("server is null in add_storage"); 161 } 162 } 163 164 static void 165 android_mtp_MtpServer_remove_storage(JNIEnv *env, jobject thiz, jint storageId) 166 { 167 Mutex::Autolock autoLock(sMutex); 168 169 MtpServer* server = getMtpServer(env, thiz); 170 if (server) { 171 MtpStorage* storage = server->getStorage(storageId); 172 if (storage) { 173 server->removeStorage(storage); 174 delete storage; 175 } 176 } else 177 ALOGE("server is null in remove_storage"); 178 } 179 180 // ---------------------------------------------------------------------------- 181 182 static JNINativeMethod gMethods[] = { 183 {"native_setup", "(Landroid/mtp/MtpDatabase;Z)V", 184 (void *)android_mtp_MtpServer_setup}, 185 {"native_run", "()V", (void *)android_mtp_MtpServer_run}, 186 {"native_cleanup", "()V", (void *)android_mtp_MtpServer_cleanup}, 187 {"native_send_object_added", "(I)V", (void *)android_mtp_MtpServer_send_object_added}, 188 {"native_send_object_removed", "(I)V", (void *)android_mtp_MtpServer_send_object_removed}, 189 {"native_send_device_property_changed", "(I)V", 190 (void *)android_mtp_MtpServer_send_device_property_changed}, 191 {"native_add_storage", "(Landroid/mtp/MtpStorage;)V", 192 (void *)android_mtp_MtpServer_add_storage}, 193 {"native_remove_storage", "(I)V", (void *)android_mtp_MtpServer_remove_storage}, 194 }; 195 196 static const char* const kClassPathName = "android/mtp/MtpServer"; 197 198 int register_android_mtp_MtpServer(JNIEnv *env) 199 { 200 jclass clazz; 201 202 clazz = env->FindClass("android/mtp/MtpStorage"); 203 if (clazz == NULL) { 204 ALOGE("Can't find android/mtp/MtpStorage"); 205 return -1; 206 } 207 field_MtpStorage_storageId = env->GetFieldID(clazz, "mStorageId", "I"); 208 if (field_MtpStorage_storageId == NULL) { 209 ALOGE("Can't find MtpStorage.mStorageId"); 210 return -1; 211 } 212 field_MtpStorage_path = env->GetFieldID(clazz, "mPath", "Ljava/lang/String;"); 213 if (field_MtpStorage_path == NULL) { 214 ALOGE("Can't find MtpStorage.mPath"); 215 return -1; 216 } 217 field_MtpStorage_description = env->GetFieldID(clazz, "mDescription", "Ljava/lang/String;"); 218 if (field_MtpStorage_description == NULL) { 219 ALOGE("Can't find MtpStorage.mDescription"); 220 return -1; 221 } 222 field_MtpStorage_reserveSpace = env->GetFieldID(clazz, "mReserveSpace", "J"); 223 if (field_MtpStorage_reserveSpace == NULL) { 224 ALOGE("Can't find MtpStorage.mReserveSpace"); 225 return -1; 226 } 227 field_MtpStorage_removable = env->GetFieldID(clazz, "mRemovable", "Z"); 228 if (field_MtpStorage_removable == NULL) { 229 ALOGE("Can't find MtpStorage.mRemovable"); 230 return -1; 231 } 232 field_MtpStorage_maxFileSize = env->GetFieldID(clazz, "mMaxFileSize", "J"); 233 if (field_MtpStorage_maxFileSize == NULL) { 234 ALOGE("Can't find MtpStorage.mMaxFileSize"); 235 return -1; 236 } 237 238 clazz = env->FindClass("android/mtp/MtpServer"); 239 if (clazz == NULL) { 240 ALOGE("Can't find android/mtp/MtpServer"); 241 return -1; 242 } 243 field_MtpServer_nativeContext = env->GetFieldID(clazz, "mNativeContext", "J"); 244 if (field_MtpServer_nativeContext == NULL) { 245 ALOGE("Can't find MtpServer.mNativeContext"); 246 return -1; 247 } 248 249 return AndroidRuntime::registerNativeMethods(env, 250 "android/mtp/MtpServer", gMethods, NELEM(gMethods)); 251 } 252