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 <nativehelper/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_removable; 45 static jfieldID field_MtpStorage_maxFileSize; 46 47 static Mutex sMutex; 48 49 // ---------------------------------------------------------------------------- 50 51 // in android_mtp_MtpDatabase.cpp 52 extern IMtpDatabase* getMtpDatabase(JNIEnv *env, jobject database); 53 54 static inline MtpServer* getMtpServer(JNIEnv *env, jobject thiz) { 55 return (MtpServer*)env->GetLongField(thiz, field_MtpServer_nativeContext); 56 } 57 58 static void 59 android_mtp_MtpServer_setup(JNIEnv *env, jobject thiz, jobject javaDatabase, jobject jControlFd, 60 jboolean usePtp, jstring deviceInfoManufacturer, jstring deviceInfoModel, 61 jstring deviceInfoDeviceVersion, jstring deviceInfoSerialNumber) 62 { 63 const char *deviceInfoManufacturerStr = env->GetStringUTFChars(deviceInfoManufacturer, NULL); 64 const char *deviceInfoModelStr = env->GetStringUTFChars(deviceInfoModel, NULL); 65 const char *deviceInfoDeviceVersionStr = env->GetStringUTFChars(deviceInfoDeviceVersion, NULL); 66 const char *deviceInfoSerialNumberStr = env->GetStringUTFChars(deviceInfoSerialNumber, NULL); 67 int controlFd = dup(jniGetFDFromFileDescriptor(env, jControlFd)); 68 MtpServer* server = new MtpServer(getMtpDatabase(env, javaDatabase), controlFd, 69 usePtp, 70 (deviceInfoManufacturerStr != NULL) ? deviceInfoManufacturerStr : "", 71 (deviceInfoModelStr != NULL) ? deviceInfoModelStr : "", 72 (deviceInfoDeviceVersionStr != NULL) ? deviceInfoDeviceVersionStr : "", 73 (deviceInfoSerialNumberStr != NULL) ? deviceInfoSerialNumberStr : ""); 74 if (deviceInfoManufacturerStr != NULL) { 75 env->ReleaseStringUTFChars(deviceInfoManufacturer, deviceInfoManufacturerStr); 76 } 77 if (deviceInfoModelStr != NULL) { 78 env->ReleaseStringUTFChars(deviceInfoModel, deviceInfoModelStr); 79 } 80 if (deviceInfoDeviceVersionStr != NULL) { 81 env->ReleaseStringUTFChars(deviceInfoDeviceVersion, deviceInfoDeviceVersionStr); 82 } 83 if (deviceInfoSerialNumberStr != NULL) { 84 env->ReleaseStringUTFChars(deviceInfoSerialNumber, deviceInfoSerialNumberStr); 85 } 86 env->SetLongField(thiz, field_MtpServer_nativeContext, (jlong)server); 87 } 88 89 static void 90 android_mtp_MtpServer_run(JNIEnv *env, jobject thiz) 91 { 92 MtpServer* server = getMtpServer(env, thiz); 93 if (server) 94 server->run(); 95 else 96 ALOGE("server is null in run"); 97 } 98 99 static void 100 android_mtp_MtpServer_cleanup(JNIEnv *env, jobject thiz) 101 { 102 Mutex::Autolock autoLock(sMutex); 103 104 MtpServer* server = getMtpServer(env, thiz); 105 if (server) { 106 delete server; 107 env->SetLongField(thiz, field_MtpServer_nativeContext, 0); 108 } else { 109 ALOGE("server is null in cleanup"); 110 } 111 } 112 113 static void 114 android_mtp_MtpServer_send_object_added(JNIEnv *env, jobject thiz, jint handle) 115 { 116 Mutex::Autolock autoLock(sMutex); 117 118 MtpServer* server = getMtpServer(env, thiz); 119 if (server) 120 server->sendObjectAdded(handle); 121 else 122 ALOGE("server is null in send_object_added"); 123 } 124 125 static void 126 android_mtp_MtpServer_send_object_removed(JNIEnv *env, jobject thiz, jint handle) 127 { 128 Mutex::Autolock autoLock(sMutex); 129 130 MtpServer* server = getMtpServer(env, thiz); 131 if (server) 132 server->sendObjectRemoved(handle); 133 else 134 ALOGE("server is null in send_object_removed"); 135 } 136 137 static void 138 android_mtp_MtpServer_send_object_info_changed(JNIEnv *env, jobject thiz, jint handle) 139 { 140 Mutex::Autolock autoLock(sMutex); 141 142 MtpServer* server = getMtpServer(env, thiz); 143 if (server) 144 server->sendObjectInfoChanged(handle); 145 else 146 ALOGE("server is null in send_object_info_changed"); 147 } 148 149 static void 150 android_mtp_MtpServer_send_device_property_changed(JNIEnv *env, jobject thiz, jint property) 151 { 152 Mutex::Autolock autoLock(sMutex); 153 154 MtpServer* server = getMtpServer(env, thiz); 155 if (server) 156 server->sendDevicePropertyChanged(property); 157 else 158 ALOGE("server is null in send_object_removed"); 159 } 160 161 static void 162 android_mtp_MtpServer_add_storage(JNIEnv *env, jobject thiz, jobject jstorage) 163 { 164 Mutex::Autolock autoLock(sMutex); 165 166 MtpServer* server = getMtpServer(env, thiz); 167 if (server) { 168 jint storageID = env->GetIntField(jstorage, field_MtpStorage_storageId); 169 jstring path = (jstring)env->GetObjectField(jstorage, field_MtpStorage_path); 170 jstring description = (jstring)env->GetObjectField(jstorage, field_MtpStorage_description); 171 jboolean removable = env->GetBooleanField(jstorage, field_MtpStorage_removable); 172 jlong maxFileSize = env->GetLongField(jstorage, field_MtpStorage_maxFileSize); 173 174 const char *pathStr = env->GetStringUTFChars(path, NULL); 175 if (pathStr != NULL) { 176 const char *descriptionStr = env->GetStringUTFChars(description, NULL); 177 if (descriptionStr != NULL) { 178 MtpStorage* storage = new MtpStorage(storageID, pathStr, descriptionStr, 179 removable, maxFileSize); 180 server->addStorage(storage); 181 env->ReleaseStringUTFChars(path, pathStr); 182 env->ReleaseStringUTFChars(description, descriptionStr); 183 } else { 184 env->ReleaseStringUTFChars(path, pathStr); 185 } 186 } 187 } else { 188 ALOGE("server is null in add_storage"); 189 } 190 } 191 192 static void 193 android_mtp_MtpServer_remove_storage(JNIEnv *env, jobject thiz, jint storageId) 194 { 195 Mutex::Autolock autoLock(sMutex); 196 197 MtpServer* server = getMtpServer(env, thiz); 198 if (server) { 199 MtpStorage* storage = server->getStorage(storageId); 200 if (storage) { 201 server->removeStorage(storage); 202 delete storage; 203 } 204 } else 205 ALOGE("server is null in remove_storage"); 206 } 207 208 // ---------------------------------------------------------------------------- 209 210 static const JNINativeMethod gMethods[] = { 211 {"native_setup", "(Landroid/mtp/MtpDatabase;Ljava/io/FileDescriptor;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V", 212 (void *)android_mtp_MtpServer_setup}, 213 {"native_run", "()V", (void *)android_mtp_MtpServer_run}, 214 {"native_cleanup", "()V", (void *)android_mtp_MtpServer_cleanup}, 215 {"native_send_object_added", "(I)V", (void *)android_mtp_MtpServer_send_object_added}, 216 {"native_send_object_removed", "(I)V", (void *)android_mtp_MtpServer_send_object_removed}, 217 {"native_send_object_info_changed", "(I)V", (void *)android_mtp_MtpServer_send_object_info_changed}, 218 {"native_send_device_property_changed", "(I)V", 219 (void *)android_mtp_MtpServer_send_device_property_changed}, 220 {"native_add_storage", "(Landroid/mtp/MtpStorage;)V", 221 (void *)android_mtp_MtpServer_add_storage}, 222 {"native_remove_storage", "(I)V", (void *)android_mtp_MtpServer_remove_storage}, 223 }; 224 225 int register_android_mtp_MtpServer(JNIEnv *env) 226 { 227 jclass clazz; 228 229 clazz = env->FindClass("android/mtp/MtpStorage"); 230 if (clazz == NULL) { 231 ALOGE("Can't find android/mtp/MtpStorage"); 232 return -1; 233 } 234 field_MtpStorage_storageId = env->GetFieldID(clazz, "mStorageId", "I"); 235 if (field_MtpStorage_storageId == NULL) { 236 ALOGE("Can't find MtpStorage.mStorageId"); 237 return -1; 238 } 239 field_MtpStorage_path = env->GetFieldID(clazz, "mPath", "Ljava/lang/String;"); 240 if (field_MtpStorage_path == NULL) { 241 ALOGE("Can't find MtpStorage.mPath"); 242 return -1; 243 } 244 field_MtpStorage_description = env->GetFieldID(clazz, "mDescription", "Ljava/lang/String;"); 245 if (field_MtpStorage_description == NULL) { 246 ALOGE("Can't find MtpStorage.mDescription"); 247 return -1; 248 } 249 field_MtpStorage_removable = env->GetFieldID(clazz, "mRemovable", "Z"); 250 if (field_MtpStorage_removable == NULL) { 251 ALOGE("Can't find MtpStorage.mRemovable"); 252 return -1; 253 } 254 field_MtpStorage_maxFileSize = env->GetFieldID(clazz, "mMaxFileSize", "J"); 255 if (field_MtpStorage_maxFileSize == NULL) { 256 ALOGE("Can't find MtpStorage.mMaxFileSize"); 257 return -1; 258 } 259 260 clazz = env->FindClass("android/mtp/MtpServer"); 261 if (clazz == NULL) { 262 ALOGE("Can't find android/mtp/MtpServer"); 263 return -1; 264 } 265 field_MtpServer_nativeContext = env->GetFieldID(clazz, "mNativeContext", "J"); 266 if (field_MtpServer_nativeContext == NULL) { 267 ALOGE("Can't find MtpServer.mNativeContext"); 268 return -1; 269 } 270 271 return AndroidRuntime::registerNativeMethods(env, 272 "android/mtp/MtpServer", gMethods, NELEM(gMethods)); 273 } 274