Add AppFuseBridge class to the system service.

Bug: 29970149
Test: None
Change-Id: I1d40d8e3aec1c57a31d5ae66b33305990dc86b67
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;
 }