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 60android_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 72static void 73android_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 82static void 83android_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 96static void 97android_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 108static void 109android_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 120static void 121android_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 132static void 133android_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 164static void 165android_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 182static const 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 196int register_android_mtp_MtpServer(JNIEnv *env) 197{ 198 jclass clazz; 199 200 clazz = env->FindClass("android/mtp/MtpStorage"); 201 if (clazz == NULL) { 202 ALOGE("Can't find android/mtp/MtpStorage"); 203 return -1; 204 } 205 field_MtpStorage_storageId = env->GetFieldID(clazz, "mStorageId", "I"); 206 if (field_MtpStorage_storageId == NULL) { 207 ALOGE("Can't find MtpStorage.mStorageId"); 208 return -1; 209 } 210 field_MtpStorage_path = env->GetFieldID(clazz, "mPath", "Ljava/lang/String;"); 211 if (field_MtpStorage_path == NULL) { 212 ALOGE("Can't find MtpStorage.mPath"); 213 return -1; 214 } 215 field_MtpStorage_description = env->GetFieldID(clazz, "mDescription", "Ljava/lang/String;"); 216 if (field_MtpStorage_description == NULL) { 217 ALOGE("Can't find MtpStorage.mDescription"); 218 return -1; 219 } 220 field_MtpStorage_reserveSpace = env->GetFieldID(clazz, "mReserveSpace", "J"); 221 if (field_MtpStorage_reserveSpace == NULL) { 222 ALOGE("Can't find MtpStorage.mReserveSpace"); 223 return -1; 224 } 225 field_MtpStorage_removable = env->GetFieldID(clazz, "mRemovable", "Z"); 226 if (field_MtpStorage_removable == NULL) { 227 ALOGE("Can't find MtpStorage.mRemovable"); 228 return -1; 229 } 230 field_MtpStorage_maxFileSize = env->GetFieldID(clazz, "mMaxFileSize", "J"); 231 if (field_MtpStorage_maxFileSize == NULL) { 232 ALOGE("Can't find MtpStorage.mMaxFileSize"); 233 return -1; 234 } 235 236 clazz = env->FindClass("android/mtp/MtpServer"); 237 if (clazz == NULL) { 238 ALOGE("Can't find android/mtp/MtpServer"); 239 return -1; 240 } 241 field_MtpServer_nativeContext = env->GetFieldID(clazz, "mNativeContext", "J"); 242 if (field_MtpServer_nativeContext == NULL) { 243 ALOGE("Can't find MtpServer.mNativeContext"); 244 return -1; 245 } 246 247 return AndroidRuntime::registerNativeMethods(env, 248 "android/mtp/MtpServer", gMethods, NELEM(gMethods)); 249} 250