blob: cad482b6bab98a518425159ef1aaa30e7e0f8ede [file] [log] [blame]
Dianne Hackborn9461b6f2015-10-07 17:33:16 -07001/*
2 * Copyright (C) 2015 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.Slog;
20import com.android.internal.util.FastPrintWriter;
21
Todd Kennedyec059d82015-11-03 17:08:55 -080022import java.io.BufferedInputStream;
Dianne Hackborn9461b6f2015-10-07 17:33:16 -070023import java.io.FileDescriptor;
Todd Kennedyec059d82015-11-03 17:08:55 -080024import java.io.FileInputStream;
Dianne Hackborn9461b6f2015-10-07 17:33:16 -070025import java.io.FileOutputStream;
Todd Kennedyec059d82015-11-03 17:08:55 -080026import java.io.InputStream;
Dianne Hackborn9461b6f2015-10-07 17:33:16 -070027import java.io.PrintWriter;
28
29/**
30 * @hide
31 */
32public abstract class ShellCommand {
33 static final String TAG = "ShellCommand";
34 static final boolean DEBUG = false;
35
36 private Binder mTarget;
37 private FileDescriptor mIn;
38 private FileDescriptor mOut;
39 private FileDescriptor mErr;
40 private String[] mArgs;
41 private ResultReceiver mResultReceiver;
42
43 private String mCmd;
44 private int mArgPos;
45 private String mCurArgData;
46
47 private FastPrintWriter mOutPrintWriter;
48 private FastPrintWriter mErrPrintWriter;
Todd Kennedyec059d82015-11-03 17:08:55 -080049 private InputStream mInputStream;
Dianne Hackborn9461b6f2015-10-07 17:33:16 -070050
Dianne Hackborn2e441072015-10-28 18:00:57 -070051 public int exec(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err,
Dianne Hackborn9461b6f2015-10-07 17:33:16 -070052 String[] args, ResultReceiver resultReceiver) {
53 mTarget = target;
54 mIn = in;
55 mOut = out;
56 mErr = err;
57 mArgs = args;
58 mResultReceiver = resultReceiver;
59 mCmd = args != null && args.length > 0 ? args[0] : null;
60 mArgPos = 1;
61 mCurArgData = null;
62 mOutPrintWriter = null;
63 mErrPrintWriter = null;
64
65 if (DEBUG) Slog.d(TAG, "Starting command " + mCmd + " on " + mTarget);
66 int res = -1;
67 try {
68 res = onCommand(mCmd);
69 if (DEBUG) Slog.d(TAG, "Executed command " + mCmd + " on " + mTarget);
70 } catch (SecurityException e) {
71 PrintWriter eout = getErrPrintWriter();
72 eout.println("Security exception: " + e.getMessage());
73 eout.println();
74 e.printStackTrace(eout);
75 } catch (Throwable e) {
76 // Unlike usual calls, in this case if an exception gets thrown
77 // back to us we want to print it back in to the dump data, since
78 // that is where the caller expects all interesting information to
79 // go.
80 PrintWriter eout = getErrPrintWriter();
81 eout.println();
82 eout.println("Exception occurred while dumping:");
83 e.printStackTrace(eout);
84 } finally {
85 if (DEBUG) Slog.d(TAG, "Flushing output streams on " + mTarget);
86 if (mOutPrintWriter != null) {
87 mOutPrintWriter.flush();
88 }
89 if (mErrPrintWriter != null) {
90 mErrPrintWriter.flush();
91 }
92 if (DEBUG) Slog.d(TAG, "Sending command result on " + mTarget);
93 mResultReceiver.send(res, null);
94 }
95 if (DEBUG) Slog.d(TAG, "Finished command " + mCmd + " on " + mTarget);
Dianne Hackborn2e441072015-10-28 18:00:57 -070096 return res;
Dianne Hackborn9461b6f2015-10-07 17:33:16 -070097 }
98
99 public PrintWriter getOutPrintWriter() {
100 if (mOutPrintWriter == null) {
101 FileOutputStream fout = new FileOutputStream(mOut);
102 mOutPrintWriter = new FastPrintWriter(fout);
103 }
104 return mOutPrintWriter;
105 }
106
107 public PrintWriter getErrPrintWriter() {
108 if (mErr == null) {
109 return getOutPrintWriter();
110 }
111 if (mErrPrintWriter == null) {
112 FileOutputStream fout = new FileOutputStream(mErr);
113 mErrPrintWriter = new FastPrintWriter(fout);
114 }
115 return mErrPrintWriter;
116 }
117
Todd Kennedyec059d82015-11-03 17:08:55 -0800118 public InputStream getInputStream() {
119 if (mInputStream == null) {
120 mInputStream = new BufferedInputStream(new FileInputStream(mIn));
121 }
122 return mInputStream;
123 }
124
Dianne Hackborn9461b6f2015-10-07 17:33:16 -0700125 /**
126 * Return the next option on the command line -- that is an argument that
127 * starts with '-'. If the next argument is not an option, null is returned.
128 */
129 public String getNextOption() {
130 if (mCurArgData != null) {
131 String prev = mArgs[mArgPos - 1];
132 throw new IllegalArgumentException("No argument expected after \"" + prev + "\"");
133 }
134 if (mArgPos >= mArgs.length) {
135 return null;
136 }
137 String arg = mArgs[mArgPos];
138 if (!arg.startsWith("-")) {
139 return null;
140 }
141 mArgPos++;
142 if (arg.equals("--")) {
143 return null;
144 }
145 if (arg.length() > 1 && arg.charAt(1) != '-') {
146 if (arg.length() > 2) {
147 mCurArgData = arg.substring(2);
148 return arg.substring(0, 2);
149 } else {
150 mCurArgData = null;
151 return arg;
152 }
153 }
154 mCurArgData = null;
155 return arg;
156 }
157
158 /**
159 * Return the next argument on the command line, whatever it is; if there are
160 * no arguments left, return null.
161 */
162 public String getNextArg() {
163 if (mCurArgData != null) {
164 String arg = mCurArgData;
165 mCurArgData = null;
166 return arg;
167 } else if (mArgPos < mArgs.length) {
168 return mArgs[mArgPos++];
169 } else {
170 return null;
171 }
172 }
173
174 /**
175 * Return the next argument on the command line, whatever it is; if there are
176 * no arguments left, throws an IllegalArgumentException to report this to the user.
177 */
178 public String getNextArgRequired() {
179 String arg = getNextArg();
180 if (arg == null) {
181 String prev = mArgs[mArgPos - 1];
182 throw new IllegalArgumentException("Argument expected after \"" + prev + "\"");
183 }
184 return arg;
185 }
186
187 public int handleDefaultCommands(String cmd) {
188 if ("dump".equals(cmd)) {
189 String[] newArgs = new String[mArgs.length-1];
190 System.arraycopy(mArgs, 1, newArgs, 0, mArgs.length-1);
191 mTarget.doDump(mOut, getOutPrintWriter(), newArgs);
192 return 0;
193 } else if (cmd == null || "help".equals(cmd) || "-h".equals(cmd)) {
194 onHelp();
195 } else {
196 getOutPrintWriter().println("Unknown command: " + cmd);
197 }
198 return -1;
199 }
200
201 public abstract int onCommand(String cmd);
202
203 public abstract void onHelp();
204}