Merge changes from topic "move_BSCH" am: 1b414d61b4
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1503395 Change-Id: I1e27a7fcde0ba83ffcad525ca091af7fc5ced2db
This commit is contained in:
@@ -1,330 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.os;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* Helper for implementing {@link Binder#onShellCommand Binder.onShellCommand}. This is meant to
|
||||
* be copied into mainline modules, so this class must not use any hidden APIs.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public abstract class BasicShellCommandHandler {
|
||||
static final String TAG = "ShellCommand";
|
||||
static final boolean DEBUG = false;
|
||||
|
||||
private Binder mTarget;
|
||||
private FileDescriptor mIn;
|
||||
private FileDescriptor mOut;
|
||||
private FileDescriptor mErr;
|
||||
private String[] mArgs;
|
||||
|
||||
private String mCmd;
|
||||
private int mArgPos;
|
||||
private String mCurArgData;
|
||||
|
||||
private FileInputStream mFileIn;
|
||||
private FileOutputStream mFileOut;
|
||||
private FileOutputStream mFileErr;
|
||||
|
||||
private PrintWriter mOutPrintWriter;
|
||||
private PrintWriter mErrPrintWriter;
|
||||
private InputStream mInputStream;
|
||||
|
||||
public void init(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err,
|
||||
String[] args, int firstArgPos) {
|
||||
mTarget = target;
|
||||
mIn = in;
|
||||
mOut = out;
|
||||
mErr = err;
|
||||
mArgs = args;
|
||||
mCmd = null;
|
||||
mArgPos = firstArgPos;
|
||||
mCurArgData = null;
|
||||
mFileIn = null;
|
||||
mFileOut = null;
|
||||
mFileErr = null;
|
||||
mOutPrintWriter = null;
|
||||
mErrPrintWriter = null;
|
||||
mInputStream = null;
|
||||
}
|
||||
|
||||
public int exec(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err,
|
||||
String[] args) {
|
||||
String cmd;
|
||||
int start;
|
||||
if (args != null && args.length > 0) {
|
||||
cmd = args[0];
|
||||
start = 1;
|
||||
} else {
|
||||
cmd = null;
|
||||
start = 0;
|
||||
}
|
||||
init(target, in, out, err, args, start);
|
||||
mCmd = cmd;
|
||||
|
||||
if (DEBUG) {
|
||||
RuntimeException here = new RuntimeException("here");
|
||||
here.fillInStackTrace();
|
||||
Log.d(TAG, "Starting command " + mCmd + " on " + mTarget, here);
|
||||
Log.d(TAG, "Calling uid=" + Binder.getCallingUid()
|
||||
+ " pid=" + Binder.getCallingPid());
|
||||
}
|
||||
int res = -1;
|
||||
try {
|
||||
res = onCommand(mCmd);
|
||||
if (DEBUG) Log.d(TAG, "Executed command " + mCmd + " on " + mTarget);
|
||||
} catch (Throwable e) {
|
||||
// Unlike usual calls, in this case if an exception gets thrown
|
||||
// back to us we want to print it back in to the dump data, since
|
||||
// that is where the caller expects all interesting information to
|
||||
// go.
|
||||
PrintWriter eout = getErrPrintWriter();
|
||||
eout.println();
|
||||
eout.println("Exception occurred while executing '" + mCmd + "':");
|
||||
e.printStackTrace(eout);
|
||||
} finally {
|
||||
if (DEBUG) Log.d(TAG, "Flushing output streams on " + mTarget);
|
||||
if (mOutPrintWriter != null) {
|
||||
mOutPrintWriter.flush();
|
||||
}
|
||||
if (mErrPrintWriter != null) {
|
||||
mErrPrintWriter.flush();
|
||||
}
|
||||
if (DEBUG) Log.d(TAG, "Sending command result on " + mTarget);
|
||||
}
|
||||
if (DEBUG) Log.d(TAG, "Finished command " + mCmd + " on " + mTarget);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the raw FileDescriptor for the output stream.
|
||||
*/
|
||||
public FileDescriptor getOutFileDescriptor() {
|
||||
return mOut;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return direct raw access (not buffered) to the command's output data stream.
|
||||
*/
|
||||
public OutputStream getRawOutputStream() {
|
||||
if (mFileOut == null) {
|
||||
mFileOut = new FileOutputStream(mOut);
|
||||
}
|
||||
return mFileOut;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a PrintWriter for formatting output to {@link #getRawOutputStream()}.
|
||||
*/
|
||||
public PrintWriter getOutPrintWriter() {
|
||||
if (mOutPrintWriter == null) {
|
||||
mOutPrintWriter = new PrintWriter(getRawOutputStream());
|
||||
}
|
||||
return mOutPrintWriter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the raw FileDescriptor for the error stream.
|
||||
*/
|
||||
public FileDescriptor getErrFileDescriptor() {
|
||||
return mErr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return direct raw access (not buffered) to the command's error output data stream.
|
||||
*/
|
||||
public OutputStream getRawErrorStream() {
|
||||
if (mFileErr == null) {
|
||||
mFileErr = new FileOutputStream(mErr);
|
||||
}
|
||||
return mFileErr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a PrintWriter for formatting output to {@link #getRawErrorStream()}.
|
||||
*/
|
||||
public PrintWriter getErrPrintWriter() {
|
||||
if (mErr == null) {
|
||||
return getOutPrintWriter();
|
||||
}
|
||||
if (mErrPrintWriter == null) {
|
||||
mErrPrintWriter = new PrintWriter(getRawErrorStream());
|
||||
}
|
||||
return mErrPrintWriter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the raw FileDescriptor for the input stream.
|
||||
*/
|
||||
public FileDescriptor getInFileDescriptor() {
|
||||
return mIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return direct raw access (not buffered) to the command's input data stream.
|
||||
*/
|
||||
public InputStream getRawInputStream() {
|
||||
if (mFileIn == null) {
|
||||
mFileIn = new FileInputStream(mIn);
|
||||
}
|
||||
return mFileIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return buffered access to the command's {@link #getRawInputStream()}.
|
||||
*/
|
||||
public InputStream getBufferedInputStream() {
|
||||
if (mInputStream == null) {
|
||||
mInputStream = new BufferedInputStream(getRawInputStream());
|
||||
}
|
||||
return mInputStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the next option on the command line -- that is an argument that
|
||||
* starts with '-'. If the next argument is not an option, null is returned.
|
||||
*/
|
||||
public String getNextOption() {
|
||||
if (mCurArgData != null) {
|
||||
String prev = mArgs[mArgPos - 1];
|
||||
throw new IllegalArgumentException("No argument expected after \"" + prev + "\"");
|
||||
}
|
||||
if (mArgPos >= mArgs.length) {
|
||||
return null;
|
||||
}
|
||||
String arg = mArgs[mArgPos];
|
||||
if (!arg.startsWith("-")) {
|
||||
return null;
|
||||
}
|
||||
mArgPos++;
|
||||
if (arg.equals("--")) {
|
||||
return null;
|
||||
}
|
||||
if (arg.length() > 1 && arg.charAt(1) != '-') {
|
||||
if (arg.length() > 2) {
|
||||
mCurArgData = arg.substring(2);
|
||||
return arg.substring(0, 2);
|
||||
} else {
|
||||
mCurArgData = null;
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
mCurArgData = null;
|
||||
return arg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the next argument on the command line, whatever it is; if there are
|
||||
* no arguments left, return null.
|
||||
*/
|
||||
public String getNextArg() {
|
||||
if (mCurArgData != null) {
|
||||
String arg = mCurArgData;
|
||||
mCurArgData = null;
|
||||
return arg;
|
||||
} else if (mArgPos < mArgs.length) {
|
||||
return mArgs[mArgPos++];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public String peekNextArg() {
|
||||
if (mCurArgData != null) {
|
||||
return mCurArgData;
|
||||
} else if (mArgPos < mArgs.length) {
|
||||
return mArgs[mArgPos];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of arguments that haven't been processed yet.
|
||||
*/
|
||||
public int getRemainingArgsCount() {
|
||||
if (mArgPos >= mArgs.length) {
|
||||
return 0;
|
||||
}
|
||||
return mArgs.length - mArgPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the next argument on the command line, whatever it is; if there are
|
||||
* no arguments left, throws an IllegalArgumentException to report this to the user.
|
||||
*/
|
||||
public String getNextArgRequired() {
|
||||
String arg = getNextArg();
|
||||
if (arg == null) {
|
||||
String prev = mArgs[mArgPos - 1];
|
||||
throw new IllegalArgumentException("Argument expected after \"" + prev + "\"");
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
public int handleDefaultCommands(String cmd) {
|
||||
if (cmd == null || "help".equals(cmd) || "-h".equals(cmd)) {
|
||||
onHelp();
|
||||
} else {
|
||||
getOutPrintWriter().println("Unknown command: " + cmd);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public Binder getTarget() {
|
||||
return mTarget;
|
||||
}
|
||||
|
||||
public String[] getAllArgs() {
|
||||
return mArgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement parsing and execution of a command. If it isn't a command you understand,
|
||||
* call {@link #handleDefaultCommands(String)} and return its result as a last resort.
|
||||
* Use {@link #getNextOption()}, {@link #getNextArg()}, and {@link #getNextArgRequired()}
|
||||
* to process additional command line arguments. Command output can be written to
|
||||
* {@link #getOutPrintWriter()} and errors to {@link #getErrPrintWriter()}.
|
||||
*
|
||||
* <p class="caution">Note that no permission checking has been done before entering this
|
||||
* function, so you need to be sure to do your own security verification for any commands you
|
||||
* are executing. The easiest way to do this is to have the ShellCommand contain
|
||||
* only a reference to your service's aidl interface, and do all of your command
|
||||
* implementations on top of that -- that way you can rely entirely on your executing security
|
||||
* code behind that interface.</p>
|
||||
*
|
||||
* @param cmd The first command line argument representing the name of the command to execute.
|
||||
* @return Return the command result; generally 0 or positive indicates success and
|
||||
* negative values indicate error.
|
||||
*/
|
||||
public abstract int onCommand(String cmd);
|
||||
|
||||
/**
|
||||
* Implement this to print help text about your command to {@link #getOutPrintWriter()}.
|
||||
*/
|
||||
public abstract void onHelp();
|
||||
}
|
||||
Reference in New Issue
Block a user