blob: 9018d0ea94f837fa63b03d1afd6b2af92bfd5893 [file] [log] [blame]
Daichi Hironobee50c02015-12-14 11:00:54 +09001/*
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
Daichi Hironobee50c02015-12-14 11:00:54 +090017#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>
Mark Salyzyn4d6c3722016-10-17 10:10:55 -070026#include <sys/uio.h>
Daichi Hironobee50c02015-12-14 11:00:54 +090027
28#include <map>
29
30#include "jni.h"
31#include "JNIHelp.h"
32#include "android_runtime/AndroidRuntime.h"
Daichi Hironocc9a7d72015-10-28 09:43:48 +090033#include "nativehelper/ScopedPrimitiveArray.h"
Daichi Hironoaf6b6652016-01-20 19:01:57 +090034#include "nativehelper/ScopedLocalRef.h"
Daichi Hironobee50c02015-12-14 11:00:54 +090035
36namespace {
37
Daichi Hirono2153e8222016-01-11 17:43:55 +090038// The numbers came from sdcard.c.
39// Maximum number of bytes to write/read in one request/one reply.
Daichi Hironobee50c02015-12-14 11:00:54 +090040constexpr size_t MAX_WRITE = 256 * 1024;
Daichi Hirono2153e8222016-01-11 17:43:55 +090041constexpr size_t MAX_READ = 128 * 1024;
42
Daichi Hironocc9a7d72015-10-28 09:43:48 +090043constexpr size_t NUM_MAX_HANDLES = 1024;
Daichi Hironobee50c02015-12-14 11:00:54 +090044
45// Largest possible request.
46// The request size is bounded by the maximum size of a FUSE_WRITE request
47// because it has the largest possible data payload.
48constexpr size_t MAX_REQUEST_SIZE = sizeof(struct fuse_in_header) +
Daichi Hironofab4a972016-01-15 16:54:24 +090049 sizeof(struct fuse_write_in) + (MAX_WRITE > MAX_READ ? MAX_WRITE : MAX_READ);
Daichi Hironobee50c02015-12-14 11:00:54 +090050
51static jclass app_fuse_class;
Daichi Hironocc9a7d72015-10-28 09:43:48 +090052static jmethodID app_fuse_get_file_size;
Daichi Hirono2f310f62016-01-27 12:34:29 +090053static jmethodID app_fuse_read_object_bytes;
Daichi Hirono09ece6c2016-01-20 19:09:25 +090054static jmethodID app_fuse_write_object_bytes;
Daichi Hironof4e7fa82016-03-28 16:07:45 +090055static jmethodID app_fuse_flush_file_handle;
56static jmethodID app_fuse_close_file_handle;
Daichi Hirono2f310f62016-01-27 12:34:29 +090057static jfieldID app_fuse_buffer;
Daichi Hironobee50c02015-12-14 11:00:54 +090058
Daichi Hirono2153e8222016-01-11 17:43:55 +090059// NOTE:
60// FuseRequest and FuseResponse shares the same buffer to save memory usage, so the handlers must
61// not access input buffer after writing data to output buffer.
Daichi Hironobee50c02015-12-14 11:00:54 +090062struct FuseRequest {
63 char buffer[MAX_REQUEST_SIZE];
64 FuseRequest() {}
65 const struct fuse_in_header& header() const {
66 return *(const struct fuse_in_header*) buffer;
67 }
Daichi Hirono2153e8222016-01-11 17:43:55 +090068 void* data() {
Daichi Hironobee50c02015-12-14 11:00:54 +090069 return (buffer + sizeof(struct fuse_in_header));
70 }
71 size_t data_length() const {
72 return header().len - sizeof(struct fuse_in_header);
73 }
74};
75
Daichi Hirono2153e8222016-01-11 17:43:55 +090076template<typename T>
77class FuseResponse {
78 size_t size_;
79 T* const buffer_;
80public:
81 FuseResponse(void* buffer) : size_(0), buffer_(static_cast<T*>(buffer)) {}
82
83 void prepare_buffer(size_t size = sizeof(T)) {
84 memset(buffer_, 0, size);
85 size_ = size;
86 }
87
88 void set_size(size_t size) {
89 size_ = size;
90 }
91
92 size_t size() const { return size_; }
93 T* data() const { return buffer_; }
94};
95
Daichi Hirono91e3b502015-12-16 09:24:16 +090096class ScopedFd {
97 int mFd;
98
99public:
100 explicit ScopedFd(int fd) : mFd(fd) {}
101 ~ScopedFd() {
102 close(mFd);
103 }
104 operator int() {
105 return mFd;
106 }
107};
108
Daichi Hironobee50c02015-12-14 11:00:54 +0900109/**
Daichi Hirono2153e8222016-01-11 17:43:55 +0900110 * Fuse implementation consists of handlers parsing FUSE commands.
Daichi Hironobee50c02015-12-14 11:00:54 +0900111 */
112class AppFuse {
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900113 JNIEnv* env_;
114 jobject self_;
115
116 // Map between file handle and inode.
117 std::map<uint32_t, uint64_t> handles_;
118 uint32_t handle_counter_;
119
Daichi Hironobee50c02015-12-14 11:00:54 +0900120public:
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900121 AppFuse(JNIEnv* env, jobject self) :
122 env_(env), self_(self), handle_counter_(0) {}
Daichi Hironobee50c02015-12-14 11:00:54 +0900123
Daichi Hirono07f48ad2016-05-02 12:48:43 +0900124 void handle_fuse_request(int fd, FuseRequest* req) {
Daichi Hirono2153e8222016-01-11 17:43:55 +0900125 ALOGV("Request op=%d", req->header().opcode);
126 switch (req->header().opcode) {
Daichi Hironobee50c02015-12-14 11:00:54 +0900127 // TODO: Handle more operations that are enough to provide seekable
128 // FD.
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900129 case FUSE_LOOKUP:
130 invoke_handler(fd, req, &AppFuse::handle_fuse_lookup);
Daichi Hirono07f48ad2016-05-02 12:48:43 +0900131 return;
132 case FUSE_FORGET:
133 // Return without replying.
134 return;
Daichi Hironobee50c02015-12-14 11:00:54 +0900135 case FUSE_INIT:
136 invoke_handler(fd, req, &AppFuse::handle_fuse_init);
Daichi Hirono07f48ad2016-05-02 12:48:43 +0900137 return;
Daichi Hironobee50c02015-12-14 11:00:54 +0900138 case FUSE_GETATTR:
139 invoke_handler(fd, req, &AppFuse::handle_fuse_getattr);
Daichi Hirono07f48ad2016-05-02 12:48:43 +0900140 return;
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900141 case FUSE_OPEN:
142 invoke_handler(fd, req, &AppFuse::handle_fuse_open);
Daichi Hirono07f48ad2016-05-02 12:48:43 +0900143 return;
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900144 case FUSE_READ:
Daichi Hirono2153e8222016-01-11 17:43:55 +0900145 invoke_handler(fd, req, &AppFuse::handle_fuse_read);
Daichi Hirono07f48ad2016-05-02 12:48:43 +0900146 return;
Daichi Hirono09ece6c2016-01-20 19:09:25 +0900147 case FUSE_WRITE:
148 invoke_handler(fd, req, &AppFuse::handle_fuse_write);
Daichi Hirono07f48ad2016-05-02 12:48:43 +0900149 return;
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900150 case FUSE_RELEASE:
Daichi Hirono2153e8222016-01-11 17:43:55 +0900151 invoke_handler(fd, req, &AppFuse::handle_fuse_release);
Daichi Hirono07f48ad2016-05-02 12:48:43 +0900152 return;
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900153 case FUSE_FLUSH:
Daichi Hirono2153e8222016-01-11 17:43:55 +0900154 invoke_handler(fd, req, &AppFuse::handle_fuse_flush);
Daichi Hirono07f48ad2016-05-02 12:48:43 +0900155 return;
Daichi Hironobee50c02015-12-14 11:00:54 +0900156 default: {
157 ALOGV("NOTIMPL op=%d uniq=%" PRIx64 " nid=%" PRIx64 "\n",
Daichi Hirono2153e8222016-01-11 17:43:55 +0900158 req->header().opcode,
159 req->header().unique,
160 req->header().nodeid);
161 fuse_reply(fd, req->header().unique, -ENOSYS, NULL, 0);
Daichi Hirono07f48ad2016-05-02 12:48:43 +0900162 return;
Daichi Hironobee50c02015-12-14 11:00:54 +0900163 }
164 }
165 }
166
167private:
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900168 int handle_fuse_lookup(const fuse_in_header& header,
169 const char* name,
Daichi Hirono2153e8222016-01-11 17:43:55 +0900170 FuseResponse<fuse_entry_out>* out) {
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900171 if (header.nodeid != 1) {
172 return -ENOENT;
173 }
174
175 const int n = atoi(name);
176 if (n == 0) {
177 return -ENOENT;
178 }
179
180 int64_t size = get_file_size(n);
181 if (size < 0) {
182 return -ENOENT;
183 }
184
Daichi Hirono2153e8222016-01-11 17:43:55 +0900185 out->prepare_buffer();
186 out->data()->nodeid = n;
187 out->data()->attr_valid = 10;
188 out->data()->entry_valid = 10;
189 out->data()->attr.ino = n;
190 out->data()->attr.mode = S_IFREG | 0777;
191 out->data()->attr.size = size;
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900192 return 0;
193 }
194
Daichi Hironobee50c02015-12-14 11:00:54 +0900195 int handle_fuse_init(const fuse_in_header&,
196 const fuse_init_in* in,
Daichi Hirono2153e8222016-01-11 17:43:55 +0900197 FuseResponse<fuse_init_out>* out) {
Daichi Hironobee50c02015-12-14 11:00:54 +0900198 // Kernel 2.6.16 is the first stable kernel with struct fuse_init_out
199 // defined (fuse version 7.6). The structure is the same from 7.6 through
200 // 7.22. Beginning with 7.23, the structure increased in size and added
201 // new parameters.
202 if (in->major != FUSE_KERNEL_VERSION || in->minor < 6) {
203 ALOGE("Fuse kernel version mismatch: Kernel version %d.%d, "
204 "Expected at least %d.6",
205 in->major, in->minor, FUSE_KERNEL_VERSION);
206 return -1;
207 }
208
Daichi Hirono2153e8222016-01-11 17:43:55 +0900209 // Before writing |out|, we need to copy data from |in|.
210 const uint32_t minor = in->minor;
211 const uint32_t max_readahead = in->max_readahead;
212
Daichi Hironobee50c02015-12-14 11:00:54 +0900213 // We limit ourselves to 15 because we don't handle BATCH_FORGET yet
Daichi Hirono2153e8222016-01-11 17:43:55 +0900214 size_t response_size = sizeof(fuse_init_out);
Daichi Hironobee50c02015-12-14 11:00:54 +0900215#if defined(FUSE_COMPAT_22_INIT_OUT_SIZE)
216 // FUSE_KERNEL_VERSION >= 23.
217
218 // If the kernel only works on minor revs older than or equal to 22,
219 // then use the older structure size since this code only uses the 7.22
220 // version of the structure.
Daichi Hirono2153e8222016-01-11 17:43:55 +0900221 if (minor <= 22) {
222 response_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
Daichi Hironobee50c02015-12-14 11:00:54 +0900223 }
Daichi Hironobee50c02015-12-14 11:00:54 +0900224#endif
Daichi Hirono2153e8222016-01-11 17:43:55 +0900225 out->prepare_buffer(response_size);
226 out->data()->major = FUSE_KERNEL_VERSION;
227 out->data()->minor = std::min(minor, 15u);
228 out->data()->max_readahead = max_readahead;
229 out->data()->flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
230 out->data()->max_background = 32;
231 out->data()->congestion_threshold = 32;
232 out->data()->max_write = MAX_WRITE;
Daichi Hironobee50c02015-12-14 11:00:54 +0900233
234 return 0;
235 }
236
237 int handle_fuse_getattr(const fuse_in_header& header,
238 const fuse_getattr_in* /* in */,
Daichi Hirono2153e8222016-01-11 17:43:55 +0900239 FuseResponse<fuse_attr_out>* out) {
240 out->prepare_buffer();
241 out->data()->attr_valid = 10;
242 out->data()->attr.ino = header.nodeid;
243 if (header.nodeid == 1) {
244 out->data()->attr.mode = S_IFDIR | 0777;
245 out->data()->attr.size = 0;
246 } else {
247 int64_t size = get_file_size(header.nodeid);
248 if (size < 0) {
249 return -ENOENT;
250 }
251 out->data()->attr.mode = S_IFREG | 0777;
252 out->data()->attr.size = size;
Daichi Hironobee50c02015-12-14 11:00:54 +0900253 }
Daichi Hirono2153e8222016-01-11 17:43:55 +0900254
Daichi Hironobee50c02015-12-14 11:00:54 +0900255 return 0;
256 }
257
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900258 int handle_fuse_open(const fuse_in_header& header,
259 const fuse_open_in* /* in */,
Daichi Hirono2153e8222016-01-11 17:43:55 +0900260 FuseResponse<fuse_open_out>* out) {
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900261 if (handles_.size() >= NUM_MAX_HANDLES) {
262 // Too many open files.
263 return -EMFILE;
264 }
265 uint32_t handle;
266 do {
267 handle = handle_counter_++;
268 } while (handles_.count(handle) != 0);
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900269 handles_.insert(std::make_pair(handle, header.nodeid));
Daichi Hirono2153e8222016-01-11 17:43:55 +0900270
271 out->prepare_buffer();
272 out->data()->fh = handle;
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900273 return 0;
274 }
275
276 int handle_fuse_read(const fuse_in_header& /* header */,
277 const fuse_read_in* in,
Daichi Hirono2153e8222016-01-11 17:43:55 +0900278 FuseResponse<void>* out) {
279 if (in->size > MAX_READ) {
280 return -EINVAL;
281 }
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900282 const std::map<uint32_t, uint64_t>::iterator it = handles_.find(in->fh);
283 if (it == handles_.end()) {
284 return -EBADF;
285 }
Daichi Hirono2153e8222016-01-11 17:43:55 +0900286 uint64_t offset = in->offset;
287 uint32_t size = in->size;
288
289 // Overwrite the size after writing data.
290 out->prepare_buffer(0);
291 const int64_t result = get_object_bytes(it->second, offset, size, out->data());
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900292 if (result < 0) {
Daichi Hirono2f310f62016-01-27 12:34:29 +0900293 return result;
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900294 }
Daichi Hirono2153e8222016-01-11 17:43:55 +0900295 out->set_size(result);
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900296 return 0;
297 }
298
Daichi Hirono09ece6c2016-01-20 19:09:25 +0900299 int handle_fuse_write(const fuse_in_header& /* header */,
300 const fuse_write_in* in,
301 FuseResponse<fuse_write_out>* out) {
302 if (in->size > MAX_WRITE) {
303 return -EINVAL;
304 }
305 const std::map<uint32_t, uint64_t>::iterator it = handles_.find(in->fh);
306 if (it == handles_.end()) {
307 return -EBADF;
308 }
309 const uint64_t offset = in->offset;
310 const uint32_t size = in->size;
311 const void* const buffer = reinterpret_cast<const uint8_t*>(in) + sizeof(fuse_write_in);
312 uint32_t written_size;
Daichi Hironof4e7fa82016-03-28 16:07:45 +0900313 const int result = write_object_bytes(
314 in->fh, it->second, offset, size, buffer, &written_size);
Daichi Hirono09ece6c2016-01-20 19:09:25 +0900315 if (result < 0) {
316 return result;
317 }
318 out->prepare_buffer();
319 out->data()->size = written_size;
320 return 0;
321 }
322
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900323 int handle_fuse_release(const fuse_in_header& /* header */,
324 const fuse_release_in* in,
Daichi Hirono2153e8222016-01-11 17:43:55 +0900325 FuseResponse<void>* /* out */) {
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900326 handles_.erase(in->fh);
Daichi Hironof4e7fa82016-03-28 16:07:45 +0900327 return env_->CallIntMethod(self_, app_fuse_close_file_handle, file_handle_to_jlong(in->fh));
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900328 }
329
330 int handle_fuse_flush(const fuse_in_header& /* header */,
Daichi Hironof4e7fa82016-03-28 16:07:45 +0900331 const fuse_flush_in* in,
Daichi Hirono2153e8222016-01-11 17:43:55 +0900332 FuseResponse<void>* /* out */) {
Daichi Hironof4e7fa82016-03-28 16:07:45 +0900333 return env_->CallIntMethod(self_, app_fuse_flush_file_handle, file_handle_to_jlong(in->fh));
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900334 }
335
Daichi Hironobee50c02015-12-14 11:00:54 +0900336 template <typename T, typename S>
337 void invoke_handler(int fd,
Daichi Hirono2153e8222016-01-11 17:43:55 +0900338 FuseRequest* request,
Daichi Hironobee50c02015-12-14 11:00:54 +0900339 int (AppFuse::*handler)(const fuse_in_header&,
340 const T*,
Daichi Hirono2153e8222016-01-11 17:43:55 +0900341 FuseResponse<S>*)) {
342 FuseResponse<S> response(request->data());
Daichi Hironobee50c02015-12-14 11:00:54 +0900343 const int reply_code = (this->*handler)(
Daichi Hirono2153e8222016-01-11 17:43:55 +0900344 request->header(),
345 static_cast<const T*>(request->data()),
346 &response);
Daichi Hironobee50c02015-12-14 11:00:54 +0900347 fuse_reply(
348 fd,
Daichi Hirono2153e8222016-01-11 17:43:55 +0900349 request->header().unique,
Daichi Hironobee50c02015-12-14 11:00:54 +0900350 reply_code,
Daichi Hirono2153e8222016-01-11 17:43:55 +0900351 request->data(),
352 response.size());
Daichi Hironobee50c02015-12-14 11:00:54 +0900353 }
354
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900355 int64_t get_file_size(int inode) {
356 return static_cast<int64_t>(env_->CallLongMethod(
357 self_,
358 app_fuse_get_file_size,
359 static_cast<int>(inode)));
360 }
361
362 int64_t get_object_bytes(
363 int inode,
364 uint64_t offset,
365 uint32_t size,
366 void* buf) {
Daichi Hirono2f310f62016-01-27 12:34:29 +0900367 const jlong read_size = env_->CallLongMethod(
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900368 self_,
Daichi Hirono2f310f62016-01-27 12:34:29 +0900369 app_fuse_read_object_bytes,
370 static_cast<jint>(inode),
371 static_cast<jlong>(offset),
372 static_cast<jlong>(size));
373 if (read_size <= 0) {
374 return read_size;
375 }
376 ScopedLocalRef<jbyteArray> array(
377 env_, static_cast<jbyteArray>(env_->GetObjectField(self_, app_fuse_buffer)));
Daichi Hironoaf6b6652016-01-20 19:01:57 +0900378 if (array.get() == nullptr) {
Daichi Hirono2f310f62016-01-27 12:34:29 +0900379 return -EFAULT;
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900380 }
Daichi Hironoaf6b6652016-01-20 19:01:57 +0900381 ScopedByteArrayRO bytes(env_, array.get());
Daichi Hironob36b1552016-01-25 14:26:14 +0900382 if (bytes.get() == nullptr) {
Daichi Hirono2f310f62016-01-27 12:34:29 +0900383 return -ENOMEM;
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900384 }
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900385 memcpy(buf, bytes.get(), read_size);
386 return read_size;
387 }
388
Daichi Hironof4e7fa82016-03-28 16:07:45 +0900389 int write_object_bytes(uint64_t handle, int inode, uint64_t offset, uint32_t size,
390 const void* buffer, uint32_t* written_size) {
391 static_assert(sizeof(uint64_t) <= sizeof(jlong),
392 "jlong must be able to express any uint64_t values");
Daichi Hirono09ece6c2016-01-20 19:09:25 +0900393 ScopedLocalRef<jbyteArray> array(
394 env_,
395 static_cast<jbyteArray>(env_->GetObjectField(self_, app_fuse_buffer)));
396 {
397 ScopedByteArrayRW bytes(env_, array.get());
398 if (bytes.get() == nullptr) {
399 return -EIO;
400 }
401 memcpy(bytes.get(), buffer, size);
402 }
Daichi Hironof4e7fa82016-03-28 16:07:45 +0900403 const int result = env_->CallIntMethod(
404 self_,
405 app_fuse_write_object_bytes,
406 file_handle_to_jlong(handle),
407 inode,
408 offset,
409 size,
410 array.get());
411 if (result < 0) {
412 return result;
Daichi Hirono09ece6c2016-01-20 19:09:25 +0900413 }
Daichi Hironof4e7fa82016-03-28 16:07:45 +0900414 *written_size = result;
Daichi Hirono09ece6c2016-01-20 19:09:25 +0900415 return 0;
416 }
417
Daichi Hironof4e7fa82016-03-28 16:07:45 +0900418 static jlong file_handle_to_jlong(uint64_t handle) {
419 static_assert(
420 sizeof(uint64_t) <= sizeof(jlong),
421 "jlong must be able to express any uint64_t values");
422 return static_cast<jlong>(handle);
423 }
424
Daichi Hironobee50c02015-12-14 11:00:54 +0900425 static void fuse_reply(int fd, int unique, int reply_code, void* reply_data,
426 size_t reply_size) {
427 // Don't send any data for error case.
428 if (reply_code != 0) {
429 reply_size = 0;
430 }
431
432 struct fuse_out_header hdr;
433 hdr.len = reply_size + sizeof(hdr);
434 hdr.error = reply_code;
435 hdr.unique = unique;
436
437 struct iovec vec[2];
438 vec[0].iov_base = &hdr;
439 vec[0].iov_len = sizeof(hdr);
440 vec[1].iov_base = reply_data;
441 vec[1].iov_len = reply_size;
442
443 const int res = writev(fd, vec, reply_size != 0 ? 2 : 1);
444 if (res < 0) {
445 ALOGE("*** REPLY FAILED *** %d\n", errno);
446 }
447 }
448};
449
Daichi Hirono07f48ad2016-05-02 12:48:43 +0900450void com_android_mtp_AppFuse_start_app_fuse_loop(JNIEnv* env, jobject self, jint jfd) {
Daichi Hironoe6054c02016-01-20 15:36:04 +0900451 ScopedFd fd(static_cast<int>(jfd));
Daichi Hironobee50c02015-12-14 11:00:54 +0900452 AppFuse appfuse(env, self);
453
Daichi Hironod0ef1392016-04-08 10:07:01 +0900454 ALOGV("Start fuse loop.");
Daichi Hironobee50c02015-12-14 11:00:54 +0900455 while (true) {
456 FuseRequest request;
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900457
Daichi Hironobee50c02015-12-14 11:00:54 +0900458 const ssize_t result = TEMP_FAILURE_RETRY(
459 read(fd, request.buffer, sizeof(request.buffer)));
460 if (result < 0) {
461 if (errno == ENODEV) {
Daichi Hirono07f48ad2016-05-02 12:48:43 +0900462 ALOGV("AppFuse was unmounted.\n");
463 return;
Daichi Hironobee50c02015-12-14 11:00:54 +0900464 }
465 ALOGE("Failed to read bytes from FD: errno=%d\n", errno);
466 continue;
467 }
468
469 const size_t length = static_cast<size_t>(result);
470 if (length < sizeof(struct fuse_in_header)) {
471 ALOGE("request too short: len=%zu\n", length);
472 continue;
473 }
474
475 if (request.header().len != length) {
476 ALOGE("malformed header: len=%zu, hdr->len=%u\n",
477 length, request.header().len);
478 continue;
479 }
480
Daichi Hirono07f48ad2016-05-02 12:48:43 +0900481 appfuse.handle_fuse_request(fd, &request);
Daichi Hironobee50c02015-12-14 11:00:54 +0900482 }
483}
484
485static const JNINativeMethod gMethods[] = {
486 {
487 "native_start_app_fuse_loop",
Daichi Hirono07f48ad2016-05-02 12:48:43 +0900488 "(I)V",
Daichi Hironobee50c02015-12-14 11:00:54 +0900489 (void *) com_android_mtp_AppFuse_start_app_fuse_loop
490 }
491};
492
493}
494
495jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) {
496 JNIEnv* env = nullptr;
497 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
498 ALOGE("ERROR: GetEnv failed\n");
499 return -1;
500
501 }
502 assert(env != nullptr);
503
504 jclass clazz = env->FindClass("com/android/mtp/AppFuse");
505 if (clazz == nullptr) {
506 ALOGE("Can't find com/android/mtp/AppFuse");
507 return -1;
508 }
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900509
Daichi Hironobee50c02015-12-14 11:00:54 +0900510 app_fuse_class = static_cast<jclass>(env->NewGlobalRef(clazz));
511 if (app_fuse_class == nullptr) {
512 ALOGE("Can't obtain global reference for com/android/mtp/AppFuse");
513 return -1;
514 }
515
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900516 app_fuse_get_file_size = env->GetMethodID(
517 app_fuse_class, "getFileSize", "(I)J");
518 if (app_fuse_get_file_size == nullptr) {
519 ALOGE("Can't find getFileSize");
520 return -1;
521 }
522
Daichi Hirono2f310f62016-01-27 12:34:29 +0900523 app_fuse_read_object_bytes = env->GetMethodID(
524 app_fuse_class, "readObjectBytes", "(IJJ)J");
525 if (app_fuse_read_object_bytes == nullptr) {
526 ALOGE("Can't find readObjectBytes");
527 return -1;
528 }
529
Daichi Hironof4e7fa82016-03-28 16:07:45 +0900530 app_fuse_write_object_bytes = env->GetMethodID(app_fuse_class, "writeObjectBytes", "(JIJI[B)I");
531 if (app_fuse_write_object_bytes == nullptr) {
532 ALOGE("Can't find writeObjectBytes");
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900533 return -1;
534 }
535
Daichi Hironof4e7fa82016-03-28 16:07:45 +0900536 app_fuse_flush_file_handle = env->GetMethodID(app_fuse_class, "flushFileHandle", "(J)I");
537 if (app_fuse_flush_file_handle == nullptr) {
538 ALOGE("Can't find flushFileHandle");
539 return -1;
540 }
541
542 app_fuse_close_file_handle = env->GetMethodID(app_fuse_class, "closeFileHandle", "(J)I");
543 if (app_fuse_close_file_handle == nullptr) {
544 ALOGE("Can't find closeFileHandle");
Daichi Hirono09ece6c2016-01-20 19:09:25 +0900545 return -1;
546 }
547
548 app_fuse_buffer = env->GetFieldID(app_fuse_class, "mBuffer", "[B");
549 if (app_fuse_buffer == nullptr) {
550 ALOGE("Can't find mBuffer");
551 return -1;
552 }
553
554 const jfieldID read_max_fied = env->GetStaticFieldID(app_fuse_class, "MAX_READ", "I");
555 if (static_cast<int>(env->GetStaticIntField(app_fuse_class, read_max_fied)) != MAX_READ) {
556 return -1;
557 }
558
559 const jfieldID write_max_fied = env->GetStaticFieldID(app_fuse_class, "MAX_WRITE", "I");
560 if (static_cast<int>(env->GetStaticIntField(app_fuse_class, write_max_fied)) != MAX_WRITE) {
561 return -1;
562 }
563
Daichi Hironobee50c02015-12-14 11:00:54 +0900564 const int result = android::AndroidRuntime::registerNativeMethods(
565 env, "com/android/mtp/AppFuse", gMethods, NELEM(gMethods));
566 if (result < 0) {
567 return -1;
568 }
569
570 return JNI_VERSION_1_4;
571}