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 35using namespace android; 36 37// MtpServer fields 38static jfieldID field_MtpServer_nativeContext; 39 40// MtpStorage fields 41static jfieldID field_MtpStorage_storageId; 42static jfieldID field_MtpStorage_path; 43static jfieldID field_MtpStorage_description; 44static jfieldID field_MtpStorage_removable; 45static jfieldID field_MtpStorage_maxFileSize; 46 47static Mutex sMutex; 48 49// ---------------------------------------------------------------------------- 50 51// in android_mtp_MtpDatabase.cpp 52extern IMtpDatabase* getMtpDatabase(JNIEnv *env, jobject database); 53 54static inline MtpServer* getMtpServer(JNIEnv *env, jobject thiz) { 55 return (MtpServer*)env->GetLongField(thiz, field_MtpServer_nativeContext); 56} 57 58static void 59android_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 89static void 90android_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 99static void 100android_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 113static void 114android_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 125static void 126android_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 137static void 138android_mtp_MtpServer_send_device_property_changed(JNIEnv *env, jobject thiz, jint property) 139{ 140 Mutex::Autolock autoLock(sMutex); 141 142 MtpServer* server = getMtpServer(env, thiz); 143 if (server) 144 server->sendDevicePropertyChanged(property); 145 else 146 ALOGE("server is null in send_object_removed"); 147} 148 149static void 150android_mtp_MtpServer_add_storage(JNIEnv *env, jobject thiz, jobject jstorage) 151{ 152 Mutex::Autolock autoLock(sMutex); 153 154 MtpServer* server = getMtpServer(env, thiz); 155 if (server) { 156 jint storageID = env->GetIntField(jstorage, field_MtpStorage_storageId); 157 jstring path = (jstring)env->GetObjectField(jstorage, field_MtpStorage_path); 158 jstring description = (jstring)env->GetObjectField(jstorage, field_MtpStorage_description); 159 jboolean removable = env->GetBooleanField(jstorage, field_MtpStorage_removable); 160 jlong maxFileSize = env->GetLongField(jstorage, field_MtpStorage_maxFileSize); 161 162 const char *pathStr = env->GetStringUTFChars(path, NULL); 163 if (pathStr != NULL) { 164 const char *descriptionStr = env->GetStringUTFChars(description, NULL); 165 if (descriptionStr != NULL) { 166 MtpStorage* storage = new MtpStorage(storageID, pathStr, descriptionStr, 167 removable, maxFileSize); 168 server->addStorage(storage); 169 env->ReleaseStringUTFChars(path, pathStr); 170 env->ReleaseStringUTFChars(description, descriptionStr); 171 } else { 172 env->ReleaseStringUTFChars(path, pathStr); 173 } 174 } 175 } else { 176 ALOGE("server is null in add_storage"); 177 } 178} 179 180static void 181android_mtp_MtpServer_remove_storage(JNIEnv *env, jobject thiz, jint storageId) 182{ 183 Mutex::Autolock autoLock(sMutex); 184 185 MtpServer* server = getMtpServer(env, thiz); 186 if (server) { 187 MtpStorage* storage = server->getStorage(storageId); 188 if (storage) { 189 server->removeStorage(storage); 190 delete storage; 191 } 192 } else 193 ALOGE("server is null in remove_storage"); 194} 195 196// ---------------------------------------------------------------------------- 197 198static const JNINativeMethod gMethods[] = { 199 {"native_setup", "(Landroid/mtp/MtpDatabase;Ljava/io/FileDescriptor;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V", 200 (void *)android_mtp_MtpServer_setup}, 201 {"native_run", "()V", (void *)android_mtp_MtpServer_run}, 202 {"native_cleanup", "()V", (void *)android_mtp_MtpServer_cleanup}, 203 {"native_send_object_added", "(I)V", (void *)android_mtp_MtpServer_send_object_added}, 204 {"native_send_object_removed", "(I)V", (void *)android_mtp_MtpServer_send_object_removed}, 205 {"native_send_device_property_changed", "(I)V", 206 (void *)android_mtp_MtpServer_send_device_property_changed}, 207 {"native_add_storage", "(Landroid/mtp/MtpStorage;)V", 208 (void *)android_mtp_MtpServer_add_storage}, 209 {"native_remove_storage", "(I)V", (void *)android_mtp_MtpServer_remove_storage}, 210}; 211 212int register_android_mtp_MtpServer(JNIEnv *env) 213{ 214 jclass clazz; 215 216 clazz = env->FindClass("android/mtp/MtpStorage"); 217 if (clazz == NULL) { 218 ALOGE("Can't find android/mtp/MtpStorage"); 219 return -1; 220 } 221 field_MtpStorage_storageId = env->GetFieldID(clazz, "mStorageId", "I"); 222 if (field_MtpStorage_storageId == NULL) { 223 ALOGE("Can't find MtpStorage.mStorageId"); 224 return -1; 225 } 226 field_MtpStorage_path = env->GetFieldID(clazz, "mPath", "Ljava/lang/String;"); 227 if (field_MtpStorage_path == NULL) { 228 ALOGE("Can't find MtpStorage.mPath"); 229 return -1; 230 } 231 field_MtpStorage_description = env->GetFieldID(clazz, "mDescription", "Ljava/lang/String;"); 232 if (field_MtpStorage_description == NULL) { 233 ALOGE("Can't find MtpStorage.mDescription"); 234 return -1; 235 } 236 field_MtpStorage_removable = env->GetFieldID(clazz, "mRemovable", "Z"); 237 if (field_MtpStorage_removable == NULL) { 238 ALOGE("Can't find MtpStorage.mRemovable"); 239 return -1; 240 } 241 field_MtpStorage_maxFileSize = env->GetFieldID(clazz, "mMaxFileSize", "J"); 242 if (field_MtpStorage_maxFileSize == NULL) { 243 ALOGE("Can't find MtpStorage.mMaxFileSize"); 244 return -1; 245 } 246 247 clazz = env->FindClass("android/mtp/MtpServer"); 248 if (clazz == NULL) { 249 ALOGE("Can't find android/mtp/MtpServer"); 250 return -1; 251 } 252 field_MtpServer_nativeContext = env->GetFieldID(clazz, "mNativeContext", "J"); 253 if (field_MtpServer_nativeContext == NULL) { 254 ALOGE("Can't find MtpServer.mNativeContext"); 255 return -1; 256 } 257 258 return AndroidRuntime::registerNativeMethods(env, 259 "android/mtp/MtpServer", gMethods, NELEM(gMethods)); 260} 261