1 /*
2 * Copyright (C) 2015 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 specic language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "AppFuseJNI"
18 #include "utils/Log.h"
19
20 #include <assert.h>
21 #include <dirent.h>
22 #include <inttypes.h>
23
24 #include <linux/fuse.h>
25 #include <sys/stat.h>
26
27 #include <map>
28
29 #include "jni.h"
30 #include "JNIHelp.h"
31 #include "android_runtime/AndroidRuntime.h"
32 #include "nativehelper/ScopedPrimitiveArray.h"
33 #include "nativehelper/ScopedLocalRef.h"
34
35 namespace {
36
37 // The numbers came from sdcard.c.
38 // Maximum number of bytes to write/read in one request/one reply.
39 constexpr size_t MAX_WRITE = 256 * 1024;
40 constexpr size_t MAX_READ = 128 * 1024;
41
42 constexpr size_t NUM_MAX_HANDLES = 1024;
43
44 // Largest possible request.
45 // The request size is bounded by the maximum size of a FUSE_WRITE request
46 // because it has the largest possible data payload.
47 constexpr size_t MAX_REQUEST_SIZE = sizeof(struct fuse_in_header) +
48 sizeof(struct fuse_write_in) + (MAX_WRITE > MAX_READ ? MAX_WRITE : MAX_READ);
49
50 static jclass app_fuse_class;
51 static jmethodID app_fuse_get_file_size;
52 static jmethodID app_fuse_read_object_bytes;
53 static jmethodID app_fuse_write_object_bytes;
54 static jmethodID app_fuse_flush_file_handle;
55 static jmethodID app_fuse_close_file_handle;
56 static jfieldID app_fuse_buffer;
57
58 // NOTE:
59 // FuseRequest and FuseResponse shares the same buffer to save memory usage, so the handlers must
60 // not access input buffer after writing data to output buffer.
61 struct FuseRequest {
62 char buffer[MAX_REQUEST_SIZE];
FuseRequest__anon0736f3c70111::FuseRequest63 FuseRequest() {}
header__anon0736f3c70111::FuseRequest64 const struct fuse_in_header& header() const {
65 return *(const struct fuse_in_header*) buffer;
66 }
data__anon0736f3c70111::FuseRequest67 void* data() {
68 return (buffer + sizeof(struct fuse_in_header));
69 }
data_length__anon0736f3c70111::FuseRequest70 size_t data_length() const {
71 return header().len - sizeof(struct fuse_in_header);
72 }
73 };
74
75 template<typename T>
76 class FuseResponse {
77 size_t size_;
78 T* const buffer_;
79 public:
FuseResponse(void * buffer)80 FuseResponse(void* buffer) : size_(0), buffer_(static_cast<T*>(buffer)) {}
81
prepare_buffer(size_t size=sizeof (T))82 void prepare_buffer(size_t size = sizeof(T)) {
83 memset(buffer_, 0, size);
84 size_ = size;
85 }
86
set_size(size_t size)87 void set_size(size_t size) {
88 size_ = size;
89 }
90
size() const91 size_t size() const { return size_; }
data() const92 T* data() const { return buffer_; }
93 };
94
95 class ScopedFd {
96 int mFd;
97
98 public:
ScopedFd(int fd)99 explicit ScopedFd(int fd) : mFd(fd) {}
~ScopedFd()100 ~ScopedFd() {
101 close(mFd);
102 }
operator int()103 operator int() {
104 return mFd;
105 }
106 };
107
108 /**
109 * Fuse implementation consists of handlers parsing FUSE commands.
110 */
111 class AppFuse {
112 JNIEnv* env_;
113 jobject self_;
114
115 // Map between file handle and inode.
116 std::map<uint32_t, uint64_t> handles_;
117 uint32_t handle_counter_;
118
119 public:
AppFuse(JNIEnv * env,jobject self)120 AppFuse(JNIEnv* env, jobject self) :
121 env_(env), self_(self), handle_counter_(0) {}
122
handle_fuse_request(int fd,FuseRequest * req)123 void handle_fuse_request(int fd, FuseRequest* req) {
124 ALOGV("Request op=%d", req->header().opcode);
125 switch (req->header().opcode) {
126 // TODO: Handle more operations that are enough to provide seekable
127 // FD.
128 case FUSE_LOOKUP:
129 invoke_handler(fd, req, &AppFuse::handle_fuse_lookup);
130 return;
131 case FUSE_FORGET:
132 // Return without replying.
133 return;
134 case FUSE_INIT:
135 invoke_handler(fd, req, &AppFuse::handle_fuse_init);
136 return;
137 case FUSE_GETATTR:
138 invoke_handler(fd, req, &AppFuse::handle_fuse_getattr);
139 return;
140 case FUSE_OPEN:
141 invoke_handler(fd, req, &AppFuse::handle_fuse_open);
142 return;
143 case FUSE_READ:
144 invoke_handler(fd, req, &AppFuse::handle_fuse_read);
145 return;
146 case FUSE_WRITE:
147 invoke_handler(fd, req, &AppFuse::handle_fuse_write);
148 return;
149 case FUSE_RELEASE:
150 invoke_handler(fd, req, &AppFuse::handle_fuse_release);
151 return;
152 case FUSE_FLUSH:
153 invoke_handler(fd, req, &AppFuse::handle_fuse_flush);
154 return;
155 default: {
156 ALOGV("NOTIMPL op=%d uniq=%" PRIx64 " nid=%" PRIx64 "\n",
157 req->header().opcode,
158 req->header().unique,
159 req->header().nodeid);
160 fuse_reply(fd, req->header().unique, -ENOSYS, NULL, 0);
161 return;
162 }
163 }
164 }
165
166 private:
handle_fuse_lookup(const fuse_in_header & header,const char * name,FuseResponse<fuse_entry_out> * out)167 int handle_fuse_lookup(const fuse_in_header& header,
168 const char* name,
169 FuseResponse<fuse_entry_out>* out) {
170 if (header.nodeid != 1) {
171 return -ENOENT;
172 }
173
174 const int n = atoi(name);
175 if (n == 0) {
176 return -ENOENT;
177 }
178
179 int64_t size = get_file_size(n);
180 if (size < 0) {
181 return -ENOENT;
182 }
183
184 out->prepare_buffer();
185 out->data()->nodeid = n;
186 out->data()->attr_valid = 10;
187 out->data()->entry_valid = 10;
188 out->data()->attr.ino = n;
189 out->data()->attr.mode = S_IFREG | 0777;
190 out->data()->attr.size = size;
191 return 0;
192 }
193
handle_fuse_init(const fuse_in_header &,const fuse_init_in * in,FuseResponse<fuse_init_out> * out)194 int handle_fuse_init(const fuse_in_header&,
195 const fuse_init_in* in,
196 FuseResponse<fuse_init_out>* out) {
197 // Kernel 2.6.16 is the first stable kernel with struct fuse_init_out
198 // defined (fuse version 7.6). The structure is the same from 7.6 through
199 // 7.22. Beginning with 7.23, the structure increased in size and added
200 // new parameters.
201 if (in->major != FUSE_KERNEL_VERSION || in->minor < 6) {
202 ALOGE("Fuse kernel version mismatch: Kernel version %d.%d, "
203 "Expected at least %d.6",
204 in->major, in->minor, FUSE_KERNEL_VERSION);
205 return -1;
206 }
207
208 // Before writing |out|, we need to copy data from |in|.
209 const uint32_t minor = in->minor;
210 const uint32_t max_readahead = in->max_readahead;
211
212 // We limit ourselves to 15 because we don't handle BATCH_FORGET yet
213 size_t response_size = sizeof(fuse_init_out);
214 #if defined(FUSE_COMPAT_22_INIT_OUT_SIZE)
215 // FUSE_KERNEL_VERSION >= 23.
216
217 // If the kernel only works on minor revs older than or equal to 22,
218 // then use the older structure size since this code only uses the 7.22
219 // version of the structure.
220 if (minor <= 22) {
221 response_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
222 }
223 #endif
224 out->prepare_buffer(response_size);
225 out->data()->major = FUSE_KERNEL_VERSION;
226 out->data()->minor = std::min(minor, 15u);
227 out->data()->max_readahead = max_readahead;
228 out->data()->flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
229 out->data()->max_background = 32;
230 out->data()->congestion_threshold = 32;
231 out->data()->max_write = MAX_WRITE;
232
233 return 0;
234 }
235
handle_fuse_getattr(const fuse_in_header & header,const fuse_getattr_in *,FuseResponse<fuse_attr_out> * out)236 int handle_fuse_getattr(const fuse_in_header& header,
237 const fuse_getattr_in* /* in */,
238 FuseResponse<fuse_attr_out>* out) {
239 out->prepare_buffer();
240 out->data()->attr_valid = 10;
241 out->data()->attr.ino = header.nodeid;
242 if (header.nodeid == 1) {
243 out->data()->attr.mode = S_IFDIR | 0777;
244 out->data()->attr.size = 0;
245 } else {
246 int64_t size = get_file_size(header.nodeid);
247 if (size < 0) {
248 return -ENOENT;
249 }
250 out->data()->attr.mode = S_IFREG | 0777;
251 out->data()->attr.size = size;
252 }
253
254 return 0;
255 }
256
handle_fuse_open(const fuse_in_header & header,const fuse_open_in *,FuseResponse<fuse_open_out> * out)257 int handle_fuse_open(const fuse_in_header& header,
258 const fuse_open_in* /* in */,
259 FuseResponse<fuse_open_out>* out) {
260 if (handles_.size() >= NUM_MAX_HANDLES) {
261 // Too many open files.
262 return -EMFILE;
263 }
264 uint32_t handle;
265 do {
266 handle = handle_counter_++;
267 } while (handles_.count(handle) != 0);
268 handles_.insert(std::make_pair(handle, header.nodeid));
269
270 out->prepare_buffer();
271 out->data()->fh = handle;
272 return 0;
273 }
274
handle_fuse_read(const fuse_in_header &,const fuse_read_in * in,FuseResponse<void> * out)275 int handle_fuse_read(const fuse_in_header& /* header */,
276 const fuse_read_in* in,
277 FuseResponse<void>* out) {
278 if (in->size > MAX_READ) {
279 return -EINVAL;
280 }
281 const std::map<uint32_t, uint64_t>::iterator it = handles_.find(in->fh);
282 if (it == handles_.end()) {
283 return -EBADF;
284 }
285 uint64_t offset = in->offset;
286 uint32_t size = in->size;
287
288 // Overwrite the size after writing data.
289 out->prepare_buffer(0);
290 const int64_t result = get_object_bytes(it->second, offset, size, out->data());
291 if (result < 0) {
292 return result;
293 }
294 out->set_size(result);
295 return 0;
296 }
297
handle_fuse_write(const fuse_in_header &,const fuse_write_in * in,FuseResponse<fuse_write_out> * out)298 int handle_fuse_write(const fuse_in_header& /* header */,
299 const fuse_write_in* in,
300 FuseResponse<fuse_write_out>* out) {
301 if (in->size > MAX_WRITE) {
302 return -EINVAL;
303 }
304 const std::map<uint32_t, uint64_t>::iterator it = handles_.find(in->fh);
305 if (it == handles_.end()) {
306 return -EBADF;
307 }
308 const uint64_t offset = in->offset;
309 const uint32_t size = in->size;
310 const void* const buffer = reinterpret_cast<const uint8_t*>(in) + sizeof(fuse_write_in);
311 uint32_t written_size;
312 const int result = write_object_bytes(
313 in->fh, it->second, offset, size, buffer, &written_size);
314 if (result < 0) {
315 return result;
316 }
317 out->prepare_buffer();
318 out->data()->size = written_size;
319 return 0;
320 }
321
handle_fuse_release(const fuse_in_header &,const fuse_release_in * in,FuseResponse<void> *)322 int handle_fuse_release(const fuse_in_header& /* header */,
323 const fuse_release_in* in,
324 FuseResponse<void>* /* out */) {
325 handles_.erase(in->fh);
326 return env_->CallIntMethod(self_, app_fuse_close_file_handle, file_handle_to_jlong(in->fh));
327 }
328
handle_fuse_flush(const fuse_in_header &,const fuse_flush_in * in,FuseResponse<void> *)329 int handle_fuse_flush(const fuse_in_header& /* header */,
330 const fuse_flush_in* in,
331 FuseResponse<void>* /* out */) {
332 return env_->CallIntMethod(self_, app_fuse_flush_file_handle, file_handle_to_jlong(in->fh));
333 }
334
335 template <typename T, typename S>
invoke_handler(int fd,FuseRequest * request,int (AppFuse::* handler)(const fuse_in_header &,const T *,FuseResponse<S> *))336 void invoke_handler(int fd,
337 FuseRequest* request,
338 int (AppFuse::*handler)(const fuse_in_header&,
339 const T*,
340 FuseResponse<S>*)) {
341 FuseResponse<S> response(request->data());
342 const int reply_code = (this->*handler)(
343 request->header(),
344 static_cast<const T*>(request->data()),
345 &response);
346 fuse_reply(
347 fd,
348 request->header().unique,
349 reply_code,
350 request->data(),
351 response.size());
352 }
353
get_file_size(int inode)354 int64_t get_file_size(int inode) {
355 return static_cast<int64_t>(env_->CallLongMethod(
356 self_,
357 app_fuse_get_file_size,
358 static_cast<int>(inode)));
359 }
360
get_object_bytes(int inode,uint64_t offset,uint32_t size,void * buf)361 int64_t get_object_bytes(
362 int inode,
363 uint64_t offset,
364 uint32_t size,
365 void* buf) {
366 const jlong read_size = env_->CallLongMethod(
367 self_,
368 app_fuse_read_object_bytes,
369 static_cast<jint>(inode),
370 static_cast<jlong>(offset),
371 static_cast<jlong>(size));
372 if (read_size <= 0) {
373 return read_size;
374 }
375 ScopedLocalRef<jbyteArray> array(
376 env_, static_cast<jbyteArray>(env_->GetObjectField(self_, app_fuse_buffer)));
377 if (array.get() == nullptr) {
378 return -EFAULT;
379 }
380 ScopedByteArrayRO bytes(env_, array.get());
381 if (bytes.get() == nullptr) {
382 return -ENOMEM;
383 }
384 memcpy(buf, bytes.get(), read_size);
385 return read_size;
386 }
387
write_object_bytes(uint64_t handle,int inode,uint64_t offset,uint32_t size,const void * buffer,uint32_t * written_size)388 int write_object_bytes(uint64_t handle, int inode, uint64_t offset, uint32_t size,
389 const void* buffer, uint32_t* written_size) {
390 static_assert(sizeof(uint64_t) <= sizeof(jlong),
391 "jlong must be able to express any uint64_t values");
392 ScopedLocalRef<jbyteArray> array(
393 env_,
394 static_cast<jbyteArray>(env_->GetObjectField(self_, app_fuse_buffer)));
395 {
396 ScopedByteArrayRW bytes(env_, array.get());
397 if (bytes.get() == nullptr) {
398 return -EIO;
399 }
400 memcpy(bytes.get(), buffer, size);
401 }
402 const int result = env_->CallIntMethod(
403 self_,
404 app_fuse_write_object_bytes,
405 file_handle_to_jlong(handle),
406 inode,
407 offset,
408 size,
409 array.get());
410 if (result < 0) {
411 return result;
412 }
413 *written_size = result;
414 return 0;
415 }
416
file_handle_to_jlong(uint64_t handle)417 static jlong file_handle_to_jlong(uint64_t handle) {
418 static_assert(
419 sizeof(uint64_t) <= sizeof(jlong),
420 "jlong must be able to express any uint64_t values");
421 return static_cast<jlong>(handle);
422 }
423
fuse_reply(int fd,int unique,int reply_code,void * reply_data,size_t reply_size)424 static void fuse_reply(int fd, int unique, int reply_code, void* reply_data,
425 size_t reply_size) {
426 // Don't send any data for error case.
427 if (reply_code != 0) {
428 reply_size = 0;
429 }
430
431 struct fuse_out_header hdr;
432 hdr.len = reply_size + sizeof(hdr);
433 hdr.error = reply_code;
434 hdr.unique = unique;
435
436 struct iovec vec[2];
437 vec[0].iov_base = &hdr;
438 vec[0].iov_len = sizeof(hdr);
439 vec[1].iov_base = reply_data;
440 vec[1].iov_len = reply_size;
441
442 const int res = writev(fd, vec, reply_size != 0 ? 2 : 1);
443 if (res < 0) {
444 ALOGE("*** REPLY FAILED *** %d\n", errno);
445 }
446 }
447 };
448
com_android_mtp_AppFuse_start_app_fuse_loop(JNIEnv * env,jobject self,jint jfd)449 void com_android_mtp_AppFuse_start_app_fuse_loop(JNIEnv* env, jobject self, jint jfd) {
450 ScopedFd fd(static_cast<int>(jfd));
451 AppFuse appfuse(env, self);
452
453 ALOGV("Start fuse loop.");
454 while (true) {
455 FuseRequest request;
456
457 const ssize_t result = TEMP_FAILURE_RETRY(
458 read(fd, request.buffer, sizeof(request.buffer)));
459 if (result < 0) {
460 if (errno == ENODEV) {
461 ALOGV("AppFuse was unmounted.\n");
462 return;
463 }
464 ALOGE("Failed to read bytes from FD: errno=%d\n", errno);
465 continue;
466 }
467
468 const size_t length = static_cast<size_t>(result);
469 if (length < sizeof(struct fuse_in_header)) {
470 ALOGE("request too short: len=%zu\n", length);
471 continue;
472 }
473
474 if (request.header().len != length) {
475 ALOGE("malformed header: len=%zu, hdr->len=%u\n",
476 length, request.header().len);
477 continue;
478 }
479
480 appfuse.handle_fuse_request(fd, &request);
481 }
482 }
483
484 static const JNINativeMethod gMethods[] = {
485 {
486 "native_start_app_fuse_loop",
487 "(I)V",
488 (void *) com_android_mtp_AppFuse_start_app_fuse_loop
489 }
490 };
491
492 }
493
JNI_OnLoad(JavaVM * vm,void *)494 jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) {
495 JNIEnv* env = nullptr;
496 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
497 ALOGE("ERROR: GetEnv failed\n");
498 return -1;
499
500 }
501 assert(env != nullptr);
502
503 jclass clazz = env->FindClass("com/android/mtp/AppFuse");
504 if (clazz == nullptr) {
505 ALOGE("Can't find com/android/mtp/AppFuse");
506 return -1;
507 }
508
509 app_fuse_class = static_cast<jclass>(env->NewGlobalRef(clazz));
510 if (app_fuse_class == nullptr) {
511 ALOGE("Can't obtain global reference for com/android/mtp/AppFuse");
512 return -1;
513 }
514
515 app_fuse_get_file_size = env->GetMethodID(
516 app_fuse_class, "getFileSize", "(I)J");
517 if (app_fuse_get_file_size == nullptr) {
518 ALOGE("Can't find getFileSize");
519 return -1;
520 }
521
522 app_fuse_read_object_bytes = env->GetMethodID(
523 app_fuse_class, "readObjectBytes", "(IJJ)J");
524 if (app_fuse_read_object_bytes == nullptr) {
525 ALOGE("Can't find readObjectBytes");
526 return -1;
527 }
528
529 app_fuse_write_object_bytes = env->GetMethodID(app_fuse_class, "writeObjectBytes", "(JIJI[B)I");
530 if (app_fuse_write_object_bytes == nullptr) {
531 ALOGE("Can't find writeObjectBytes");
532 return -1;
533 }
534
535 app_fuse_flush_file_handle = env->GetMethodID(app_fuse_class, "flushFileHandle", "(J)I");
536 if (app_fuse_flush_file_handle == nullptr) {
537 ALOGE("Can't find flushFileHandle");
538 return -1;
539 }
540
541 app_fuse_close_file_handle = env->GetMethodID(app_fuse_class, "closeFileHandle", "(J)I");
542 if (app_fuse_close_file_handle == nullptr) {
543 ALOGE("Can't find closeFileHandle");
544 return -1;
545 }
546
547 app_fuse_buffer = env->GetFieldID(app_fuse_class, "mBuffer", "[B");
548 if (app_fuse_buffer == nullptr) {
549 ALOGE("Can't find mBuffer");
550 return -1;
551 }
552
553 const jfieldID read_max_fied = env->GetStaticFieldID(app_fuse_class, "MAX_READ", "I");
554 if (static_cast<int>(env->GetStaticIntField(app_fuse_class, read_max_fied)) != MAX_READ) {
555 return -1;
556 }
557
558 const jfieldID write_max_fied = env->GetStaticFieldID(app_fuse_class, "MAX_WRITE", "I");
559 if (static_cast<int>(env->GetStaticIntField(app_fuse_class, write_max_fied)) != MAX_WRITE) {
560 return -1;
561 }
562
563 const int result = android::AndroidRuntime::registerNativeMethods(
564 env, "com/android/mtp/AppFuse", gMethods, NELEM(gMethods));
565 if (result < 0) {
566 return -1;
567 }
568
569 return JNI_VERSION_1_4;
570 }
571