1878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono/* 2878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * Copyright (C) 2016 The Android Open Source Project 3878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * 4878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * Licensed under the Apache License, Version 2.0 (the "License"); 5878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * you may not use this file except in compliance with the License. 6878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * You may obtain a copy of the License at 7878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * 8878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * http://www.apache.org/licenses/LICENSE-2.0 9878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * 10878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * Unless required by applicable law or agreed to in writing, software 11878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * distributed under the License is distributed on an "AS IS" BASIS, 12878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * See the License for the specific language governing permissions and 14878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * limitations under the License. 15878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono */ 16878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 17878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hironopackage com.android.internal.os; 18878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 19878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hironoimport android.annotation.NonNull; 20878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hironoimport android.annotation.Nullable; 219fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hironoimport android.os.ProxyFileDescriptorCallback; 22812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hironoimport android.os.Handler; 23ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hironoimport android.os.Message; 24878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hironoimport android.os.ParcelFileDescriptor; 25878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hironoimport android.system.ErrnoException; 26878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hironoimport android.system.OsConstants; 27878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hironoimport android.util.Log; 28878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hironoimport android.util.SparseArray; 29878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hironoimport com.android.internal.annotations.GuardedBy; 30878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hironoimport com.android.internal.util.Preconditions; 31812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hironoimport java.util.HashMap; 32ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hironoimport java.util.LinkedList; 33812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hironoimport java.util.Map; 349fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hironoimport java.util.concurrent.ThreadFactory; 35878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 36ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hironopublic class FuseAppLoop implements Handler.Callback { 37878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono private static final String TAG = "FuseAppLoop"; 38878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 39878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono public static final int ROOT_INODE = 1; 40878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono private static final int MIN_INODE = 2; 419fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono private static final ThreadFactory sDefaultThreadFactory = new ThreadFactory() { 429fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono @Override 439fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono public Thread newThread(Runnable r) { 449fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono return new Thread(r, TAG); 459fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono } 469fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono }; 47812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono private static final int FUSE_OK = 0; 48ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono private static final int ARGS_POOL_SIZE = 50; 49878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 50878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono private final Object mLock = new Object(); 519fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono private final int mMountPointId; 529fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono private final Thread mThread; 53878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 54878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono @GuardedBy("mLock") 55878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono private final SparseArray<CallbackEntry> mCallbackMap = new SparseArray<>(); 56878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 57812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono @GuardedBy("mLock") 58812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono private final BytesMap mBytesMap = new BytesMap(); 59812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono 60ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono @GuardedBy("mLock") 61ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono private final LinkedList<Args> mArgsPool = new LinkedList<>(); 62ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono 63878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono /** 64878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * Sequential number can be used as file name and inode in AppFuse. 65878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono * 0 is regarded as an error, 1 is mount point. So we start the number from 2. 66878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono */ 67878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono @GuardedBy("mLock") 68878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono private int mNextInode = MIN_INODE; 69878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 70812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono @GuardedBy("mLock") 71812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono private long mInstance; 72812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono 73812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono public FuseAppLoop( 749fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono int mountPointId, @NonNull ParcelFileDescriptor fd, @Nullable ThreadFactory factory) { 759fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono mMountPointId = mountPointId; 769fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono if (factory == null) { 779fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono factory = sDefaultThreadFactory; 789fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono } 79812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono mInstance = native_new(fd.detachFd()); 80812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono mThread = factory.newThread(() -> { 81812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono native_start(mInstance); 82812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono synchronized (mLock) { 83812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono native_delete(mInstance); 84812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono mInstance = 0; 85812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono mBytesMap.clear(); 86878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 879fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono }); 88812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono mThread.start(); 899fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono } 909fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono 91812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono public int registerCallback(@NonNull ProxyFileDescriptorCallback callback, 92812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono @NonNull Handler handler) throws FuseUnavailableMountException { 93878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono synchronized (mLock) { 94812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono Preconditions.checkNotNull(callback); 95812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono Preconditions.checkNotNull(handler); 96812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono Preconditions.checkState( 97812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono mCallbackMap.size() < Integer.MAX_VALUE - MIN_INODE, "Too many opened files."); 98812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono Preconditions.checkArgument( 99812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono Thread.currentThread().getId() != handler.getLooper().getThread().getId(), 100812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono "Handler must be different from the current thread"); 101812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono if (mInstance == 0) { 102812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono throw new FuseUnavailableMountException(mMountPointId); 103878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 1049fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono int id; 105878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono while (true) { 106878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono id = mNextInode; 107878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono mNextInode++; 108878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono if (mNextInode < 0) { 109878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono mNextInode = MIN_INODE; 110878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 111878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono if (mCallbackMap.get(id) == null) { 112878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono break; 113878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 114878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 115ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono mCallbackMap.put(id, new CallbackEntry( 116ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono callback, new Handler(handler.getLooper(), this))); 1179fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono return id; 118878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 119878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 120878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 1219fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono public void unregisterCallback(int id) { 122812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono synchronized (mLock) { 123812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono mCallbackMap.remove(id); 124812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono } 1259fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono } 1269fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono 1279fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono public int getMountPointId() { 1289fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono return mMountPointId; 129878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 130878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 131812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono // Defined in fuse.h 132812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono private static final int FUSE_LOOKUP = 1; 133812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono private static final int FUSE_GETATTR = 3; 134812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono private static final int FUSE_OPEN = 14; 135812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono private static final int FUSE_READ = 15; 136812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono private static final int FUSE_WRITE = 16; 137812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono private static final int FUSE_RELEASE = 18; 138812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono private static final int FUSE_FSYNC = 20; 139812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono 140812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono // Defined in FuseBuffer.h 141812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono private static final int FUSE_MAX_WRITE = 256 * 1024; 142878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 143ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono @Override 144ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono public boolean handleMessage(Message msg) { 145ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono final Args args = (Args) msg.obj; 146ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono final CallbackEntry entry = args.entry; 147ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono final long inode = args.inode; 148ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono final long unique = args.unique; 149ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono final int size = args.size; 150ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono final long offset = args.offset; 151ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono final byte[] data = args.data; 152ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono 153ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono try { 154ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono switch (msg.what) { 155ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono case FUSE_LOOKUP: { 156ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono final long fileSize = entry.callback.onGetSize(); 157ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono synchronized (mLock) { 158ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono if (mInstance != 0) { 159ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono native_replyLookup(mInstance, unique, inode, fileSize); 160ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono } 161ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono recycleLocked(args); 162ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono } 163ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono break; 164ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono } 165ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono case FUSE_GETATTR: { 166ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono final long fileSize = entry.callback.onGetSize(); 167ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono synchronized (mLock) { 168ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono if (mInstance != 0) { 169ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono native_replyGetAttr(mInstance, unique, inode, fileSize); 170ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono } 171ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono recycleLocked(args); 172ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono } 173ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono break; 174ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono } 175ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono case FUSE_READ: 176ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono final int readSize = entry.callback.onRead( 177ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono offset, size, data); 178ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono synchronized (mLock) { 179ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono if (mInstance != 0) { 180ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono native_replyRead(mInstance, unique, readSize, data); 181ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono } 182ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono recycleLocked(args); 183ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono } 184ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono break; 185ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono case FUSE_WRITE: 186ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono final int writeSize = entry.callback.onWrite(offset, size, data); 187ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono synchronized (mLock) { 188ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono if (mInstance != 0) { 189ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono native_replyWrite(mInstance, unique, writeSize); 190ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono } 191ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono recycleLocked(args); 192ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono } 193ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono break; 194ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono case FUSE_FSYNC: 195ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono entry.callback.onFsync(); 196ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono synchronized (mLock) { 197ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono if (mInstance != 0) { 198ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono native_replySimple(mInstance, unique, FUSE_OK); 199ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono } 200ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono recycleLocked(args); 201ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono } 202ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono break; 203ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono case FUSE_RELEASE: 204ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono entry.callback.onRelease(); 205ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono synchronized (mLock) { 206ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono if (mInstance != 0) { 207ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono native_replySimple(mInstance, unique, FUSE_OK); 208ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono } 209ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono mBytesMap.stopUsing(entry.getThreadId()); 210ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono recycleLocked(args); 211ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono } 212ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono break; 213ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono default: 214ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono throw new IllegalArgumentException("Unknown FUSE command: " + msg.what); 215ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono } 216ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono } catch (Exception error) { 217ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono synchronized (mLock) { 218ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono Log.e(TAG, "", error); 219ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono replySimpleLocked(unique, getError(error)); 220ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono recycleLocked(args); 221ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono } 222ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono } 223ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono 224ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono return true; 225ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono } 226ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono 227878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono // Called by JNI. 228878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono @SuppressWarnings("unused") 229812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono private void onCommand(int command, long unique, long inode, long offset, int size, 230812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono byte[] data) { 231ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono synchronized (mLock) { 232878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono try { 233ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono final Args args; 234ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono if (mArgsPool.size() == 0) { 235ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono args = new Args(); 236ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono } else { 237ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono args = mArgsPool.pop(); 238ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono } 239ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono args.unique = unique; 240ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono args.inode = inode; 241ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono args.offset = offset; 242ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono args.size = size; 243ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono args.data = data; 244ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono args.entry = getCallbackEntryOrThrowLocked(inode); 245ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono if (!args.entry.handler.sendMessage( 246ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono Message.obtain(args.entry.handler, command, 0, 0, args))) { 247ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono throw new ErrnoException("onCommand", OsConstants.EBADF); 248ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono } 249ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono } catch (Exception error) { 250812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono replySimpleLocked(unique, getError(error)); 251878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 252878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 253878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 254878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 255878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono // Called by JNI. 256878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono @SuppressWarnings("unused") 257812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono private byte[] onOpen(long unique, long inode) { 258812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono synchronized (mLock) { 259878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono try { 260878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono final CallbackEntry entry = getCallbackEntryOrThrowLocked(inode); 261878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono if (entry.opened) { 262878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono throw new ErrnoException("onOpen", OsConstants.EMFILE); 263878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 264812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono if (mInstance != 0) { 265812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono native_replyOpen(mInstance, unique, /* fh */ inode); 266812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono entry.opened = true; 267812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono return mBytesMap.startUsing(entry.getThreadId()); 268812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono } 269812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono } catch (ErrnoException error) { 270812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono replySimpleLocked(unique, getError(error)); 271878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 272812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono return null; 273878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 274878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 275878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 276812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono private static int getError(@NonNull Exception error) { 277812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono if (error instanceof ErrnoException) { 278812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono final int errno = ((ErrnoException) error).errno; 279812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono if (errno != OsConstants.ENOSYS) { 280812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono return -errno; 281878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 282878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 283812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono return -OsConstants.EBADF; 284878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 285878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 286812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono private CallbackEntry getCallbackEntryOrThrowLocked(long inode) throws ErrnoException { 287812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono final CallbackEntry entry = mCallbackMap.get(checkInode(inode)); 288812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono if (entry == null) { 289812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono throw new ErrnoException("getCallbackEntryOrThrowLocked", OsConstants.ENOENT); 290878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 291812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono return entry; 292878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 293878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 294ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono private void recycleLocked(Args args) { 295ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono if (mArgsPool.size() < ARGS_POOL_SIZE) { 296ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono mArgsPool.add(args); 297878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 298878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 299878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 300812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono private void replySimpleLocked(long unique, int result) { 301812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono if (mInstance != 0) { 302812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono native_replySimple(mInstance, unique, result); 303878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 304878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 305878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 306812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono native long native_new(int fd); 307812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono native void native_delete(long ptr); 308812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono native void native_start(long ptr); 3099fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono 310812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono native void native_replySimple(long ptr, long unique, int result); 311812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono native void native_replyOpen(long ptr, long unique, long fh); 312812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono native void native_replyLookup(long ptr, long unique, long inode, long size); 313812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono native void native_replyGetAttr(long ptr, long unique, long inode, long size); 314812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono native void native_replyWrite(long ptr, long unique, int size); 315812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono native void native_replyRead(long ptr, long unique, int size, byte[] bytes); 316878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 317878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono private static int checkInode(long inode) { 318878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono Preconditions.checkArgumentInRange(inode, MIN_INODE, Integer.MAX_VALUE, "checkInode"); 319878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono return (int) inode; 320878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 321878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 322878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono public static class UnmountedException extends Exception {} 323878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono 324878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono private static class CallbackEntry { 3259fb00183a04036a58ee208f5bfd6c9768982f0aaDaichi Hirono final ProxyFileDescriptorCallback callback; 326812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono final Handler handler; 327878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono boolean opened; 328812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono 329812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono CallbackEntry(ProxyFileDescriptorCallback callback, Handler handler) { 330812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono this.callback = Preconditions.checkNotNull(callback); 331812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono this.handler = Preconditions.checkNotNull(handler); 332812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono } 333812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono 334812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono long getThreadId() { 335812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono return handler.getLooper().getThread().getId(); 336812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono } 337812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono } 338812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono 339812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono /** 340812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono * Entry for bytes map. 341812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono */ 342812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono private static class BytesMapEntry { 343812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono int counter = 0; 344812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono byte[] bytes = new byte[FUSE_MAX_WRITE]; 345812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono } 346812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono 347812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono /** 348812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono * Map between Thread ID and byte buffer. 349812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono */ 350812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono private static class BytesMap { 351812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono final Map<Long, BytesMapEntry> mEntries = new HashMap<>(); 352812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono 353812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono byte[] startUsing(long threadId) { 354812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono BytesMapEntry entry = mEntries.get(threadId); 355812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono if (entry == null) { 356812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono entry = new BytesMapEntry(); 357812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono mEntries.put(threadId, entry); 358812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono } 359812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono entry.counter++; 360812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono return entry.bytes; 361812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono } 362812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono 363812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono void stopUsing(long threadId) { 364812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono final BytesMapEntry entry = mEntries.get(threadId); 365812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono Preconditions.checkNotNull(entry); 366812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono entry.counter--; 367812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono if (entry.counter <= 0) { 368812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono mEntries.remove(threadId); 369812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono } 370812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono } 371812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono 372812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono void clear() { 373812c95d37dccf8a1fcef55c6999c6d69ecbac400Daichi Hirono mEntries.clear(); 374878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 375878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono } 376ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono 377ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono private static class Args { 378ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono long unique; 379ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono long inode; 380ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono long offset; 381ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono int size; 382ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono byte[] data; 383ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono CallbackEntry entry; 384ea6e6e17a0cd6fffd1c293972e138728851d4372Daichi Hirono } 385878e86f38f87cc5dc537ffc623b04f9a779fb080Daichi Hirono} 386