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 
17 package android.os;
18 
19 import android.util.Log;
20 
21 import 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  */
28 public 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 {
openFile(String path, String seLinuxContext, String mode)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      */
ShellCallback()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      */
openFile(String path, String seLinuxContext, String mode)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 
onOpenFile(String path, String seLinuxContext, String mode)80     public ParcelFileDescriptor onOpenFile(String path, String seLinuxContext, String mode) {
81         return null;
82     }
83 
writeToParcel(ShellCallback callback, Parcel out)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 
describeContents()92     public int describeContents() {
93         return 0;
94     }
95 
writeToParcel(Parcel out, int flags)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 
ShellCallback(Parcel in)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 @android.annotation.NonNull 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