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