1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.os;
18
19import android.util.Log;
20
21import com.android.internal.os.IShellCallback;
22
23/**
24 * Special-purpose API for use with {@link IBinder#shellCommand IBinder.shellCommand} for
25 * performing operations back on the invoking shell.
26 * @hide
27 */
28public class ShellCallback implements Parcelable {
29    final static String TAG = "ShellCallback";
30
31    final static boolean DEBUG = false;
32
33    final boolean mLocal;
34
35    IShellCallback mShellCallback;
36
37    class MyShellCallback extends IShellCallback.Stub {
38        public ParcelFileDescriptor openFile(String path, String seLinuxContext,
39                String mode) {
40            return onOpenFile(path, seLinuxContext, mode);
41        }
42    }
43
44    /**
45     * Create a new ShellCallback to receive requests.
46     */
47    public ShellCallback() {
48        mLocal = true;
49    }
50
51    /**
52     * Ask the shell to open a file.  If opening for writing, will truncate the file if it
53     * already exists and will create the file if it doesn't exist.
54     * @param path Path of the file to be opened/created.
55     * @param seLinuxContext Optional SELinux context that must be allowed to have
56     * access to the file; if null, nothing is required.
57     * @param mode Mode to open file in: "r" for input/reading an existing file,
58     * "r+" for reading/writing an existing file, "w" for output/writing a new file (either
59     * creating or truncating an existing one), "w+" for reading/writing a new file (either
60     * creating or truncating an existing one).
61     */
62    public ParcelFileDescriptor openFile(String path, String seLinuxContext, String mode) {
63        if (DEBUG) Log.d(TAG, "openFile " + this + " mode=" + mode + ": mLocal=" + mLocal
64                + " mShellCallback=" + mShellCallback);
65
66        if (mLocal) {
67            return onOpenFile(path, seLinuxContext, mode);
68        }
69
70        if (mShellCallback != null) {
71            try {
72                return mShellCallback.openFile(path, seLinuxContext, mode);
73            } catch (RemoteException e) {
74                Log.w(TAG, "Failure opening " + path, e);
75            }
76        }
77        return null;
78    }
79
80    public ParcelFileDescriptor onOpenFile(String path, String seLinuxContext, String mode) {
81        return null;
82    }
83
84    public static void writeToParcel(ShellCallback callback, Parcel out) {
85        if (callback == null) {
86            out.writeStrongBinder(null);
87        } else {
88            callback.writeToParcel(out, 0);
89        }
90    }
91
92    public int describeContents() {
93        return 0;
94    }
95
96    public void writeToParcel(Parcel out, int flags) {
97        synchronized (this) {
98            if (mShellCallback == null) {
99                mShellCallback = new MyShellCallback();
100            }
101            out.writeStrongBinder(mShellCallback.asBinder());
102        }
103    }
104
105    ShellCallback(Parcel in) {
106        mLocal = false;
107        mShellCallback = IShellCallback.Stub.asInterface(in.readStrongBinder());
108        if (mShellCallback != null) {
109            Binder.allowBlocking(mShellCallback.asBinder());
110        }
111    }
112
113    public static final Parcelable.Creator<ShellCallback> CREATOR
114            = new Parcelable.Creator<ShellCallback>() {
115        public ShellCallback createFromParcel(Parcel in) {
116            return new ShellCallback(in);
117        }
118        public ShellCallback[] newArray(int size) {
119            return new ShellCallback[size];
120        }
121    };
122}
123