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
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_removable;
45static jfieldID field_MtpStorage_maxFileSize;
46
47static Mutex sMutex;
48
49// ----------------------------------------------------------------------------
50
51// in android_mtp_MtpDatabase.cpp
52extern IMtpDatabase* getMtpDatabase(JNIEnv *env, jobject database);
53
54static inline MtpServer* getMtpServer(JNIEnv *env, jobject thiz) {
55    return (MtpServer*)env->GetLongField(thiz, field_MtpServer_nativeContext);
56}
57
58static void
59android_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
89static void
90android_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
99static void
100android_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
113static void
114android_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
125static void
126android_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
137static void
138android_mtp_MtpServer_send_device_property_changed(JNIEnv *env, jobject thiz, jint property)
139{
140    Mutex::Autolock autoLock(sMutex);
141
142    MtpServer* server = getMtpServer(env, thiz);
143    if (server)
144        server->sendDevicePropertyChanged(property);
145    else
146        ALOGE("server is null in send_object_removed");
147}
148
149static void
150android_mtp_MtpServer_add_storage(JNIEnv *env, jobject thiz, jobject jstorage)
151{
152    Mutex::Autolock autoLock(sMutex);
153
154    MtpServer* server = getMtpServer(env, thiz);
155    if (server) {
156        jint storageID = env->GetIntField(jstorage, field_MtpStorage_storageId);
157        jstring path = (jstring)env->GetObjectField(jstorage, field_MtpStorage_path);
158        jstring description = (jstring)env->GetObjectField(jstorage, field_MtpStorage_description);
159        jboolean removable = env->GetBooleanField(jstorage, field_MtpStorage_removable);
160        jlong maxFileSize = env->GetLongField(jstorage, field_MtpStorage_maxFileSize);
161
162        const char *pathStr = env->GetStringUTFChars(path, NULL);
163        if (pathStr != NULL) {
164            const char *descriptionStr = env->GetStringUTFChars(description, NULL);
165            if (descriptionStr != NULL) {
166                MtpStorage* storage = new MtpStorage(storageID, pathStr, descriptionStr,
167                        removable, maxFileSize);
168                server->addStorage(storage);
169                env->ReleaseStringUTFChars(path, pathStr);
170                env->ReleaseStringUTFChars(description, descriptionStr);
171            } else {
172                env->ReleaseStringUTFChars(path, pathStr);
173            }
174        }
175    } else {
176        ALOGE("server is null in add_storage");
177    }
178}
179
180static void
181android_mtp_MtpServer_remove_storage(JNIEnv *env, jobject thiz, jint storageId)
182{
183    Mutex::Autolock autoLock(sMutex);
184
185    MtpServer* server = getMtpServer(env, thiz);
186    if (server) {
187        MtpStorage* storage = server->getStorage(storageId);
188        if (storage) {
189            server->removeStorage(storage);
190            delete storage;
191        }
192    } else
193        ALOGE("server is null in remove_storage");
194}
195
196// ----------------------------------------------------------------------------
197
198static const JNINativeMethod gMethods[] = {
199    {"native_setup",                "(Landroid/mtp/MtpDatabase;Ljava/io/FileDescriptor;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
200                                            (void *)android_mtp_MtpServer_setup},
201    {"native_run",                  "()V",  (void *)android_mtp_MtpServer_run},
202    {"native_cleanup",              "()V",  (void *)android_mtp_MtpServer_cleanup},
203    {"native_send_object_added",    "(I)V", (void *)android_mtp_MtpServer_send_object_added},
204    {"native_send_object_removed",  "(I)V", (void *)android_mtp_MtpServer_send_object_removed},
205    {"native_send_device_property_changed",  "(I)V",
206                                    (void *)android_mtp_MtpServer_send_device_property_changed},
207    {"native_add_storage",          "(Landroid/mtp/MtpStorage;)V",
208                                            (void *)android_mtp_MtpServer_add_storage},
209    {"native_remove_storage",       "(I)V", (void *)android_mtp_MtpServer_remove_storage},
210};
211
212int register_android_mtp_MtpServer(JNIEnv *env)
213{
214    jclass clazz;
215
216    clazz = env->FindClass("android/mtp/MtpStorage");
217    if (clazz == NULL) {
218        ALOGE("Can't find android/mtp/MtpStorage");
219        return -1;
220    }
221    field_MtpStorage_storageId = env->GetFieldID(clazz, "mStorageId", "I");
222    if (field_MtpStorage_storageId == NULL) {
223        ALOGE("Can't find MtpStorage.mStorageId");
224        return -1;
225    }
226    field_MtpStorage_path = env->GetFieldID(clazz, "mPath", "Ljava/lang/String;");
227    if (field_MtpStorage_path == NULL) {
228        ALOGE("Can't find MtpStorage.mPath");
229        return -1;
230    }
231    field_MtpStorage_description = env->GetFieldID(clazz, "mDescription", "Ljava/lang/String;");
232    if (field_MtpStorage_description == NULL) {
233        ALOGE("Can't find MtpStorage.mDescription");
234        return -1;
235    }
236    field_MtpStorage_removable = env->GetFieldID(clazz, "mRemovable", "Z");
237    if (field_MtpStorage_removable == NULL) {
238        ALOGE("Can't find MtpStorage.mRemovable");
239        return -1;
240    }
241    field_MtpStorage_maxFileSize = env->GetFieldID(clazz, "mMaxFileSize", "J");
242    if (field_MtpStorage_maxFileSize == NULL) {
243        ALOGE("Can't find MtpStorage.mMaxFileSize");
244        return -1;
245    }
246
247    clazz = env->FindClass("android/mtp/MtpServer");
248    if (clazz == NULL) {
249        ALOGE("Can't find android/mtp/MtpServer");
250        return -1;
251    }
252    field_MtpServer_nativeContext = env->GetFieldID(clazz, "mNativeContext", "J");
253    if (field_MtpServer_nativeContext == NULL) {
254        ALOGE("Can't find MtpServer.mNativeContext");
255        return -1;
256    }
257
258    return AndroidRuntime::registerNativeMethods(env,
259                "android/mtp/MtpServer", gMethods, NELEM(gMethods));
260}
261