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