Add AppFuseBridge class to the system service.
Bug: 29970149
Test: None
Change-Id: I1d40d8e3aec1c57a31d5ae66b33305990dc86b67
diff --git a/core/java/com/android/internal/os/AppFuseMount.java b/core/java/com/android/internal/os/AppFuseMount.java
new file mode 100644
index 0000000..b392186
--- /dev/null
+++ b/core/java/com/android/internal/os/AppFuseMount.java
@@ -0,0 +1,56 @@
+/*
+ * 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 specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
+import java.io.File;
+
+public class AppFuseMount implements Parcelable {
+ final public File mountPoint;
+ final public ParcelFileDescriptor fd;
+
+ public AppFuseMount(File mountPoint, ParcelFileDescriptor fd) {
+ this.mountPoint = mountPoint;
+ this.fd = fd;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(this.mountPoint.getPath());
+ dest.writeParcelable(fd, flags);
+ }
+
+ public static final Parcelable.Creator<AppFuseMount> CREATOR =
+ new Parcelable.Creator<AppFuseMount>() {
+ @Override
+ public AppFuseMount createFromParcel(Parcel in) {
+ return new AppFuseMount(new File(in.readString()), in.readParcelable(null));
+ }
+
+ @Override
+ public AppFuseMount[] newArray(int size) {
+ return new AppFuseMount[size];
+ }
+ };
+}
diff --git a/services/core/java/com/android/server/storage/AppFuseBridge.java b/services/core/java/com/android/server/storage/AppFuseBridge.java
new file mode 100644
index 0000000..23be9a3
--- /dev/null
+++ b/services/core/java/com/android/server/storage/AppFuseBridge.java
@@ -0,0 +1,95 @@
+/*
+ * 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 specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.storage;
+
+import android.annotation.CallSuper;
+import android.annotation.WorkerThread;
+import android.os.Handler;
+import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+import android.util.Log;
+import com.android.internal.os.AppFuseMount;
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+
+public class AppFuseBridge implements Runnable {
+ private static final String TAG = AppFuseBridge.class.getSimpleName();
+
+ private final FileDescriptor mDeviceFd;
+ private final FileDescriptor mProxyFd;
+ private final CountDownLatch mMountLatch = new CountDownLatch(1);
+
+ /**
+ * @param deviceFd FD of /dev/fuse. Ownership of fd is taken by AppFuseBridge.
+ * @param proxyFd FD of socket pair. Ownership of fd is taken by AppFuseBridge.
+ */
+ private AppFuseBridge(FileDescriptor deviceFd, FileDescriptor proxyFd) {
+ mDeviceFd = deviceFd;
+ mProxyFd = proxyFd;
+ }
+
+ public static AppFuseMount startMessageLoop(
+ int uid,
+ String name,
+ FileDescriptor deviceFd,
+ Handler handler,
+ ParcelFileDescriptor.OnCloseListener listener)
+ throws IOException, ErrnoException, InterruptedException {
+ final FileDescriptor localFd = new FileDescriptor();
+ final FileDescriptor remoteFd = new FileDescriptor();
+ // Needs to specify OsConstants.SOCK_SEQPACKET to keep message boundaries.
+ Os.socketpair(OsConstants.AF_UNIX, OsConstants.SOCK_SEQPACKET, 0, remoteFd, localFd);
+
+ // Caller must invoke #start() after instantiate AppFuseBridge.
+ // Otherwise FDs will be leaked.
+ final AppFuseBridge bridge = new AppFuseBridge(deviceFd, localFd);
+ final Thread thread = new Thread(bridge, TAG);
+ thread.start();
+ try {
+ bridge.mMountLatch.await();
+ } catch (InterruptedException error) {
+ throw error;
+ }
+ return new AppFuseMount(
+ new File("/mnt/appfuse/" + uid + "_" + name),
+ ParcelFileDescriptor.fromFd(remoteFd, handler, listener));
+ }
+
+ @Override
+ public void run() {
+ // deviceFd and proxyFd must be closed in native_start_loop.
+ final int deviceFd = mDeviceFd.getInt$();
+ final int proxyFd = mProxyFd.getInt$();
+ mDeviceFd.setInt$(-1);
+ mProxyFd.setInt$(-1);
+ native_start_loop(deviceFd, proxyFd);
+ }
+
+ // Used by com_android_server_storage_AppFuse.cpp.
+ private void onMount() {
+ mMountLatch.countDown();
+ }
+
+ private native boolean native_start_loop(int deviceFd, int proxyFd);
+}
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 2c46413..17b143c 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -19,6 +19,7 @@
$(LOCAL_REL_DIR)/com_android_server_location_FlpHardwareProvider.cpp \
$(LOCAL_REL_DIR)/com_android_server_power_PowerManagerService.cpp \
$(LOCAL_REL_DIR)/com_android_server_SerialService.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_storage_AppFuseBridge.cpp \
$(LOCAL_REL_DIR)/com_android_server_SystemServer.cpp \
$(LOCAL_REL_DIR)/com_android_server_tv_TvUinputBridge.cpp \
$(LOCAL_REL_DIR)/com_android_server_tv_TvInputHal.cpp \
@@ -37,6 +38,7 @@
frameworks/base/libs/hwui \
frameworks/base/core/jni \
frameworks/native/services \
+ system/core/libappfuse/include \
system/security/keystore/include \
$(call include-path-for, libhardware)/hardware \
$(call include-path-for, libhardware_legacy)/hardware_legacy \
@@ -44,6 +46,7 @@
LOCAL_SHARED_LIBRARIES += \
libandroid_runtime \
libandroidfw \
+ libappfuse \
libbinder \
libcutils \
liblog \
diff --git a/services/core/jni/com_android_server_storage_AppFuseBridge.cpp b/services/core/jni/com_android_server_storage_AppFuseBridge.cpp
new file mode 100644
index 0000000..640fd0e
--- /dev/null
+++ b/services/core/jni/com_android_server_storage_AppFuseBridge.cpp
@@ -0,0 +1,72 @@
+/*
+ * 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 <core_jni_helpers.h>
+#include <libappfuse/FuseBridgeLoop.h>
+#include <nativehelper/JNIHelp.h>
+
+namespace android {
+namespace {
+
+constexpr const char* CLASS_NAME = "com/android/server/storage/AppFuseBridge";
+static jclass appFuseClass;
+static jmethodID appFuseOnMount;
+
+class Callback : public FuseBridgeLoop::Callback {
+ JNIEnv* mEnv;
+ jobject mSelf;
+
+public:
+ Callback(JNIEnv* env, jobject self) : mEnv(env), mSelf(self) {}
+ void OnMount() override {
+ mEnv->CallVoidMethod(mSelf, appFuseOnMount);
+ if (mEnv->ExceptionCheck()) {
+ LOGE_EX(mEnv, nullptr);
+ mEnv->ExceptionClear();
+ }
+ }
+};
+
+jboolean com_android_server_storage_AppFuseBridge_start_loop(
+ JNIEnv* env, jobject self, jint devJavaFd, jint proxyJavaFd) {
+ FuseBridgeLoop loop;
+ Callback callback(env, self);
+ return loop.Start(devJavaFd, proxyJavaFd, &callback);
+}
+
+const JNINativeMethod methods[] = {
+ {
+ "native_start_loop",
+ "(II)Z",
+ (void *) com_android_server_storage_AppFuseBridge_start_loop
+ }
+};
+
+} // namespace
+
+void register_android_server_storage_AppFuse(JNIEnv* env) {
+ CHECK(env != nullptr);
+
+ appFuseClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, CLASS_NAME));
+ appFuseOnMount = GetMethodIDOrDie(env, appFuseClass, "onMount", "()V");
+ RegisterMethodsOrDie(env, CLASS_NAME, methods, NELEM(methods));
+}
+} // namespace android
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index d69c37f..c291ba0 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -28,6 +28,7 @@
int register_android_server_InputManager(JNIEnv* env);
int register_android_server_LightsService(JNIEnv* env);
int register_android_server_PowerManagerService(JNIEnv* env);
+int register_android_server_storage_AppFuse(JNIEnv* env);
int register_android_server_SerialService(JNIEnv* env);
int register_android_server_SystemServer(JNIEnv* env);
int register_android_server_UsbDeviceManager(JNIEnv* env);
@@ -83,6 +84,7 @@
register_android_server_PersistentDataBlockService(env);
register_android_server_Watchdog(env);
register_android_server_HardwarePropertiesManagerService(env);
+ register_android_server_storage_AppFuse(env);
return JNI_VERSION_1_4;
}