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 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
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
register_android_server_storage_AppFuse(JNIEnv * env)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