Merge "Process FuseAppLoop messages in Handler.Callback" into oc-dev
diff --git a/core/java/com/android/internal/os/FuseAppLoop.java b/core/java/com/android/internal/os/FuseAppLoop.java
index 8edd637..088e726 100644
--- a/core/java/com/android/internal/os/FuseAppLoop.java
+++ b/core/java/com/android/internal/os/FuseAppLoop.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.os.ProxyFileDescriptorCallback;
import android.os.Handler;
+import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.system.ErrnoException;
import android.system.OsConstants;
@@ -28,10 +29,11 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
import java.util.HashMap;
+import java.util.LinkedList;
import java.util.Map;
import java.util.concurrent.ThreadFactory;
-public class FuseAppLoop {
+public class FuseAppLoop implements Handler.Callback {
private static final String TAG = "FuseAppLoop";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
public static final int ROOT_INODE = 1;
@@ -43,13 +45,11 @@
}
};
private static final int FUSE_OK = 0;
+ private static final int ARGS_POOL_SIZE = 50;
private final Object mLock = new Object();
private final int mMountPointId;
private final Thread mThread;
- private final Handler mDefaultHandler;
-
- private static final int CMD_FSYNC = 1;
@GuardedBy("mLock")
private final SparseArray<CallbackEntry> mCallbackMap = new SparseArray<>();
@@ -57,6 +57,9 @@
@GuardedBy("mLock")
private final BytesMap mBytesMap = new BytesMap();
+ @GuardedBy("mLock")
+ private final LinkedList<Args> mArgsPool = new LinkedList<>();
+
/**
* Sequential number can be used as file name and inode in AppFuse.
* 0 is regarded as an error, 1 is mount point. So we start the number from 2.
@@ -83,7 +86,6 @@
}
});
mThread.start();
- mDefaultHandler = null;
}
public int registerCallback(@NonNull ProxyFileDescriptorCallback callback,
@@ -110,7 +112,8 @@
break;
}
}
- mCallbackMap.put(id, new CallbackEntry(callback, handler));
+ mCallbackMap.put(id, new CallbackEntry(
+ callback, new Handler(handler.getLooper(), this)));
return id;
}
}
@@ -137,78 +140,113 @@
// Defined in FuseBuffer.h
private static final int FUSE_MAX_WRITE = 256 * 1024;
+ @Override
+ public boolean handleMessage(Message msg) {
+ final Args args = (Args) msg.obj;
+ final CallbackEntry entry = args.entry;
+ final long inode = args.inode;
+ final long unique = args.unique;
+ final int size = args.size;
+ final long offset = args.offset;
+ final byte[] data = args.data;
+
+ try {
+ switch (msg.what) {
+ case FUSE_LOOKUP: {
+ final long fileSize = entry.callback.onGetSize();
+ synchronized (mLock) {
+ if (mInstance != 0) {
+ native_replyLookup(mInstance, unique, inode, fileSize);
+ }
+ recycleLocked(args);
+ }
+ break;
+ }
+ case FUSE_GETATTR: {
+ final long fileSize = entry.callback.onGetSize();
+ synchronized (mLock) {
+ if (mInstance != 0) {
+ native_replyGetAttr(mInstance, unique, inode, fileSize);
+ }
+ recycleLocked(args);
+ }
+ break;
+ }
+ case FUSE_READ:
+ final int readSize = entry.callback.onRead(
+ offset, size, data);
+ synchronized (mLock) {
+ if (mInstance != 0) {
+ native_replyRead(mInstance, unique, readSize, data);
+ }
+ recycleLocked(args);
+ }
+ break;
+ case FUSE_WRITE:
+ final int writeSize = entry.callback.onWrite(offset, size, data);
+ synchronized (mLock) {
+ if (mInstance != 0) {
+ native_replyWrite(mInstance, unique, writeSize);
+ }
+ recycleLocked(args);
+ }
+ break;
+ case FUSE_FSYNC:
+ entry.callback.onFsync();
+ synchronized (mLock) {
+ if (mInstance != 0) {
+ native_replySimple(mInstance, unique, FUSE_OK);
+ }
+ recycleLocked(args);
+ }
+ break;
+ case FUSE_RELEASE:
+ entry.callback.onRelease();
+ synchronized (mLock) {
+ if (mInstance != 0) {
+ native_replySimple(mInstance, unique, FUSE_OK);
+ }
+ mBytesMap.stopUsing(entry.getThreadId());
+ recycleLocked(args);
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown FUSE command: " + msg.what);
+ }
+ } catch (Exception error) {
+ synchronized (mLock) {
+ Log.e(TAG, "", error);
+ replySimpleLocked(unique, getError(error));
+ recycleLocked(args);
+ }
+ }
+
+ return true;
+ }
+
// Called by JNI.
@SuppressWarnings("unused")
private void onCommand(int command, long unique, long inode, long offset, int size,
byte[] data) {
- synchronized(mLock) {
+ synchronized (mLock) {
try {
- final CallbackEntry entry = getCallbackEntryOrThrowLocked(inode);
- entry.postRunnable(() -> {
- try {
- switch (command) {
- case FUSE_LOOKUP: {
- final long fileSize = entry.callback.onGetSize();
- synchronized (mLock) {
- if (mInstance != 0) {
- native_replyLookup(mInstance, unique, inode, fileSize);
- }
- }
- break;
- }
- case FUSE_GETATTR: {
- final long fileSize = entry.callback.onGetSize();
- synchronized (mLock) {
- if (mInstance != 0) {
- native_replyGetAttr(mInstance, unique, inode, fileSize);
- }
- }
- break;
- }
- case FUSE_READ:
- final int readSize = entry.callback.onRead(offset, size, data);
- synchronized (mLock) {
- if (mInstance != 0) {
- native_replyRead(mInstance, unique, readSize, data);
- }
- }
- break;
- case FUSE_WRITE:
- final int writeSize = entry.callback.onWrite(offset, size, data);
- synchronized (mLock) {
- if (mInstance != 0) {
- native_replyWrite(mInstance, unique, writeSize);
- }
- }
- break;
- case FUSE_FSYNC:
- entry.callback.onFsync();
- synchronized (mLock) {
- if (mInstance != 0) {
- native_replySimple(mInstance, unique, FUSE_OK);
- }
- }
- break;
- case FUSE_RELEASE:
- entry.callback.onRelease();
- synchronized (mLock) {
- if (mInstance != 0) {
- native_replySimple(mInstance, unique, FUSE_OK);
- }
- mBytesMap.stopUsing(entry.getThreadId());
- }
- break;
- default:
- throw new IllegalArgumentException(
- "Unknown FUSE command: " + command);
- }
- } catch (Exception error) {
- Log.e(TAG, "", error);
- replySimple(unique, getError(error));
- }
- });
- } catch (ErrnoException error) {
- Log.e(TAG, "", error);
+ final Args args;
+ if (mArgsPool.size() == 0) {
+ args = new Args();
+ } else {
+ args = mArgsPool.pop();
+ }
+ args.unique = unique;
+ args.inode = inode;
+ args.offset = offset;
+ args.size = size;
+ args.data = data;
+ args.entry = getCallbackEntryOrThrowLocked(inode);
+ if (!args.entry.handler.sendMessage(
+ Message.obtain(args.entry.handler, command, 0, 0, args))) {
+ throw new ErrnoException("onCommand", OsConstants.EBADF);
+ }
+ } catch (Exception error) {
replySimpleLocked(unique, getError(error));
}
}
@@ -253,9 +291,9 @@
return entry;
}
- private void replySimple(long unique, int result) {
- synchronized (mLock) {
- replySimpleLocked(unique, result);
+ private void recycleLocked(Args args) {
+ if (mArgsPool.size() < ARGS_POOL_SIZE) {
+ mArgsPool.add(args);
}
}
@@ -296,13 +334,6 @@
long getThreadId() {
return handler.getLooper().getThread().getId();
}
-
- void postRunnable(Runnable runnable) throws ErrnoException {
- final boolean result = handler.post(runnable);
- if (!result) {
- throw new ErrnoException("postRunnable", OsConstants.EBADF);
- }
- }
}
/**
@@ -342,4 +373,13 @@
mEntries.clear();
}
}
+
+ private static class Args {
+ long unique;
+ long inode;
+ long offset;
+ int size;
+ byte[] data;
+ CallbackEntry entry;
+ }
}