19461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn/*
29461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn * Copyright (C) 2015 The Android Open Source Project
39461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn *
49461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License");
59461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn * you may not use this file except in compliance with the License.
69461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn * You may obtain a copy of the License at
79461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn *
89461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn *      http://www.apache.org/licenses/LICENSE-2.0
99461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn *
109461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn * Unless required by applicable law or agreed to in writing, software
119461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS,
129461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn * See the License for the specific language governing permissions and
149461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn * limitations under the License.
159461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn */
169461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn
179461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackbornpackage android.os;
189461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn
199461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackbornimport android.util.Slog;
209461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackbornimport com.android.internal.util.FastPrintWriter;
219461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn
2272cfcd02b89838264b018e9b9417d2829c87b7e2Todd Kennedyimport java.io.BufferedInputStream;
239461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackbornimport java.io.FileDescriptor;
2472cfcd02b89838264b018e9b9417d2829c87b7e2Todd Kennedyimport java.io.FileInputStream;
259461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackbornimport java.io.FileOutputStream;
2672cfcd02b89838264b018e9b9417d2829c87b7e2Todd Kennedyimport java.io.InputStream;
272e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackbornimport java.io.OutputStream;
289461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackbornimport java.io.PrintWriter;
299461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn
309461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn/**
312e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn * Helper for implementing {@link Binder#onShellCommand Binder.onShellCommand}.
329461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn * @hide
339461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn */
349461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackbornpublic abstract class ShellCommand {
359461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    static final String TAG = "ShellCommand";
369461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    static final boolean DEBUG = false;
379461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn
389461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    private Binder mTarget;
399461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    private FileDescriptor mIn;
409461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    private FileDescriptor mOut;
419461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    private FileDescriptor mErr;
429461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    private String[] mArgs;
439461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    private ResultReceiver mResultReceiver;
449461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn
459461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    private String mCmd;
469461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    private int mArgPos;
479461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    private String mCurArgData;
489461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn
492e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn    private FileInputStream mFileIn;
502e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn    private FileOutputStream mFileOut;
512e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn    private FileOutputStream mFileErr;
522e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn
539461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    private FastPrintWriter mOutPrintWriter;
549461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    private FastPrintWriter mErrPrintWriter;
5572cfcd02b89838264b018e9b9417d2829c87b7e2Todd Kennedy    private InputStream mInputStream;
569461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn
573cdb56efea044112bfe1b97b3ed78ee05e0dba46Dianne Hackborn    public void init(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err,
583cdb56efea044112bfe1b97b3ed78ee05e0dba46Dianne Hackborn            String[] args, int firstArgPos) {
599461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        mTarget = target;
609461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        mIn = in;
619461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        mOut = out;
629461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        mErr = err;
639461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        mArgs = args;
643cdb56efea044112bfe1b97b3ed78ee05e0dba46Dianne Hackborn        mResultReceiver = null;
653cdb56efea044112bfe1b97b3ed78ee05e0dba46Dianne Hackborn        mCmd = null;
663cdb56efea044112bfe1b97b3ed78ee05e0dba46Dianne Hackborn        mArgPos = firstArgPos;
679461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        mCurArgData = null;
682e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn        mFileIn = null;
692e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn        mFileOut = null;
702e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn        mFileErr = null;
719461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        mOutPrintWriter = null;
729461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        mErrPrintWriter = null;
732e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn        mInputStream = null;
743cdb56efea044112bfe1b97b3ed78ee05e0dba46Dianne Hackborn    }
753cdb56efea044112bfe1b97b3ed78ee05e0dba46Dianne Hackborn
763cdb56efea044112bfe1b97b3ed78ee05e0dba46Dianne Hackborn    public int exec(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err,
773cdb56efea044112bfe1b97b3ed78ee05e0dba46Dianne Hackborn            String[] args, ResultReceiver resultReceiver) {
783cdb56efea044112bfe1b97b3ed78ee05e0dba46Dianne Hackborn        String cmd;
793cdb56efea044112bfe1b97b3ed78ee05e0dba46Dianne Hackborn        int start;
803cdb56efea044112bfe1b97b3ed78ee05e0dba46Dianne Hackborn        if (args != null && args.length > 0) {
813cdb56efea044112bfe1b97b3ed78ee05e0dba46Dianne Hackborn            cmd = args[0];
823cdb56efea044112bfe1b97b3ed78ee05e0dba46Dianne Hackborn            start = 1;
833cdb56efea044112bfe1b97b3ed78ee05e0dba46Dianne Hackborn        } else {
843cdb56efea044112bfe1b97b3ed78ee05e0dba46Dianne Hackborn            cmd = null;
853cdb56efea044112bfe1b97b3ed78ee05e0dba46Dianne Hackborn            start = 0;
863cdb56efea044112bfe1b97b3ed78ee05e0dba46Dianne Hackborn        }
873cdb56efea044112bfe1b97b3ed78ee05e0dba46Dianne Hackborn        init(target, in, out, err, args, start);
883cdb56efea044112bfe1b97b3ed78ee05e0dba46Dianne Hackborn        mCmd = cmd;
893cdb56efea044112bfe1b97b3ed78ee05e0dba46Dianne Hackborn        mResultReceiver = resultReceiver;
909461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn
919461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        if (DEBUG) Slog.d(TAG, "Starting command " + mCmd + " on " + mTarget);
929461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        int res = -1;
939461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        try {
949461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            res = onCommand(mCmd);
959461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            if (DEBUG) Slog.d(TAG, "Executed command " + mCmd + " on " + mTarget);
969461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        } catch (SecurityException e) {
979461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            PrintWriter eout = getErrPrintWriter();
989461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            eout.println("Security exception: " + e.getMessage());
999461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            eout.println();
1009461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            e.printStackTrace(eout);
1019461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        } catch (Throwable e) {
1029461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            // Unlike usual calls, in this case if an exception gets thrown
1039461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            // back to us we want to print it back in to the dump data, since
1049461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            // that is where the caller expects all interesting information to
1059461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            // go.
1069461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            PrintWriter eout = getErrPrintWriter();
1079461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            eout.println();
1089461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            eout.println("Exception occurred while dumping:");
1099461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            e.printStackTrace(eout);
1109461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        } finally {
1119461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            if (DEBUG) Slog.d(TAG, "Flushing output streams on " + mTarget);
1129461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            if (mOutPrintWriter != null) {
1139461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn                mOutPrintWriter.flush();
1149461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            }
1159461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            if (mErrPrintWriter != null) {
1169461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn                mErrPrintWriter.flush();
1179461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            }
1189461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            if (DEBUG) Slog.d(TAG, "Sending command result on " + mTarget);
1199461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            mResultReceiver.send(res, null);
1209461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        }
1219461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        if (DEBUG) Slog.d(TAG, "Finished command " + mCmd + " on " + mTarget);
1222e44107bf7d9ad97833933422ccd241bf53ff50cDianne Hackborn        return res;
1239461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    }
1249461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn
1252e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn    /**
1262e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     * Return direct raw access (not buffered) to the command's output data stream.
1272e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     */
1282e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn    public OutputStream getRawOutputStream() {
1292e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn        if (mFileOut == null) {
1302e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn            mFileOut = new FileOutputStream(mOut);
1312e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn        }
1322e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn        return mFileOut;
1332e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn    }
1342e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn
1352e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn    /**
1362e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     * Return a PrintWriter for formatting output to {@link #getRawOutputStream()}.
1372e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     */
1389461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    public PrintWriter getOutPrintWriter() {
1399461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        if (mOutPrintWriter == null) {
1402e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn            mOutPrintWriter = new FastPrintWriter(getRawOutputStream());
1419461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        }
1429461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        return mOutPrintWriter;
1439461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    }
1449461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn
1452e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn    /**
1462e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     * Return direct raw access (not buffered) to the command's error output data stream.
1472e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     */
1482e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn    public OutputStream getRawErrorStream() {
1492e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn        if (mFileErr == null) {
1502e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn            mFileErr = new FileOutputStream(mErr);
1512e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn        }
1522e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn        return mFileErr;
1532e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn    }
1542e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn
1552e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn    /**
1562e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     * Return a PrintWriter for formatting output to {@link #getRawErrorStream()}.
1572e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     */
1589461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    public PrintWriter getErrPrintWriter() {
1599461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        if (mErr == null) {
1609461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            return getOutPrintWriter();
1619461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        }
1629461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        if (mErrPrintWriter == null) {
1632e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn            mErrPrintWriter = new FastPrintWriter(getRawErrorStream());
1649461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        }
1659461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        return mErrPrintWriter;
1669461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    }
1679461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn
1682e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn    /**
1692e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     * Return direct raw access (not buffered) to the command's input data stream.
1702e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     */
1712e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn    public InputStream getRawInputStream() {
1722e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn        if (mFileIn == null) {
1732e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn            mFileIn = new FileInputStream(mIn);
1742e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn        }
1752e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn        return mFileIn;
1762e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn    }
1772e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn
1782e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn    /**
1792e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     * Return buffered access to the command's {@link #getRawInputStream()}.
1802e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     */
1812e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn    public InputStream getBufferedInputStream() {
18272cfcd02b89838264b018e9b9417d2829c87b7e2Todd Kennedy        if (mInputStream == null) {
1832e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn            mInputStream = new BufferedInputStream(getRawInputStream());
18472cfcd02b89838264b018e9b9417d2829c87b7e2Todd Kennedy        }
18572cfcd02b89838264b018e9b9417d2829c87b7e2Todd Kennedy        return mInputStream;
18672cfcd02b89838264b018e9b9417d2829c87b7e2Todd Kennedy    }
18772cfcd02b89838264b018e9b9417d2829c87b7e2Todd Kennedy
1889461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    /**
1899461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn     * Return the next option on the command line -- that is an argument that
1909461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn     * starts with '-'.  If the next argument is not an option, null is returned.
1919461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn     */
1929461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    public String getNextOption() {
1939461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        if (mCurArgData != null) {
1949461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            String prev = mArgs[mArgPos - 1];
1959461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            throw new IllegalArgumentException("No argument expected after \"" + prev + "\"");
1969461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        }
1979461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        if (mArgPos >= mArgs.length) {
1989461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            return null;
1999461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        }
2009461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        String arg = mArgs[mArgPos];
2019461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        if (!arg.startsWith("-")) {
2029461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            return null;
2039461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        }
2049461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        mArgPos++;
2059461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        if (arg.equals("--")) {
2069461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            return null;
2079461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        }
2089461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        if (arg.length() > 1 && arg.charAt(1) != '-') {
2099461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            if (arg.length() > 2) {
2109461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn                mCurArgData = arg.substring(2);
2119461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn                return arg.substring(0, 2);
2129461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            } else {
2139461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn                mCurArgData = null;
2149461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn                return arg;
2159461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            }
2169461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        }
2179461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        mCurArgData = null;
2189461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        return arg;
2199461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    }
2209461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn
2219461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    /**
2229461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn     * Return the next argument on the command line, whatever it is; if there are
2239461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn     * no arguments left, return null.
2249461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn     */
2259461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    public String getNextArg() {
2269461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        if (mCurArgData != null) {
2279461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            String arg = mCurArgData;
2289461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            mCurArgData = null;
2299461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            return arg;
2309461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        } else if (mArgPos < mArgs.length) {
2319461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            return mArgs[mArgPos++];
2329461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        } else {
2339461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            return null;
2349461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        }
2359461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    }
2369461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn
237c17d8b79afd02133b021d89b536c812578308329Filip Gruszczynski    public String peekNextArg() {
238c17d8b79afd02133b021d89b536c812578308329Filip Gruszczynski        if (mCurArgData != null) {
239c17d8b79afd02133b021d89b536c812578308329Filip Gruszczynski            return mCurArgData;
240c17d8b79afd02133b021d89b536c812578308329Filip Gruszczynski        } else if (mArgPos < mArgs.length) {
241c17d8b79afd02133b021d89b536c812578308329Filip Gruszczynski            return mArgs[mArgPos];
242c17d8b79afd02133b021d89b536c812578308329Filip Gruszczynski        } else {
243c17d8b79afd02133b021d89b536c812578308329Filip Gruszczynski            return null;
244c17d8b79afd02133b021d89b536c812578308329Filip Gruszczynski        }
245c17d8b79afd02133b021d89b536c812578308329Filip Gruszczynski    }
246c17d8b79afd02133b021d89b536c812578308329Filip Gruszczynski
2479461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    /**
2489461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn     * Return the next argument on the command line, whatever it is; if there are
2499461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn     * no arguments left, throws an IllegalArgumentException to report this to the user.
2509461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn     */
2519461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    public String getNextArgRequired() {
2529461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        String arg = getNextArg();
2539461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        if (arg == null) {
2549461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            String prev = mArgs[mArgPos - 1];
2559461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            throw new IllegalArgumentException("Argument expected after \"" + prev + "\"");
2569461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        }
2579461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        return arg;
2589461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    }
2599461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn
2609461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    public int handleDefaultCommands(String cmd) {
2619461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        if ("dump".equals(cmd)) {
2629461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            String[] newArgs = new String[mArgs.length-1];
2639461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            System.arraycopy(mArgs, 1, newArgs, 0, mArgs.length-1);
2649461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            mTarget.doDump(mOut, getOutPrintWriter(), newArgs);
2659461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            return 0;
2669461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        } else if (cmd == null || "help".equals(cmd) || "-h".equals(cmd)) {
2679461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            onHelp();
2689461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        } else {
2699461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn            getOutPrintWriter().println("Unknown command: " + cmd);
2709461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        }
2719461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn        return -1;
2729461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    }
2739461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn
2742e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn    /**
2752e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     * Implement parsing and execution of a command.  If it isn't a command you understand,
2762e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     * call {@link #handleDefaultCommands(String)} and return its result as a last resort.
2772e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     * User {@link #getNextOption()}, {@link #getNextArg()}, and {@link #getNextArgRequired()}
2782e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     * to process additional command line arguments.  Command output can be written to
2792e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     * {@link #getOutPrintWriter()} and errors to {@link #getErrPrintWriter()}.
2802e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     *
2812e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     * <p class="caution">Note that no permission checking has been done before entering this function,
2822e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     * so you need to be sure to do your own security verification for any commands you
2832e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     * are executing.  The easiest way to do this is to have the ShellCommand contain
2842e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     * only a reference to your service's aidl interface, and do all of your command
2852e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     * implementations on top of that -- that way you can rely entirely on your executing security
2862e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     * code behind that interface.</p>
2872e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     *
2882e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     * @param cmd The first command line argument representing the name of the command to execute.
2892e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     * @return Return the command result; generally 0 or positive indicates success and
2902e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     * negative values indicate error.
2912e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     */
2929461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    public abstract int onCommand(String cmd);
2939461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn
2942e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn    /**
2952e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     * Implement this to print help text about your command to {@link #getOutPrintWriter()}.
2962e931f56c77cf53df9daf99d5afdd7bc4c109a54Dianne Hackborn     */
2979461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn    public abstract void onHelp();
2989461b6f91f37fd32207da1bd734d9ea9629eb8e5Dianne Hackborn}
299