Home | History | Annotate | Download | only in jni
      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];
     63     FuseRequest() {}
     64     const struct fuse_in_header& header() const {
     65         return *(const struct fuse_in_header*) buffer;
     66     }
     67     void* data() {
     68         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 
     75 template<typename T>
     76 class FuseResponse {
     77    size_t size_;
     78    T* const buffer_;
     79 public:
     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 
     95 class ScopedFd {
     96     int mFd;
     97 
     98 public:
     99     explicit ScopedFd(int fd) : mFd(fd) {}
    100     ~ScopedFd() {
    101         close(mFd);
    102     }
    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:
    120     AppFuse(JNIEnv* env, jobject self) :
    121         env_(env), self_(self), handle_counter_(0) {}
    122 
    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:
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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>
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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