Home | History | Annotate | Download | only in jni
      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 
     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_reserveSpace;
     45 static jfieldID field_MtpStorage_removable;
     46 static jfieldID field_MtpStorage_maxFileSize;
     47 
     48 static Mutex sMutex;
     49 
     50 // ----------------------------------------------------------------------------
     51 
     52 // in android_mtp_MtpDatabase.cpp
     53 extern MtpDatabase* getMtpDatabase(JNIEnv *env, jobject database);
     54 
     55 static inline MtpServer* getMtpServer(JNIEnv *env, jobject thiz) {
     56     return (MtpServer*)env->GetIntField(thiz, field_MtpServer_nativeContext);
     57 }
     58 
     59 static void
     60 android_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         ALOGE("could not open MTP driver, errno: %d", errno);
     69     }
     70 }
     71 
     72 static void
     73 android_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 
     82 static void
     83 android_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         ALOGE("server is null in cleanup");
     93     }
     94 }
     95 
     96 static void
     97 android_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 
    108 static void
    109 android_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 
    120 static void
    121 android_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         ALOGE("server is null in add_storage");
    149     }
    150 }
    151 
    152 static void
    153 android_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         ALOGE("server is null in remove_storage");
    166 }
    167 
    168 // ----------------------------------------------------------------------------
    169 
    170 static 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 
    182 static const char* const kClassPathName = "android/mtp/MtpServer";
    183 
    184 int register_android_mtp_MtpServer(JNIEnv *env)
    185 {
    186     jclass clazz;
    187 
    188     clazz = env->FindClass("android/mtp/MtpStorage");
    189     if (clazz == NULL) {
    190         ALOGE("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         ALOGE("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         ALOGE("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         ALOGE("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         ALOGE("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         ALOGE("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         ALOGE("Can't find MtpStorage.mMaxFileSize");
    221         return -1;
    222     }
    223 
    224     clazz = env->FindClass("android/mtp/MtpServer");
    225     if (clazz == NULL) {
    226         ALOGE("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         ALOGE("Can't find MtpServer.mNativeContext");
    232         return -1;
    233     }
    234 
    235     return AndroidRuntime::registerNativeMethods(env,
    236                 "android/mtp/MtpServer", gMethods, NELEM(gMethods));
    237 }
    238