blob: c8f842dde7ae55900f701b7bb9395b8a6c2e148d [file] [log] [blame]
/*
* 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