Home | History | Annotate | Download | only in jni
      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 specic language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 // Need to use LOGE_EX.
     18 #define LOG_TAG "AppFuseBridge"
     19 
     20 #include <android_runtime/Log.h>
     21 #include <android-base/logging.h>
     22 #include <android-base/unique_fd.h>
     23 #include <core_jni_helpers.h>
     24 #include <libappfuse/FuseBridgeLoop.h>
     25 #include <libappfuse/FuseBuffer.h>
     26 #include <nativehelper/JNIHelp.h>
     27 
     28 namespace android {
     29 namespace {
     30 
     31 constexpr const char* CLASS_NAME = "com/android/server/storage/AppFuseBridge";
     32 static jclass gAppFuseClass;
     33 static jmethodID gAppFuseOnMount;
     34 static jmethodID gAppFuseOnClosed;
     35 
     36 class Callback : public fuse::FuseBridgeLoopCallback {
     37     JNIEnv* mEnv;
     38     jobject mSelf;
     39 
     40 public:
     41     Callback(JNIEnv* env, jobject self) : mEnv(env), mSelf(self) {}
     42     void OnMount(int mount_id) override {
     43         mEnv->CallVoidMethod(mSelf, gAppFuseOnMount, mount_id);
     44         if (mEnv->ExceptionCheck()) {
     45             LOGE_EX(mEnv, nullptr);
     46             mEnv->ExceptionClear();
     47         }
     48     }
     49 
     50     void OnClosed(int mount_id) override {
     51         mEnv->CallVoidMethod(mSelf, gAppFuseOnClosed, mount_id);
     52         if (mEnv->ExceptionCheck()) {
     53             LOGE_EX(mEnv, nullptr);
     54             mEnv->ExceptionClear();
     55         }
     56     }
     57 };
     58 
     59 class MonitorScope final {
     60 public:
     61     MonitorScope(JNIEnv* env, jobject obj) : mEnv(env), mObj(obj), mLocked(false) {
     62         if (mEnv->MonitorEnter(obj) == JNI_OK) {
     63             mLocked = true;
     64         } else {
     65             LOG(ERROR) << "Failed to enter monitor.";
     66         }
     67     }
     68 
     69     ~MonitorScope() {
     70         if (mLocked) {
     71             if (mEnv->MonitorExit(mObj) != JNI_OK) {
     72                 LOG(ERROR) << "Failed to exit monitor.";
     73             }
     74         }
     75     }
     76 
     77     operator bool() {
     78         return mLocked;
     79     }
     80 
     81 private:
     82     // Lifetime of |MonitorScope| must be shorter than the reference of mObj.
     83     JNIEnv* mEnv;
     84     jobject mObj;
     85     bool mLocked;
     86 
     87     DISALLOW_COPY_AND_ASSIGN(MonitorScope);
     88 };
     89 
     90 jlong com_android_server_storage_AppFuseBridge_new(JNIEnv* env, jobject self) {
     91     return reinterpret_cast<jlong>(new fuse::FuseBridgeLoop());
     92 }
     93 
     94 void com_android_server_storage_AppFuseBridge_delete(JNIEnv* env, jobject self, jlong java_loop) {
     95     fuse::FuseBridgeLoop* const loop = reinterpret_cast<fuse::FuseBridgeLoop*>(java_loop);
     96     CHECK(loop);
     97     delete loop;
     98 }
     99 
    100 void com_android_server_storage_AppFuseBridge_start_loop(
    101         JNIEnv* env, jobject self, jlong java_loop) {
    102     fuse::FuseBridgeLoop* const loop = reinterpret_cast<fuse::FuseBridgeLoop*>(java_loop);
    103     CHECK(loop);
    104     Callback callback(env, self);
    105     loop->Start(&callback);
    106 }
    107 
    108 jint com_android_server_storage_AppFuseBridge_add_bridge(
    109         JNIEnv* env, jobject self, jlong java_loop, jint mountId, jint javaDevFd) {
    110     base::unique_fd devFd(javaDevFd);
    111     fuse::FuseBridgeLoop* const loop = reinterpret_cast<fuse::FuseBridgeLoop*>(java_loop);
    112     CHECK(loop);
    113 
    114     base::unique_fd proxyFd[2];
    115     if (!fuse::SetupMessageSockets(&proxyFd)) {
    116         return -1;
    117     }
    118 
    119     if (!loop->AddBridge(mountId, std::move(devFd), std::move(proxyFd[0]))) {
    120         return -1;
    121     }
    122 
    123     return proxyFd[1].release();
    124 }
    125 
    126 const JNINativeMethod methods[] = {
    127     {
    128         "native_new",
    129         "()J",
    130         reinterpret_cast<void*>(com_android_server_storage_AppFuseBridge_new)
    131     },
    132     {
    133         "native_delete",
    134         "(J)V",
    135         reinterpret_cast<void*>(com_android_server_storage_AppFuseBridge_delete)
    136     },
    137     {
    138         "native_start_loop",
    139         "(J)V",
    140         reinterpret_cast<void*>(com_android_server_storage_AppFuseBridge_start_loop)
    141     },
    142     {
    143         "native_add_bridge",
    144         "(JII)I",
    145         reinterpret_cast<void*>(com_android_server_storage_AppFuseBridge_add_bridge)
    146     }
    147 };
    148 
    149 }  // namespace
    150 
    151 void register_android_server_storage_AppFuse(JNIEnv* env) {
    152     CHECK(env != nullptr);
    153 
    154     gAppFuseClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, CLASS_NAME));
    155     gAppFuseOnMount = GetMethodIDOrDie(env, gAppFuseClass, "onMount", "(I)V");
    156     gAppFuseOnClosed = GetMethodIDOrDie(env, gAppFuseClass, "onClosed", "(I)V");
    157     RegisterMethodsOrDie(env, CLASS_NAME, methods, NELEM(methods));
    158 }
    159 }  // namespace android
    160