blob: 7a9643013f46b24f3fcffe7b0dccaed1df7b6aa4 [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>
26
27#include <map>
28
29#include "jni.h"
30#include "JNIHelp.h"
31#include "android_runtime/AndroidRuntime.h"
Daichi Hironocc9a7d72015-10-28 09:43:48 +090032#include "nativehelper/ScopedPrimitiveArray.h"
Daichi Hironoaf6b6652016-01-20 19:01:57 +090033#include "nativehelper/ScopedLocalRef.h"
Daichi Hironobee50c02015-12-14 11:00:54 +090034
35namespace {
36
Daichi Hirono2153e8222016-01-11 17:43:55 +090037// The numbers came from sdcard.c.
38// Maximum number of bytes to write/read in one request/one reply.
Daichi Hironobee50c02015-12-14 11:00:54 +090039constexpr size_t MAX_WRITE = 256 * 1024;
Daichi Hirono2153e8222016-01-11 17:43:55 +090040constexpr size_t MAX_READ = 128 * 1024;
41
Daichi Hironocc9a7d72015-10-28 09:43:48 +090042constexpr size_t NUM_MAX_HANDLES = 1024;
Daichi Hironobee50c02015-12-14 11:00:54 +090043
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.
47constexpr size_t MAX_REQUEST_SIZE = sizeof(struct fuse_in_header) +
Daichi Hironofab4a972016-01-15 16:54:24 +090048 sizeof(struct fuse_write_in) + (MAX_WRITE > MAX_READ ? MAX_WRITE : MAX_READ);
Daichi Hironobee50c02015-12-14 11:00:54 +090049
50static jclass app_fuse_class;
Daichi Hironocc9a7d72015-10-28 09:43:48 +090051static jmethodID app_fuse_get_file_size;
Daichi Hirono2f310f62016-01-27 12:34:29 +090052static jmethodID app_fuse_read_object_bytes;
Daichi Hirono09ece6c2016-01-20 19:09:25 +090053static jmethodID app_fuse_write_object_bytes;
Daichi Hironof4e7fa82016-03-28 16:07:45 +090054static jmethodID app_fuse_flush_file_handle;
55static jmethodID app_fuse_close_file_handle;
Daichi Hirono2f310f62016-01-27 12:34:29 +090056static jfieldID app_fuse_buffer;
Daichi Hironobee50c02015-12-14 11:00:54 +090057
Daichi Hirono2153e8222016-01-11 17:43:55 +090058// 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.
Daichi Hironobee50c02015-12-14 11:00:54 +090061struct FuseRequest {
62 char buffer[MAX_REQUEST_SIZE];
63 FuseRequest() {}
64 const struct fuse_in_header& header() const {
65 return *(const struct fuse_in_header*) buffer;
66 }
Daichi Hirono2153e8222016-01-11 17:43:55 +090067 void* data() {
Daichi Hironobee50c02015-12-14 11:00:54 +090068 return (buffer + sizeof(struct fuse_in_header));
69 }
70 size_t data_length() const {
71 return header().len - sizeof(struct fuse_in_header);
72 }
73};
74
Daichi Hirono2153e8222016-01-11 17:43:55 +090075template<typename T>
76class FuseResponse {
77 size_t size_;
78 T* const buffer_;
79public:
80 FuseResponse(void* buffer) : size_(0), buffer_(static_cast<T*>(buffer)) {}
81
82 void prepare_buffer(size_t size = sizeof(T)) {
83 memset(buffer_, 0, size);
84 size_ = size;
85 }
86
87 void set_size(size_t size) {
88 size_ = size;
89 }
90
91 size_t size() const { return size_; }
92 T* data() const { return buffer_; }
93};
94
Daichi Hirono91e3b502015-12-16 09:24:16 +090095class ScopedFd {
96 int mFd;
97
98public:
99 explicit ScopedFd(int fd) : mFd(fd) {}
100 ~ScopedFd() {
101 close(mFd);
102 }
103 operator int() {
104 return mFd;
105 }
106};
107
Daichi Hironobee50c02015-12-14 11:00:54 +0900108/**
Daichi Hirono2153e8222016-01-11 17:43:55 +0900109 * Fuse implementation consists of handlers parsing FUSE commands.
Daichi Hironobee50c02015-12-14 11:00:54 +0900110 */
111class AppFuse {
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900112 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
Daichi Hironobee50c02015-12-14 11:00:54 +0900119public:
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900120 AppFuse(JNIEnv* env, jobject self) :
121 env_(env), self_(self), handle_counter_(0) {}
Daichi Hironobee50c02015-12-14 11:00:54 +0900122
Daichi Hirono07f48ad2016-05-02 12:48:43 +0900123 void handle_fuse_request(int fd, FuseRequest* req) {
Daichi Hirono2153e8222016-01-11 17:43:55 +0900124 ALOGV("Request op=%d", req->header().opcode);
125 switch (req->header().opcode) {
Daichi Hironobee50c02015-12-14 11:00:54 +0900126 // TODO: Handle more operations that are enough to provide seekable
127 // FD.
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900128 case FUSE_LOOKUP:
129 invoke_handler(fd, req, &AppFuse::handle_fuse_lookup);
Daichi Hirono07f48ad2016-05-02 12:48:43 +0900130 return;
131 case FUSE_FORGET:
132 // Return without replying.
133 return;
Daichi Hironobee50c02015-12-14 11:00:54 +0900134 case FUSE_INIT:
135 invoke_handler(fd, req, &AppFuse::handle_fuse_init);
Daichi Hirono07f48ad2016-05-02 12:48:43 +0900136 return;
Daichi Hironobee50c02015-12-14 11:00:54 +0900137 case FUSE_GETATTR:
138 invoke_handler(fd, req, &AppFuse::handle_fuse_getattr);
Daichi Hirono07f48ad2016-05-02 12:48:43 +0900139 return;
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900140 case FUSE_OPEN:
141 invoke_handler(fd, req, &AppFuse::handle_fuse_open);
Daichi Hirono07f48ad2016-05-02 12:48:43 +0900142 return;
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900143 case FUSE_READ:
Daichi Hirono2153e8222016-01-11 17:43:55 +0900144 invoke_handler(fd, req, &AppFuse::handle_fuse_read);
Daichi Hirono07f48ad2016-05-02 12:48:43 +0900145 return;
Daichi Hirono09ece6c2016-01-20 19:09:25 +0900146 case FUSE_WRITE:
147 invoke_handler(fd, req, &AppFuse::handle_fuse_write);
Daichi Hirono07f48ad2016-05-02 12:48:43 +0900148 return;
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900149 case FUSE_RELEASE:
Daichi Hirono2153e8222016-01-11 17:43:55 +0900150 invoke_handler(fd, req, &AppFuse::handle_fuse_release);
Daichi Hirono07f48ad2016-05-02 12:48:43 +0900151 return;
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900152 case FUSE_FLUSH:
Daichi Hirono2153e8222016-01-11 17:43:55 +0900153 invoke_handler(fd, req, &AppFuse::handle_fuse_flush);
Daichi Hirono07f48ad2016-05-02 12:48:43 +0900154 return;
Daichi Hironobee50c02015-12-14 11:00:54 +0900155 default: {
156 ALOGV("NOTIMPL op=%d uniq=%" PRIx64 " nid=%" PRIx64 "\n",
Daichi Hirono2153e8222016-01-11 17:43:55 +0900157 req->header().opcode,
158 req->header().unique,
159 req->header().nodeid);
160 fuse_reply(fd, req->header().unique, -ENOSYS, NULL, 0);
Daichi Hirono07f48ad2016-05-02 12:48:43 +0900161 return;
Daichi Hironobee50c02015-12-14 11:00:54 +0900162 }
163 }
164 }
165
166private:
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900167 int handle_fuse_lookup(const fuse_in_header& header,
168 const char* name,
Daichi Hirono2153e8222016-01-11 17:43:55 +0900169 FuseResponse<fuse_entry_out>* out) {
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900170 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
Daichi Hirono2153e8222016-01-11 17:43:55 +0900184 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;
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900191 return 0;
192 }
193
Daichi Hironobee50c02015-12-14 11:00:54 +0900194 int handle_fuse_init(const fuse_in_header&,
195 const fuse_init_in* in,
Daichi Hirono2153e8222016-01-11 17:43:55 +0900196 FuseResponse<fuse_init_out>* out) {
Daichi Hironobee50c02015-12-14 11:00:54 +0900197 // 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
Daichi Hirono2153e8222016-01-11 17:43:55 +0900208 // 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
Daichi Hironobee50c02015-12-14 11:00:54 +0900212 // We limit ourselves to 15 because we don't handle BATCH_FORGET yet
Daichi Hirono2153e8222016-01-11 17:43:55 +0900213 size_t response_size = sizeof(fuse_init_out);
Daichi Hironobee50c02015-12-14 11:00:54 +0900214#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.
Daichi Hirono2153e8222016-01-11 17:43:55 +0900220 if (minor <= 22) {
221 response_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
Daichi Hironobee50c02015-12-14 11:00:54 +0900222 }
Daichi Hironobee50c02015-12-14 11:00:54 +0900223#endif
Daichi Hirono2153e8222016-01-11 17:43:55 +0900224 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;
Daichi Hironobee50c02015-12-14 11:00:54 +0900232
233 return 0;
234 }
235
236 int handle_fuse_getattr(const fuse_in_header& header,
237 const fuse_getattr_in* /* in */,
Daichi Hirono2153e8222016-01-11 17:43:55 +0900238 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;
Daichi Hironobee50c02015-12-14 11:00:54 +0900252 }
Daichi Hirono2153e8222016-01-11 17:43:55 +0900253
Daichi Hironobee50c02015-12-14 11:00:54 +0900254 return 0;
255 }
256
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900257 int handle_fuse_open(const fuse_in_header& header,
258 const fuse_open_in* /* in */,
Daichi Hirono2153e8222016-01-11 17:43:55 +0900259 FuseResponse<fuse_open_out>* out) {
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900260 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);
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900268 handles_.insert(std::make_pair(handle, header.nodeid));
Daichi Hirono2153e8222016-01-11 17:43:55 +0900269
270 out->prepare_buffer();
271 out->data()->fh = handle;
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900272 return 0;
273 }
274
275 int handle_fuse_read(const fuse_in_header& /* header */,
276 const fuse_read_in* in,
Daichi Hirono2153e8222016-01-11 17:43:55 +0900277 FuseResponse<void>* out) {
278 if (in->size > MAX_READ) {
279 return -EINVAL;
280 }
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900281 const std::map<uint32_t, uint64_t>::iterator it = handles_.find(in->fh);
282 if (it == handles_.end()) {
283 return -EBADF;
284 }
Daichi Hirono2153e8222016-01-11 17:43:55 +0900285 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());
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900291 if (result < 0) {
Daichi Hirono2f310f62016-01-27 12:34:29 +0900292 return result;
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900293 }
Daichi Hirono2153e8222016-01-11 17:43:55 +0900294 out->set_size(result);
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900295 return 0;
296 }
297
Daichi Hirono09ece6c2016-01-20 19:09:25 +0900298 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;
Daichi Hironof4e7fa82016-03-28 16:07:45 +0900312 const int result = write_object_bytes(
313 in->fh, it->second, offset, size, buffer, &written_size);
Daichi Hirono09ece6c2016-01-20 19:09:25 +0900314 if (result < 0) {
315 return result;
316 }
317 out->prepare_buffer();
318 out->data()->size = written_size;
319 return 0;
320 }
321
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900322 int handle_fuse_release(const fuse_in_header& /* header */,
323 const fuse_release_in* in,
Daichi Hirono2153e8222016-01-11 17:43:55 +0900324 FuseResponse<void>* /* out */) {
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900325 handles_.erase(in->fh);
Daichi Hironof4e7fa82016-03-28 16:07:45 +0900326 return env_->CallIntMethod(self_, app_fuse_close_file_handle, file_handle_to_jlong(in->fh));
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900327 }
328
329 int handle_fuse_flush(const fuse_in_header& /* header */,
Daichi Hironof4e7fa82016-03-28 16:07:45 +0900330 const fuse_flush_in* in,
Daichi Hirono2153e8222016-01-11 17:43:55 +0900331 FuseResponse<void>* /* out */) {
Daichi Hironof4e7fa82016-03-28 16:07:45 +0900332 return env_->CallIntMethod(self_, app_fuse_flush_file_handle, file_handle_to_jlong(in->fh));
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900333 }
334
Daichi Hironobee50c02015-12-14 11:00:54 +0900335 template <typename T, typename S>
336 void invoke_handler(int fd,
Daichi Hirono2153e8222016-01-11 17:43:55 +0900337 FuseRequest* request,
Daichi Hironobee50c02015-12-14 11:00:54 +0900338 int (AppFuse::*handler)(const fuse_in_header&,
339 const T*,
Daichi Hirono2153e8222016-01-11 17:43:55 +0900340 FuseResponse<S>*)) {
341 FuseResponse<S> response(request->data());
Daichi Hironobee50c02015-12-14 11:00:54 +0900342 const int reply_code = (this->*handler)(
Daichi Hirono2153e8222016-01-11 17:43:55 +0900343 request->header(),
344 static_cast<const T*>(request->data()),
345 &response);
Daichi Hironobee50c02015-12-14 11:00:54 +0900346 fuse_reply(
347 fd,
Daichi Hirono2153e8222016-01-11 17:43:55 +0900348 request->header().unique,
Daichi Hironobee50c02015-12-14 11:00:54 +0900349 reply_code,
Daichi Hirono2153e8222016-01-11 17:43:55 +0900350 request->data(),
351 response.size());
Daichi Hironobee50c02015-12-14 11:00:54 +0900352 }
353
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900354 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
361 int64_t get_object_bytes(
362 int inode,
363 uint64_t offset,
364 uint32_t size,
365 void* buf) {
Daichi Hirono2f310f62016-01-27 12:34:29 +0900366 const jlong read_size = env_->CallLongMethod(
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900367 self_,
Daichi Hirono2f310f62016-01-27 12:34:29 +0900368 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)));
Daichi Hironoaf6b6652016-01-20 19:01:57 +0900377 if (array.get() == nullptr) {
Daichi Hirono2f310f62016-01-27 12:34:29 +0900378 return -EFAULT;
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900379 }
Daichi Hironoaf6b6652016-01-20 19:01:57 +0900380 ScopedByteArrayRO bytes(env_, array.get());
Daichi Hironob36b1552016-01-25 14:26:14 +0900381 if (bytes.get() == nullptr) {
Daichi Hirono2f310f62016-01-27 12:34:29 +0900382 return -ENOMEM;
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900383 }
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900384 memcpy(buf, bytes.get(), read_size);
385 return read_size;
386 }
387
Daichi Hironof4e7fa82016-03-28 16:07:45 +0900388 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");
Daichi Hirono09ece6c2016-01-20 19:09:25 +0900392 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 }
Daichi Hironof4e7fa82016-03-28 16:07:45 +0900402 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;
Daichi Hirono09ece6c2016-01-20 19:09:25 +0900412 }
Daichi Hironof4e7fa82016-03-28 16:07:45 +0900413 *written_size = result;
Daichi Hirono09ece6c2016-01-20 19:09:25 +0900414 return 0;
415 }
416
Daichi Hironof4e7fa82016-03-28 16:07:45 +0900417 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
Daichi Hironobee50c02015-12-14 11:00:54 +0900424 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
Daichi Hirono07f48ad2016-05-02 12:48:43 +0900449void com_android_mtp_AppFuse_start_app_fuse_loop(JNIEnv* env, jobject self, jint jfd) {
Daichi Hironoe6054c02016-01-20 15:36:04 +0900450 ScopedFd fd(static_cast<int>(jfd));
Daichi Hironobee50c02015-12-14 11:00:54 +0900451 AppFuse appfuse(env, self);
452
Daichi Hironod0ef1392016-04-08 10:07:01 +0900453 ALOGV("Start fuse loop.");
Daichi Hironobee50c02015-12-14 11:00:54 +0900454 while (true) {
455 FuseRequest request;
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900456
Daichi Hironobee50c02015-12-14 11:00:54 +0900457 const ssize_t result = TEMP_FAILURE_RETRY(
458 read(fd, request.buffer, sizeof(request.buffer)));
459 if (result < 0) {
460 if (errno == ENODEV) {
Daichi Hirono07f48ad2016-05-02 12:48:43 +0900461 ALOGV("AppFuse was unmounted.\n");
462 return;
Daichi Hironobee50c02015-12-14 11:00:54 +0900463 }
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
Daichi Hirono07f48ad2016-05-02 12:48:43 +0900480 appfuse.handle_fuse_request(fd, &request);
Daichi Hironobee50c02015-12-14 11:00:54 +0900481 }
482}
483
484static const JNINativeMethod gMethods[] = {
485 {
486 "native_start_app_fuse_loop",
Daichi Hirono07f48ad2016-05-02 12:48:43 +0900487 "(I)V",
Daichi Hironobee50c02015-12-14 11:00:54 +0900488 (void *) com_android_mtp_AppFuse_start_app_fuse_loop
489 }
490};
491
492}
493
494jint 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 }
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900508
Daichi Hironobee50c02015-12-14 11:00:54 +0900509 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
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900515 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
Daichi Hirono2f310f62016-01-27 12:34:29 +0900522 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
Daichi Hironof4e7fa82016-03-28 16:07:45 +0900529 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");
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900532 return -1;
533 }
534
Daichi Hironof4e7fa82016-03-28 16:07:45 +0900535 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");
Daichi Hirono09ece6c2016-01-20 19:09:25 +0900544 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
Daichi Hironobee50c02015-12-14 11:00:54 +0900563 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}