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