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->GetLongField(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->SetLongField(thiz, field_MtpServer_nativeContext, (jlong)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->SetLongField(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_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 
    132 static void
    133 android_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 
    164 static void
    165 android_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 
    182 static 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 
    196 int 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