blob: eb960153799683fece02b0e8a7b251844dec25eb [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
17#define LOG_NDEBUG 0
18#define LOG_TAG "AppFuseJNI"
19#include "utils/Log.h"
20
21#include <assert.h>
22#include <dirent.h>
23#include <inttypes.h>
24
25#include <linux/fuse.h>
26#include <sys/stat.h>
27
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 Hirono2153e8222016-01-11 17:43:55 +0900124 bool handle_fuse_request(int fd, FuseRequest* req) {
125 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);
131 return true;
Daichi Hironobee50c02015-12-14 11:00:54 +0900132 case FUSE_INIT:
133 invoke_handler(fd, req, &AppFuse::handle_fuse_init);
Daichi Hirono91e3b502015-12-16 09:24:16 +0900134 return true;
Daichi Hironobee50c02015-12-14 11:00:54 +0900135 case FUSE_GETATTR:
136 invoke_handler(fd, req, &AppFuse::handle_fuse_getattr);
Daichi Hirono91e3b502015-12-16 09:24:16 +0900137 return true;
138 case FUSE_FORGET:
139 return false;
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900140 case FUSE_OPEN:
141 invoke_handler(fd, req, &AppFuse::handle_fuse_open);
142 return true;
143 case FUSE_READ:
Daichi Hirono2153e8222016-01-11 17:43:55 +0900144 invoke_handler(fd, req, &AppFuse::handle_fuse_read);
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900145 return true;
Daichi Hirono09ece6c2016-01-20 19:09:25 +0900146 case FUSE_WRITE:
147 invoke_handler(fd, req, &AppFuse::handle_fuse_write);
148 return true;
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 Hironocc9a7d72015-10-28 09:43:48 +0900151 return true;
152 case FUSE_FLUSH:
Daichi Hirono2153e8222016-01-11 17:43:55 +0900153 invoke_handler(fd, req, &AppFuse::handle_fuse_flush);
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900154 return true;
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 Hirono91e3b502015-12-16 09:24:16 +0900161 return true;
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
449jboolean com_android_mtp_AppFuse_start_app_fuse_loop(
450 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
454 ALOGD("Start fuse loop.");
455 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) {
462 ALOGE("Someone stole our marbles!\n");
Daichi Hirono91e3b502015-12-16 09:24:16 +0900463 return JNI_FALSE;
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 Hirono2153e8222016-01-11 17:43:55 +0900481 if (!appfuse.handle_fuse_request(fd, &request)) {
Daichi Hirono91e3b502015-12-16 09:24:16 +0900482 return JNI_TRUE;
483 }
Daichi Hironobee50c02015-12-14 11:00:54 +0900484 }
485}
486
487static const JNINativeMethod gMethods[] = {
488 {
489 "native_start_app_fuse_loop",
490 "(I)Z",
491 (void *) com_android_mtp_AppFuse_start_app_fuse_loop
492 }
493};
494
495}
496
497jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) {
498 JNIEnv* env = nullptr;
499 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
500 ALOGE("ERROR: GetEnv failed\n");
501 return -1;
502
503 }
504 assert(env != nullptr);
505
506 jclass clazz = env->FindClass("com/android/mtp/AppFuse");
507 if (clazz == nullptr) {
508 ALOGE("Can't find com/android/mtp/AppFuse");
509 return -1;
510 }
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900511
Daichi Hironobee50c02015-12-14 11:00:54 +0900512 app_fuse_class = static_cast<jclass>(env->NewGlobalRef(clazz));
513 if (app_fuse_class == nullptr) {
514 ALOGE("Can't obtain global reference for com/android/mtp/AppFuse");
515 return -1;
516 }
517
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900518 app_fuse_get_file_size = env->GetMethodID(
519 app_fuse_class, "getFileSize", "(I)J");
520 if (app_fuse_get_file_size == nullptr) {
521 ALOGE("Can't find getFileSize");
522 return -1;
523 }
524
Daichi Hirono2f310f62016-01-27 12:34:29 +0900525 app_fuse_read_object_bytes = env->GetMethodID(
526 app_fuse_class, "readObjectBytes", "(IJJ)J");
527 if (app_fuse_read_object_bytes == nullptr) {
528 ALOGE("Can't find readObjectBytes");
529 return -1;
530 }
531
Daichi Hironof4e7fa82016-03-28 16:07:45 +0900532 app_fuse_write_object_bytes = env->GetMethodID(app_fuse_class, "writeObjectBytes", "(JIJI[B)I");
533 if (app_fuse_write_object_bytes == nullptr) {
534 ALOGE("Can't find writeObjectBytes");
Daichi Hironocc9a7d72015-10-28 09:43:48 +0900535 return -1;
536 }
537
Daichi Hironof4e7fa82016-03-28 16:07:45 +0900538 app_fuse_flush_file_handle = env->GetMethodID(app_fuse_class, "flushFileHandle", "(J)I");
539 if (app_fuse_flush_file_handle == nullptr) {
540 ALOGE("Can't find flushFileHandle");
541 return -1;
542 }
543
544 app_fuse_close_file_handle = env->GetMethodID(app_fuse_class, "closeFileHandle", "(J)I");
545 if (app_fuse_close_file_handle == nullptr) {
546 ALOGE("Can't find closeFileHandle");
Daichi Hirono09ece6c2016-01-20 19:09:25 +0900547 return -1;
548 }
549
550 app_fuse_buffer = env->GetFieldID(app_fuse_class, "mBuffer", "[B");
551 if (app_fuse_buffer == nullptr) {
552 ALOGE("Can't find mBuffer");
553 return -1;
554 }
555
556 const jfieldID read_max_fied = env->GetStaticFieldID(app_fuse_class, "MAX_READ", "I");
557 if (static_cast<int>(env->GetStaticIntField(app_fuse_class, read_max_fied)) != MAX_READ) {
558 return -1;
559 }
560
561 const jfieldID write_max_fied = env->GetStaticFieldID(app_fuse_class, "MAX_WRITE", "I");
562 if (static_cast<int>(env->GetStaticIntField(app_fuse_class, write_max_fied)) != MAX_WRITE) {
563 return -1;
564 }
565
Daichi Hironobee50c02015-12-14 11:00:54 +0900566 const int result = android::AndroidRuntime::registerNativeMethods(
567 env, "com/android/mtp/AppFuse", gMethods, NELEM(gMethods));
568 if (result < 0) {
569 return -1;
570 }
571
572 return JNI_VERSION_1_4;
573}