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:
Callback(JNIEnv * env,jobject self)41     Callback(JNIEnv* env, jobject self) : mEnv(env), mSelf(self) {}
OnMount(int mount_id)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 
OnClosed(int mount_id)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:
MonitorScope(JNIEnv * env,jobject obj)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 
~MonitorScope()69     ~MonitorScope() {
70         if (mLocked) {
71             if (mEnv->MonitorExit(mObj) != JNI_OK) {
72                 LOG(ERROR) << "Failed to exit monitor.";
73             }
74         }
75     }
76 
operator bool()77     explicit 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 
com_android_server_storage_AppFuseBridge_new(JNIEnv * env,jobject self)90 jlong com_android_server_storage_AppFuseBridge_new(JNIEnv* env, jobject self) {
91     return reinterpret_cast<jlong>(new fuse::FuseBridgeLoop());
92 }
93 
com_android_server_storage_AppFuseBridge_delete(JNIEnv * env,jobject self,jlong java_loop)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 
com_android_server_storage_AppFuseBridge_start_loop(JNIEnv * env,jobject self,jlong java_loop)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 
com_android_server_storage_AppFuseBridge_add_bridge(JNIEnv * env,jobject self,jlong java_loop,jint mountId,jint javaDevFd)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 
com_android_server_storage_AppFuseBridge_lock(JNIEnv * env,jobject self)126 void com_android_server_storage_AppFuseBridge_lock(JNIEnv* env, jobject self) {
127     fuse::FuseBridgeLoop::Lock();
128 }
129 
com_android_server_storage_AppFuseBridge_unlock(JNIEnv * env,jobject self)130 void com_android_server_storage_AppFuseBridge_unlock(JNIEnv* env, jobject self) {
131     fuse::FuseBridgeLoop::Unlock();
132 }
133 
134 const JNINativeMethod methods[] = {
135     {
136         "native_new",
137         "()J",
138         reinterpret_cast<void*>(com_android_server_storage_AppFuseBridge_new)
139     },
140     {
141         "native_delete",
142         "(J)V",
143         reinterpret_cast<void*>(com_android_server_storage_AppFuseBridge_delete)
144     },
145     {
146         "native_start_loop",
147         "(J)V",
148         reinterpret_cast<void*>(com_android_server_storage_AppFuseBridge_start_loop)
149     },
150     {
151         "native_add_bridge",
152         "(JII)I",
153         reinterpret_cast<void*>(com_android_server_storage_AppFuseBridge_add_bridge)
154     },
155     {
156         "native_lock",
157         "()V",
158         reinterpret_cast<void*>(com_android_server_storage_AppFuseBridge_lock)
159     },
160     {
161         "native_unlock",
162         "()V",
163         reinterpret_cast<void*>(com_android_server_storage_AppFuseBridge_unlock)
164     }
165 };
166 
167 }  // namespace
168 
register_android_server_storage_AppFuse(JNIEnv * env)169 void register_android_server_storage_AppFuse(JNIEnv* env) {
170     CHECK(env != nullptr);
171 
172     gAppFuseClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, CLASS_NAME));
173     gAppFuseOnMount = GetMethodIDOrDie(env, gAppFuseClass, "onMount", "(I)V");
174     gAppFuseOnClosed = GetMethodIDOrDie(env, gAppFuseClass, "onClosed", "(I)V");
175     RegisterMethodsOrDie(env, CLASS_NAME, methods, NELEM(methods));
176 }
177 }  // namespace android
178