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