From 3ff1c01cae0b654acd53088634e07e26557edd99 Mon Sep 17 00:00:00 2001 From: Daichi Hirono Date: Fri, 28 Oct 2016 12:53:44 +0900 Subject: [PATCH] Add AppFuseBridge class to the system service. Bug: 29970149 Test: None Change-Id: I1d40d8e3aec1c57a31d5ae66b33305990dc86b67 --- .../com/android/internal/os/AppFuseMount.java | 56 +++++++++++ .../android/server/storage/AppFuseBridge.java | 95 +++++++++++++++++++ services/core/jni/Android.mk | 3 + ...m_android_server_storage_AppFuseBridge.cpp | 72 ++++++++++++++ services/core/jni/onload.cpp | 2 + 5 files changed, 228 insertions(+) create mode 100644 core/java/com/android/internal/os/AppFuseMount.java create mode 100644 services/core/java/com/android/server/storage/AppFuseBridge.java create mode 100644 services/core/jni/com_android_server_storage_AppFuseBridge.cpp 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 0000000000000..b392186ccc771 --- /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 CREATOR = + new Parcelable.Creator() { + @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 0000000000000..23be9a3a27f7d --- /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 2c46413b32631..17b143c114347 100644 --- a/services/core/jni/Android.mk +++ b/services/core/jni/Android.mk @@ -19,6 +19,7 @@ LOCAL_SRC_FILES += \ $(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 @@ LOCAL_C_INCLUDES += \ 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_C_INCLUDES += \ 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 0000000000000..640fd0e551275 --- /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 +#include +#include +#include +#include + +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 d69c37f0afea6..c291ba0dc24a4 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -28,6 +28,7 @@ int register_android_server_InputWindowHandle(JNIEnv* env); 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 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) 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; }