PageRenderTime 43ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/core/java/android/os/ShellCommand.java

https://gitlab.com/drgroovestarr/frameworks_base
Java | 326 lines | 219 code | 26 blank | 81 comment | 58 complexity | 3ae2e3e95b51d05aef7dfa9f513cd258 MD5 | raw file
  1. /*
  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. package android.os;
  17. import android.util.Slog;
  18. import com.android.internal.util.FastPrintWriter;
  19. import java.io.BufferedInputStream;
  20. import java.io.FileDescriptor;
  21. import java.io.FileInputStream;
  22. import java.io.FileOutputStream;
  23. import java.io.InputStream;
  24. import java.io.OutputStream;
  25. import java.io.PrintWriter;
  26. /**
  27. * Helper for implementing {@link Binder#onShellCommand Binder.onShellCommand}.
  28. * @hide
  29. */
  30. public abstract class ShellCommand {
  31. static final String TAG = "ShellCommand";
  32. static final boolean DEBUG = false;
  33. private Binder mTarget;
  34. private FileDescriptor mIn;
  35. private FileDescriptor mOut;
  36. private FileDescriptor mErr;
  37. private String[] mArgs;
  38. private ShellCallback mShellCallback;
  39. private ResultReceiver mResultReceiver;
  40. private String mCmd;
  41. private int mArgPos;
  42. private String mCurArgData;
  43. private FileInputStream mFileIn;
  44. private FileOutputStream mFileOut;
  45. private FileOutputStream mFileErr;
  46. private FastPrintWriter mOutPrintWriter;
  47. private FastPrintWriter mErrPrintWriter;
  48. private InputStream mInputStream;
  49. public void init(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err,
  50. String[] args, ShellCallback callback, int firstArgPos) {
  51. mTarget = target;
  52. mIn = in;
  53. mOut = out;
  54. mErr = err;
  55. mArgs = args;
  56. mShellCallback = callback;
  57. mResultReceiver = null;
  58. mCmd = null;
  59. mArgPos = firstArgPos;
  60. mCurArgData = null;
  61. mFileIn = null;
  62. mFileOut = null;
  63. mFileErr = null;
  64. mOutPrintWriter = null;
  65. mErrPrintWriter = null;
  66. mInputStream = null;
  67. }
  68. public int exec(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err,
  69. String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
  70. String cmd;
  71. int start;
  72. if (args != null && args.length > 0) {
  73. cmd = args[0];
  74. start = 1;
  75. } else {
  76. cmd = null;
  77. start = 0;
  78. }
  79. init(target, in, out, err, args, callback, start);
  80. mCmd = cmd;
  81. mResultReceiver = resultReceiver;
  82. if (DEBUG) Slog.d(TAG, "Starting command " + mCmd + " on " + mTarget);
  83. int res = -1;
  84. try {
  85. res = onCommand(mCmd);
  86. if (DEBUG) Slog.d(TAG, "Executed command " + mCmd + " on " + mTarget);
  87. } catch (SecurityException e) {
  88. PrintWriter eout = getErrPrintWriter();
  89. eout.println("Security exception: " + e.getMessage());
  90. eout.println();
  91. e.printStackTrace(eout);
  92. } catch (Throwable e) {
  93. // Unlike usual calls, in this case if an exception gets thrown
  94. // back to us we want to print it back in to the dump data, since
  95. // that is where the caller expects all interesting information to
  96. // go.
  97. PrintWriter eout = getErrPrintWriter();
  98. eout.println();
  99. eout.println("Exception occurred while executing:");
  100. e.printStackTrace(eout);
  101. } finally {
  102. if (DEBUG) Slog.d(TAG, "Flushing output streams on " + mTarget);
  103. if (mOutPrintWriter != null) {
  104. mOutPrintWriter.flush();
  105. }
  106. if (mErrPrintWriter != null) {
  107. mErrPrintWriter.flush();
  108. }
  109. if (DEBUG) Slog.d(TAG, "Sending command result on " + mTarget);
  110. mResultReceiver.send(res, null);
  111. }
  112. if (DEBUG) Slog.d(TAG, "Finished command " + mCmd + " on " + mTarget);
  113. return res;
  114. }
  115. /**
  116. * Return direct raw access (not buffered) to the command's output data stream.
  117. */
  118. public OutputStream getRawOutputStream() {
  119. if (mFileOut == null) {
  120. mFileOut = new FileOutputStream(mOut);
  121. }
  122. return mFileOut;
  123. }
  124. /**
  125. * Return a PrintWriter for formatting output to {@link #getRawOutputStream()}.
  126. */
  127. public PrintWriter getOutPrintWriter() {
  128. if (mOutPrintWriter == null) {
  129. mOutPrintWriter = new FastPrintWriter(getRawOutputStream());
  130. }
  131. return mOutPrintWriter;
  132. }
  133. /**
  134. * Return direct raw access (not buffered) to the command's error output data stream.
  135. */
  136. public OutputStream getRawErrorStream() {
  137. if (mFileErr == null) {
  138. mFileErr = new FileOutputStream(mErr);
  139. }
  140. return mFileErr;
  141. }
  142. /**
  143. * Return a PrintWriter for formatting output to {@link #getRawErrorStream()}.
  144. */
  145. public PrintWriter getErrPrintWriter() {
  146. if (mErr == null) {
  147. return getOutPrintWriter();
  148. }
  149. if (mErrPrintWriter == null) {
  150. mErrPrintWriter = new FastPrintWriter(getRawErrorStream());
  151. }
  152. return mErrPrintWriter;
  153. }
  154. /**
  155. * Return direct raw access (not buffered) to the command's input data stream.
  156. */
  157. public InputStream getRawInputStream() {
  158. if (mFileIn == null) {
  159. mFileIn = new FileInputStream(mIn);
  160. }
  161. return mFileIn;
  162. }
  163. /**
  164. * Return buffered access to the command's {@link #getRawInputStream()}.
  165. */
  166. public InputStream getBufferedInputStream() {
  167. if (mInputStream == null) {
  168. mInputStream = new BufferedInputStream(getRawInputStream());
  169. }
  170. return mInputStream;
  171. }
  172. /**
  173. * Helper for just system services to ask the shell to open an output file.
  174. * @hide
  175. */
  176. public ParcelFileDescriptor openOutputFileForSystem(String path) {
  177. try {
  178. ParcelFileDescriptor pfd = getShellCallback().openOutputFile(path,
  179. "u:r:system_server:s0");
  180. if (pfd != null) {
  181. return pfd;
  182. }
  183. } catch (RuntimeException e) {
  184. getErrPrintWriter().println("Failure opening file: " + e.getMessage());
  185. }
  186. getErrPrintWriter().println("Error: Unable to open file: " + path);
  187. getErrPrintWriter().println("Consider using a file under /data/local/tmp/");
  188. return null;
  189. }
  190. /**
  191. * Return the next option on the command line -- that is an argument that
  192. * starts with '-'. If the next argument is not an option, null is returned.
  193. */
  194. public String getNextOption() {
  195. if (mCurArgData != null) {
  196. String prev = mArgs[mArgPos - 1];
  197. throw new IllegalArgumentException("No argument expected after \"" + prev + "\"");
  198. }
  199. if (mArgPos >= mArgs.length) {
  200. return null;
  201. }
  202. String arg = mArgs[mArgPos];
  203. if (!arg.startsWith("-")) {
  204. return null;
  205. }
  206. mArgPos++;
  207. if (arg.equals("--")) {
  208. return null;
  209. }
  210. if (arg.length() > 1 && arg.charAt(1) != '-') {
  211. if (arg.length() > 2) {
  212. mCurArgData = arg.substring(2);
  213. return arg.substring(0, 2);
  214. } else {
  215. mCurArgData = null;
  216. return arg;
  217. }
  218. }
  219. mCurArgData = null;
  220. return arg;
  221. }
  222. /**
  223. * Return the next argument on the command line, whatever it is; if there are
  224. * no arguments left, return null.
  225. */
  226. public String getNextArg() {
  227. if (mCurArgData != null) {
  228. String arg = mCurArgData;
  229. mCurArgData = null;
  230. return arg;
  231. } else if (mArgPos < mArgs.length) {
  232. return mArgs[mArgPos++];
  233. } else {
  234. return null;
  235. }
  236. }
  237. public String peekNextArg() {
  238. if (mCurArgData != null) {
  239. return mCurArgData;
  240. } else if (mArgPos < mArgs.length) {
  241. return mArgs[mArgPos];
  242. } else {
  243. return null;
  244. }
  245. }
  246. /**
  247. * Return the next argument on the command line, whatever it is; if there are
  248. * no arguments left, throws an IllegalArgumentException to report this to the user.
  249. */
  250. public String getNextArgRequired() {
  251. String arg = getNextArg();
  252. if (arg == null) {
  253. String prev = mArgs[mArgPos - 1];
  254. throw new IllegalArgumentException("Argument expected after \"" + prev + "\"");
  255. }
  256. return arg;
  257. }
  258. /**
  259. * Return the {@link ShellCallback} for communicating back with the calling shell.
  260. */
  261. public ShellCallback getShellCallback() {
  262. return mShellCallback;
  263. }
  264. public int handleDefaultCommands(String cmd) {
  265. if ("dump".equals(cmd)) {
  266. String[] newArgs = new String[mArgs.length-1];
  267. System.arraycopy(mArgs, 1, newArgs, 0, mArgs.length-1);
  268. mTarget.doDump(mOut, getOutPrintWriter(), newArgs);
  269. return 0;
  270. } else if (cmd == null || "help".equals(cmd) || "-h".equals(cmd)) {
  271. onHelp();
  272. } else {
  273. getOutPrintWriter().println("Unknown command: " + cmd);
  274. }
  275. return -1;
  276. }
  277. /**
  278. * Implement parsing and execution of a command. If it isn't a command you understand,
  279. * call {@link #handleDefaultCommands(String)} and return its result as a last resort.
  280. * Use {@link #getNextOption()}, {@link #getNextArg()}, and {@link #getNextArgRequired()}
  281. * to process additional command line arguments. Command output can be written to
  282. * {@link #getOutPrintWriter()} and errors to {@link #getErrPrintWriter()}.
  283. *
  284. * <p class="caution">Note that no permission checking has been done before entering this function,
  285. * so you need to be sure to do your own security verification for any commands you
  286. * are executing. The easiest way to do this is to have the ShellCommand contain
  287. * only a reference to your service's aidl interface, and do all of your command
  288. * implementations on top of that -- that way you can rely entirely on your executing security
  289. * code behind that interface.</p>
  290. *
  291. * @param cmd The first command line argument representing the name of the command to execute.
  292. * @return Return the command result; generally 0 or positive indicates success and
  293. * negative values indicate error.
  294. */
  295. public abstract int onCommand(String cmd);
  296. /**
  297. * Implement this to print help text about your command to {@link #getOutPrintWriter()}.
  298. */
  299. public abstract void onHelp();
  300. }