com_android_internal_os_FuseAppLoop.cpp revision 9fb00183a04036a58ee208f5bfd6c9768982f0aa
1/* 2 * Copyright (C) 2016 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 specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#define LOG_TAG "FuseAppLoopJNI" 18#define LOG_NDEBUG 0 19 20#include <stdlib.h> 21#include <sys/stat.h> 22 23#include <android_runtime/Log.h> 24#include <android-base/logging.h> 25#include <android-base/unique_fd.h> 26#include <jni.h> 27#include <libappfuse/FuseAppLoop.h> 28#include <nativehelper/ScopedLocalRef.h> 29 30#include "core_jni_helpers.h" 31 32namespace android { 33 34namespace { 35 36constexpr const char* CLASS_NAME = "com/android/internal/os/FuseAppLoop"; 37 38jclass gFuseAppLoopClass; 39jmethodID gOnGetSizeMethod; 40jmethodID gOnOpenMethod; 41jmethodID gOnFsyncMethod; 42jmethodID gOnReleaseMethod; 43jmethodID gOnReadMethod; 44jmethodID gOnWriteMethod; 45 46class Callback : public fuse::FuseAppLoopCallback { 47private: 48 static constexpr size_t kBufferSize = std::max(fuse::kFuseMaxWrite, fuse::kFuseMaxRead); 49 static_assert(kBufferSize <= INT32_MAX, "kBufferSize should be fit in int32_t."); 50 51 JNIEnv* const mEnv; 52 jobject const mSelf; 53 ScopedLocalRef<jbyteArray> mJniBuffer; 54 55 template <typename T> 56 T checkException(T result) const { 57 if (mEnv->ExceptionCheck()) { 58 LOGE_EX(mEnv, nullptr); 59 mEnv->ExceptionClear(); 60 return -EIO; 61 } 62 return result; 63 } 64 65public: 66 Callback(JNIEnv* env, jobject self) : 67 mEnv(env), 68 mSelf(self), 69 mJniBuffer(env, nullptr) {} 70 71 bool Init() { 72 mJniBuffer.reset(mEnv->NewByteArray(kBufferSize)); 73 return mJniBuffer.get(); 74 } 75 76 bool IsActive() override { 77 return true; 78 } 79 80 int64_t OnGetSize(uint64_t inode) override { 81 return checkException(mEnv->CallLongMethod(mSelf, gOnGetSizeMethod, inode)); 82 } 83 84 int32_t OnOpen(uint64_t inode) override { 85 return checkException(mEnv->CallIntMethod(mSelf, gOnOpenMethod, inode)); 86 } 87 88 int32_t OnFsync(uint64_t inode) override { 89 return checkException(mEnv->CallIntMethod(mSelf, gOnFsyncMethod, inode)); 90 } 91 92 int32_t OnRelease(uint64_t inode) override { 93 return checkException(mEnv->CallIntMethod(mSelf, gOnReleaseMethod, inode)); 94 } 95 96 int32_t OnRead(uint64_t inode, uint64_t offset, uint32_t size, void* buffer) override { 97 CHECK_LE(size, static_cast<uint32_t>(kBufferSize)); 98 const int32_t result = checkException(mEnv->CallIntMethod( 99 mSelf, gOnReadMethod, inode, offset, size, mJniBuffer.get())); 100 if (result <= 0) { 101 return result; 102 } 103 if (result > static_cast<int32_t>(size)) { 104 LOG(ERROR) << "Returned size is too large."; 105 return -EIO; 106 } 107 108 mEnv->GetByteArrayRegion(mJniBuffer.get(), 0, result, static_cast<jbyte*>(buffer)); 109 CHECK(!mEnv->ExceptionCheck()); 110 111 return checkException(result); 112 } 113 114 int32_t OnWrite(uint64_t inode, uint64_t offset, uint32_t size, const void* buffer) override { 115 CHECK_LE(size, static_cast<uint32_t>(kBufferSize)); 116 117 mEnv->SetByteArrayRegion(mJniBuffer.get(), 0, size, static_cast<const jbyte*>(buffer)); 118 CHECK(!mEnv->ExceptionCheck()); 119 120 return checkException(mEnv->CallIntMethod( 121 mSelf, gOnWriteMethod, inode, offset, size, mJniBuffer.get())); 122 } 123}; 124 125jboolean com_android_internal_os_FuseAppLoop_start_loop(JNIEnv* env, jobject self, jint jfd) { 126 base::unique_fd fd(jfd); 127 Callback callback(env, self); 128 129 if (!callback.Init()) { 130 LOG(ERROR) << "Failed to init callback"; 131 return JNI_FALSE; 132 } 133 134 return fuse::StartFuseAppLoop(fd.release(), &callback); 135} 136 137const JNINativeMethod methods[] = { 138 { 139 "native_start_loop", 140 "(I)Z", 141 (void *) com_android_internal_os_FuseAppLoop_start_loop 142 } 143}; 144 145} // namespace 146 147int register_com_android_internal_os_FuseAppLoop(JNIEnv* env) { 148 gFuseAppLoopClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, CLASS_NAME)); 149 gOnGetSizeMethod = GetMethodIDOrDie(env, gFuseAppLoopClass, "onGetSize", "(J)J"); 150 gOnOpenMethod = GetMethodIDOrDie(env, gFuseAppLoopClass, "onOpen", "(J)I"); 151 gOnFsyncMethod = GetMethodIDOrDie(env, gFuseAppLoopClass, "onFsync", "(J)I"); 152 gOnReleaseMethod = GetMethodIDOrDie(env, gFuseAppLoopClass, "onRelease", "(J)I"); 153 gOnReadMethod = GetMethodIDOrDie(env, gFuseAppLoopClass, "onRead", "(JJI[B)I"); 154 gOnWriteMethod = GetMethodIDOrDie(env, gFuseAppLoopClass, "onWrite", "(JJI[B)I"); 155 RegisterMethodsOrDie(env, CLASS_NAME, methods, NELEM(methods)); 156 return 0; 157} 158 159} // namespace android 160