android_mtp_MtpServer.cpp revision dcc31946f2b78be4bf95b1cace2e2c211f027e72
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