Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3ff1c01c authored by Daichi Hirono's avatar Daichi Hirono
Browse files

Add AppFuseBridge class to the system service.

Bug: 29970149
Test: None
Change-Id: I1d40d8e3aec1c57a31d5ae66b33305990dc86b67
parent 2cf7c483
Loading
Loading
Loading
Loading
+56 −0
Original line number Diff line number Diff line
/*
 * 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];
        }
    };
}
+95 −0
Original line number Diff line number Diff line
/*
 * 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);
}
+3 −0
Original line number Diff line number Diff line
@@ -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 \
+72 −0
Original line number Diff line number Diff line
/*
 * 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
+2 −0
Original line number Diff line number Diff line
@@ -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;
}