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