summaryrefslogtreecommitdiff
path: root/core/java
diff options
context:
space:
mode:
authorDaichi Hirono <hirono@google.com>2017-04-03 13:18:40 +0900
committerDaichi Hirono <hirono@google.com>2017-04-03 05:03:03 +0000
commitea6e6e17a0cd6fffd1c293972e138728851d4372 (patch)
tree36bb8cb9d0390d9203182e41de8d69d0a617defd /core/java
parent21a5edcc24cbca1ae3f0855d71737b22ab81ad6d (diff)
Process FuseAppLoop messages in Handler.Callback
Previously FuseAppLoop instantiates Runnable for each command, which causes lots of instantiation and GC. Test: CTS Bug: 35229514 Change-Id: Ifea098e5ade044b1a954c0b714c5b3270a95cd1a
Diffstat (limited to 'core/java')
-rw-r--r--core/java/com/android/internal/os/FuseAppLoop.java206
1 files changed, 123 insertions, 83 deletions
diff --git a/core/java/com/android/internal/os/FuseAppLoop.java b/core/java/com/android/internal/os/FuseAppLoop.java
index 8edd637ea814..088e7268b984 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.NonNull;
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 android.util.SparseArray;
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 @@ public class FuseAppLoop {
}
};
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 @@ public class FuseAppLoop {
@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 @@ public class FuseAppLoop {
}
});
mThread.start();
- mDefaultHandler = null;
}
public int registerCallback(@NonNull ProxyFileDescriptorCallback callback,
@@ -110,7 +112,8 @@ public class FuseAppLoop {
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 @@ public class FuseAppLoop {
// 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 @@ public class FuseAppLoop {
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 @@ public class FuseAppLoop {
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 @@ public class FuseAppLoop {
mEntries.clear();
}
}
+
+ private static class Args {
+ long unique;
+ long inode;
+ long offset;
+ int size;
+ byte[] data;
+ CallbackEntry entry;
+ }
}