| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specic language governing permissions and |
| * limitations under the License. |
| */ |
| |
| // Need to use LOGE_EX. |
| #define LOG_TAG "AppFuseBridge" |
| |
| #include <android_runtime/Log.h> |
| #include <android-base/logging.h> |
| #include <android-base/unique_fd.h> |
| #include <core_jni_helpers.h> |
| #include <libappfuse/FuseBridgeLoop.h> |
| #include <libappfuse/FuseBuffer.h> |
| #include <nativehelper/JNIHelp.h> |
| |
| namespace android { |
| namespace { |
| |
| constexpr const char* CLASS_NAME = "com/android/server/storage/AppFuseBridge"; |
| static jclass gAppFuseClass; |
| static jmethodID gAppFuseOnMount; |
| static jmethodID gAppFuseOnClosed; |
| |
| class Callback : public fuse::FuseBridgeLoopCallback { |
| JNIEnv* mEnv; |
| jobject mSelf; |
| |
| public: |
| Callback(JNIEnv* env, jobject self) : mEnv(env), mSelf(self) {} |
| void OnMount(int mount_id) override { |
| mEnv->CallVoidMethod(mSelf, gAppFuseOnMount, mount_id); |
| if (mEnv->ExceptionCheck()) { |
| LOGE_EX(mEnv, nullptr); |
| mEnv->ExceptionClear(); |
| } |
| } |
| |
| void OnClosed(int mount_id) override { |
| mEnv->CallVoidMethod(mSelf, gAppFuseOnClosed, mount_id); |
| if (mEnv->ExceptionCheck()) { |
| LOGE_EX(mEnv, nullptr); |
| mEnv->ExceptionClear(); |
| } |
| } |
| }; |
| |
| class MonitorScope final { |
| public: |
| MonitorScope(JNIEnv* env, jobject obj) : mEnv(env), mObj(obj), mLocked(false) { |
| if (mEnv->MonitorEnter(obj) == JNI_OK) { |
| mLocked = true; |
| } else { |
| LOG(ERROR) << "Failed to enter monitor."; |
| } |
| } |
| |
| ~MonitorScope() { |
| if (mLocked) { |
| if (mEnv->MonitorExit(mObj) != JNI_OK) { |
| LOG(ERROR) << "Failed to exit monitor."; |
| } |
| } |
| } |
| |
| operator bool() { |
| return mLocked; |
| } |
| |
| private: |
| // Lifetime of |MonitorScope| must be shorter than the reference of mObj. |
| JNIEnv* mEnv; |
| jobject mObj; |
| bool mLocked; |
| |
| DISALLOW_COPY_AND_ASSIGN(MonitorScope); |
| }; |
| |
| jlong com_android_server_storage_AppFuseBridge_new(JNIEnv* env, jobject self) { |
| return reinterpret_cast<jlong>(new fuse::FuseBridgeLoop()); |
| } |
| |
| void com_android_server_storage_AppFuseBridge_delete(JNIEnv* env, jobject self, jlong java_loop) { |
| fuse::FuseBridgeLoop* const loop = reinterpret_cast<fuse::FuseBridgeLoop*>(java_loop); |
| CHECK(loop); |
| delete loop; |
| } |
| |
| void com_android_server_storage_AppFuseBridge_start_loop( |
| JNIEnv* env, jobject self, jlong java_loop) { |
| fuse::FuseBridgeLoop* const loop = reinterpret_cast<fuse::FuseBridgeLoop*>(java_loop); |
| CHECK(loop); |
| Callback callback(env, self); |
| loop->Start(&callback); |
| } |
| |
| jint com_android_server_storage_AppFuseBridge_add_bridge( |
| JNIEnv* env, jobject self, jlong java_loop, jint mountId, jint javaDevFd) { |
| base::unique_fd devFd(javaDevFd); |
| fuse::FuseBridgeLoop* const loop = reinterpret_cast<fuse::FuseBridgeLoop*>(java_loop); |
| CHECK(loop); |
| |
| base::unique_fd proxyFd[2]; |
| if (!fuse::SetupMessageSockets(&proxyFd)) { |
| return -1; |
| } |
| |
| if (!loop->AddBridge(mountId, std::move(devFd), std::move(proxyFd[0]))) { |
| return -1; |
| } |
| |
| return proxyFd[1].release(); |
| } |
| |
| const JNINativeMethod methods[] = { |
| { |
| "native_new", |
| "()J", |
| reinterpret_cast<void*>(com_android_server_storage_AppFuseBridge_new) |
| }, |
| { |
| "native_delete", |
| "(J)V", |
| reinterpret_cast<void*>(com_android_server_storage_AppFuseBridge_delete) |
| }, |
| { |
| "native_start_loop", |
| "(J)V", |
| reinterpret_cast<void*>(com_android_server_storage_AppFuseBridge_start_loop) |
| }, |
| { |
| "native_add_bridge", |
| "(JII)I", |
| reinterpret_cast<void*>(com_android_server_storage_AppFuseBridge_add_bridge) |
| } |
| }; |
| |
| } // namespace |
| |
| void register_android_server_storage_AppFuse(JNIEnv* env) { |
| CHECK(env != nullptr); |
| |
| gAppFuseClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, CLASS_NAME)); |
| gAppFuseOnMount = GetMethodIDOrDie(env, gAppFuseClass, "onMount", "(I)V"); |
| gAppFuseOnClosed = GetMethodIDOrDie(env, gAppFuseClass, "onClosed", "(I)V"); |
| RegisterMethodsOrDie(env, CLASS_NAME, methods, NELEM(methods)); |
| } |
| } // namespace android |