Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 79f7ec70 authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Have audio service clean up new receivers in crashing processes.

The new media button receiver with only a pending intent (no
component name) could be left hanging if the process that
registered it went away.  These semantically need to be tied
to the calling process's lifetime; we now clean them up when
the calling process goes away.

Also added some additional cleanup of media button receivers
when packages change (updated, cleared).

And on top of that, a new "media" command for doing media
things.  Currently lets you send media keys and monitor
remote display data.

Oh and finally added a new BaseCommand base class for
implementing these command line utilities.

Change-Id: Iba1d56f10bab1eec4a94a7bb1d1c2ae614c8bcf5
parent bab9687e
Loading
Loading
Loading
Loading
+145 −216
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ import android.os.SystemProperties;
import android.os.UserHandle;
import android.util.AndroidException;
import android.view.IWindowManager;
import com.android.internal.os.BaseCommand;

import java.io.BufferedReader;
import java.io.File;
@@ -50,12 +51,9 @@ import java.net.URISyntaxException;
import java.util.HashSet;
import java.util.List;

public class Am {
public class Am extends BaseCommand {

    private IActivityManager mAm;
    private String[] mArgs;
    private int mNextArg;
    private String mCurArgData;

    private int mStartFlags = 0;
    private boolean mWaitOption = false;
@@ -67,43 +65,163 @@ public class Am {

    private String mProfileFile;

    // These are magic strings understood by the Eclipse plugin.
    private static final String FATAL_ERROR_CODE = "Error type 1";
    private static final String NO_SYSTEM_ERROR_CODE = "Error type 2";
    private static final String NO_CLASS_ERROR_CODE = "Error type 3";

    /**
     * Command-line entry point.
     *
     * @param args The command-line arguments
     */
    public static void main(String[] args) {
        try {
        (new Am()).run(args);
        } catch (IllegalArgumentException e) {
            showUsage();
            System.err.println("Error: " + e.getMessage());
        } catch (Exception e) {
            e.printStackTrace(System.err);
            System.exit(1);
        }
    }

    private void run(String[] args) throws Exception {
        if (args.length < 1) {
            showUsage();
            return;
    public void onShowUsage(PrintStream out) {
        out.println(
                "usage: am [subcommand] [options]\n" +
                "usage: am start [-D] [-W] [-P <FILE>] [--start-profiler <FILE>]\n" +
                "               [--R COUNT] [-S] [--opengl-trace]\n" +
                "               [--user <USER_ID> | current] <INTENT>\n" +
                "       am startservice [--user <USER_ID> | current] <INTENT>\n" +
                "       am force-stop [--user <USER_ID> | all | current] <PACKAGE>\n" +
                "       am kill [--user <USER_ID> | all | current] <PACKAGE>\n" +
                "       am kill-all\n" +
                "       am broadcast [--user <USER_ID> | all | current] <INTENT>\n" +
                "       am instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]\n" +
                "               [--user <USER_ID> | current]\n" +
                "               [--no-window-animation] <COMPONENT>\n" +
                "       am profile start [--user <USER_ID> current] <PROCESS> <FILE>\n" +
                "       am profile stop [--user <USER_ID> current] [<PROCESS>]\n" +
                "       am dumpheap [--user <USER_ID> current] [-n] <PROCESS> <FILE>\n" +
                "       am set-debug-app [-w] [--persistent] <PACKAGE>\n" +
                "       am clear-debug-app\n" +
                "       am monitor [--gdb <port>]\n" +
                "       am screen-compat [on|off] <PACKAGE>\n" +
                "       am to-uri [INTENT]\n" +
                "       am to-intent-uri [INTENT]\n" +
                "       am switch-user <USER_ID>\n" +
                "       am stop-user <USER_ID>\n" +
                "\n" +
                "am start: start an Activity.  Options are:\n" +
                "    -D: enable debugging\n" +
                "    -W: wait for launch to complete\n" +
                "    --start-profiler <FILE>: start profiler and send results to <FILE>\n" +
                "    -P <FILE>: like above, but profiling stops when app goes idle\n" +
                "    -R: repeat the activity launch <COUNT> times.  Prior to each repeat,\n" +
                "        the top activity will be finished.\n" +
                "    -S: force stop the target app before starting the activity\n" +
                "    --opengl-trace: enable tracing of OpenGL functions\n" +
                "    --user <USER_ID> | current: Specify which user to run as; if not\n" +
                "        specified then run as the current user.\n" +
                "\n" +
                "am startservice: start a Service.  Options are:\n" +
                "    --user <USER_ID> | current: Specify which user to run as; if not\n" +
                "        specified then run as the current user.\n" +
                "\n" +
                "am force-stop: force stop everything associated with <PACKAGE>.\n" +
                "    --user <USER_ID> | all | current: Specify user to force stop;\n" +
                "        all users if not specified.\n" +
                "\n" +
                "am kill: Kill all processes associated with <PACKAGE>.  Only kills.\n" +
                "  processes that are safe to kill -- that is, will not impact the user\n" +
                "  experience.\n" +
                "    --user <USER_ID> | all | current: Specify user whose processes to kill;\n" +
                "        all users if not specified.\n" +
                "\n" +
                "am kill-all: Kill all background processes.\n" +
                "\n" +
                "am broadcast: send a broadcast Intent.  Options are:\n" +
                "    --user <USER_ID> | all | current: Specify which user to send to; if not\n" +
                "        specified then send to all users.\n" +
                "    --receiver-permission <PERMISSION>: Require receiver to hold permission.\n" +
                "\n" +
                "am instrument: start an Instrumentation.  Typically this target <COMPONENT>\n" +
                "  is the form <TEST_PACKAGE>/<RUNNER_CLASS>.  Options are:\n" +
                "    -r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT).  Use with\n" +
                "        [-e perf true] to generate raw output for performance measurements.\n" +
                "    -e <NAME> <VALUE>: set argument <NAME> to <VALUE>.  For test runners a\n" +
                "        common form is [-e <testrunner_flag> <value>[,<value>...]].\n" +
                "    -p <FILE>: write profiling data to <FILE>\n" +
                "    -w: wait for instrumentation to finish before returning.  Required for\n" +
                "        test runners.\n" +
                "    --user <USER_ID> | current: Specify user instrumentation runs in;\n" +
                "        current user if not specified.\n" +
                "    --no-window-animation: turn off window animations will running.\n" +
                "\n" +
                "am profile: start and stop profiler on a process.  The given <PROCESS> argument\n" +
                "  may be either a process name or pid.  Options are:\n" +
                "    --user <USER_ID> | current: When supplying a process name,\n" +
                "        specify user of process to profile; uses current user if not specified.\n" +
                "\n" +
                "am dumpheap: dump the heap of a process.  The given <PROCESS> argument may\n" +
                "  be either a process name or pid.  Options are:\n" +
                "    -n: dump native heap instead of managed heap\n" +
                "    --user <USER_ID> | current: When supplying a process name,\n" +
                "        specify user of process to dump; uses current user if not specified.\n" +
                "\n" +
                "am set-debug-app: set application <PACKAGE> to debug.  Options are:\n" +
                "    -w: wait for debugger when application starts\n" +
                "    --persistent: retain this value\n" +
                "\n" +
                "am clear-debug-app: clear the previously set-debug-app.\n" +
                "\n" +
                "am bug-report: request bug report generation; will launch UI\n" +
                "    when done to select where it should be delivered.\n" +
                "\n" +
                "am monitor: start monitoring for crashes or ANRs.\n" +
                "    --gdb: start gdbserv on the given port at crash/ANR\n" +
                "\n" +
                "am screen-compat: control screen compatibility mode of <PACKAGE>.\n" +
                "\n" +
                "am to-uri: print the given Intent specification as a URI.\n" +
                "\n" +
                "am to-intent-uri: print the given Intent specification as an intent: URI.\n" +
                "\n" +
                "am switch-user: switch to put USER_ID in the foreground, starting\n" +
                "  execution of that user if it is currently stopped.\n" +
                "\n" +
                "am stop-user: stop execution of USER_ID, not allowing it to run any\n" +
                "  code until a later explicit switch to it.\n" +
                "\n" +
                "<INTENT> specifications include these flags and arguments:\n" +
                "    [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
                "    [-c <CATEGORY> [-c <CATEGORY>] ...]\n" +
                "    [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]\n" +
                "    [--esn <EXTRA_KEY> ...]\n" +
                "    [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]\n" +
                "    [--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" +
                "    [--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]\n" +
                "    [--ef <EXTRA_KEY> <EXTRA_FLOAT_VALUE> ...]\n" +
                "    [--eu <EXTRA_KEY> <EXTRA_URI_VALUE> ...]\n" +
                "    [--ecn <EXTRA_KEY> <EXTRA_COMPONENT_NAME_VALUE>]\n" +
                "    [--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]\n" +
                "    [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" +
                "    [--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]\n" +
                "    [-n <COMPONENT>] [-f <FLAGS>]\n" +
                "    [--grant-read-uri-permission] [--grant-write-uri-permission]\n" +
                "    [--debug-log-resolution] [--exclude-stopped-packages]\n" +
                "    [--include-stopped-packages]\n" +
                "    [--activity-brought-to-front] [--activity-clear-top]\n" +
                "    [--activity-clear-when-task-reset] [--activity-exclude-from-recents]\n" +
                "    [--activity-launched-from-history] [--activity-multiple-task]\n" +
                "    [--activity-no-animation] [--activity-no-history]\n" +
                "    [--activity-no-user-action] [--activity-previous-is-top]\n" +
                "    [--activity-reorder-to-front] [--activity-reset-task-if-needed]\n" +
                "    [--activity-single-top] [--activity-clear-task]\n" +
                "    [--activity-task-on-home]\n" +
                "    [--receiver-registered-only] [--receiver-replace-pending]\n" +
                "    [--selector]\n" +
                "    [<URI> | <PACKAGE> | <COMPONENT>]\n"
                );
    }

    public void onRun() throws Exception {

        mAm = ActivityManagerNative.getDefault();
        if (mAm == null) {
            System.err.println(NO_SYSTEM_ERROR_CODE);
            throw new AndroidException("Can't connect to activity manager; is the system running?");
        }

        mArgs = args;
        String op = args[0];
        mNextArg = 1;
        String op = nextArgRequired();

        if (op.equals("start")) {
            runStart();
@@ -142,7 +260,7 @@ public class Am {
        } else if (op.equals("stop-user")) {
            runStopUser();
        } else {
            throw new IllegalArgumentException("Unknown command: " + op);
            showError("Error: unknown command '" + op + "'");
        }
    }

@@ -1303,193 +1421,4 @@ public class Am {
            return true;
        }
    }

    private String nextOption() {
        if (mCurArgData != null) {
            String prev = mArgs[mNextArg - 1];
            throw new IllegalArgumentException("No argument expected after \"" + prev + "\"");
        }
        if (mNextArg >= mArgs.length) {
            return null;
        }
        String arg = mArgs[mNextArg];
        if (!arg.startsWith("-")) {
            return null;
        }
        mNextArg++;
        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;
    }

    private String nextArg() {
        if (mCurArgData != null) {
            String arg = mCurArgData;
            mCurArgData = null;
            return arg;
        } else if (mNextArg < mArgs.length) {
            return mArgs[mNextArg++];
        } else {
            return null;
        }
    }

    private String nextArgRequired() {
        String arg = nextArg();
        if (arg == null) {
            String prev = mArgs[mNextArg - 1];
            throw new IllegalArgumentException("Argument expected after \"" + prev + "\"");
        }
        return arg;
    }

    private static void showUsage() {
        System.err.println(
                "usage: am [subcommand] [options]\n" +
                "usage: am start [-D] [-W] [-P <FILE>] [--start-profiler <FILE>]\n" +
                "               [--R COUNT] [-S] [--opengl-trace]\n" +
                "               [--user <USER_ID> | current] <INTENT>\n" +
                "       am startservice [--user <USER_ID> | current] <INTENT>\n" +
                "       am force-stop [--user <USER_ID> | all | current] <PACKAGE>\n" +
                "       am kill [--user <USER_ID> | all | current] <PACKAGE>\n" +
                "       am kill-all\n" +
                "       am broadcast [--user <USER_ID> | all | current] <INTENT>\n" +
                "       am instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]\n" +
                "               [--user <USER_ID> | current]\n" +
                "               [--no-window-animation] <COMPONENT>\n" +
                "       am profile start [--user <USER_ID> current] <PROCESS> <FILE>\n" +
                "       am profile stop [--user <USER_ID> current] [<PROCESS>]\n" +
                "       am dumpheap [--user <USER_ID> current] [-n] <PROCESS> <FILE>\n" +
                "       am set-debug-app [-w] [--persistent] <PACKAGE>\n" +
                "       am clear-debug-app\n" +
                "       am monitor [--gdb <port>]\n" +
                "       am screen-compat [on|off] <PACKAGE>\n" +
                "       am to-uri [INTENT]\n" +
                "       am to-intent-uri [INTENT]\n" +
                "       am switch-user <USER_ID>\n" +
                "       am stop-user <USER_ID>\n" +
                "\n" +
                "am start: start an Activity.  Options are:\n" +
                "    -D: enable debugging\n" +
                "    -W: wait for launch to complete\n" +
                "    --start-profiler <FILE>: start profiler and send results to <FILE>\n" +
                "    -P <FILE>: like above, but profiling stops when app goes idle\n" +
                "    -R: repeat the activity launch <COUNT> times.  Prior to each repeat,\n" +
                "        the top activity will be finished.\n" +
                "    -S: force stop the target app before starting the activity\n" +
                "    --opengl-trace: enable tracing of OpenGL functions\n" +
                "    --user <USER_ID> | current: Specify which user to run as; if not\n" +
                "        specified then run as the current user.\n" +
                "\n" +
                "am startservice: start a Service.  Options are:\n" +
                "    --user <USER_ID> | current: Specify which user to run as; if not\n" +
                "        specified then run as the current user.\n" +
                "\n" +
                "am force-stop: force stop everything associated with <PACKAGE>.\n" +
                "    --user <USER_ID> | all | current: Specify user to force stop;\n" +
                "        all users if not specified.\n" +
                "\n" +
                "am kill: Kill all processes associated with <PACKAGE>.  Only kills.\n" +
                "  processes that are safe to kill -- that is, will not impact the user\n" +
                "  experience.\n" +
                "    --user <USER_ID> | all | current: Specify user whose processes to kill;\n" +
                "        all users if not specified.\n" +
                "\n" +
                "am kill-all: Kill all background processes.\n" +
                "\n" +
                "am broadcast: send a broadcast Intent.  Options are:\n" +
                "    --user <USER_ID> | all | current: Specify which user to send to; if not\n" +
                "        specified then send to all users.\n" +
                "    --receiver-permission <PERMISSION>: Require receiver to hold permission.\n" +
                "\n" +
                "am instrument: start an Instrumentation.  Typically this target <COMPONENT>\n" +
                "  is the form <TEST_PACKAGE>/<RUNNER_CLASS>.  Options are:\n" +
                "    -r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT).  Use with\n" +
                "        [-e perf true] to generate raw output for performance measurements.\n" +
                "    -e <NAME> <VALUE>: set argument <NAME> to <VALUE>.  For test runners a\n" +
                "        common form is [-e <testrunner_flag> <value>[,<value>...]].\n" +
                "    -p <FILE>: write profiling data to <FILE>\n" +
                "    -w: wait for instrumentation to finish before returning.  Required for\n" +
                "        test runners.\n" +
                "    --user <USER_ID> | current: Specify user instrumentation runs in;\n" +
                "        current user if not specified.\n" +
                "    --no-window-animation: turn off window animations will running.\n" +
                "\n" +
                "am profile: start and stop profiler on a process.  The given <PROCESS> argument\n" +
                "  may be either a process name or pid.  Options are:\n" +
                "    --user <USER_ID> | current: When supplying a process name,\n" +
                "        specify user of process to profile; uses current user if not specified.\n" +
                "\n" +
                "am dumpheap: dump the heap of a process.  The given <PROCESS> argument may\n" +
                "  be either a process name or pid.  Options are:\n" +
                "    -n: dump native heap instead of managed heap\n" +
                "    --user <USER_ID> | current: When supplying a process name,\n" +
                "        specify user of process to dump; uses current user if not specified.\n" +
                "\n" +
                "am set-debug-app: set application <PACKAGE> to debug.  Options are:\n" +
                "    -w: wait for debugger when application starts\n" +
                "    --persistent: retain this value\n" +
                "\n" +
                "am clear-debug-app: clear the previously set-debug-app.\n" +
                "\n" +
                "am bug-report: request bug report generation; will launch UI\n" +
                "    when done to select where it should be delivered.\n" +
                "\n" +
                "am monitor: start monitoring for crashes or ANRs.\n" +
                "    --gdb: start gdbserv on the given port at crash/ANR\n" +
                "\n" +
                "am screen-compat: control screen compatibility mode of <PACKAGE>.\n" +
                "\n" +
                "am to-uri: print the given Intent specification as a URI.\n" +
                "\n" +
                "am to-intent-uri: print the given Intent specification as an intent: URI.\n" +
                "\n" +
                "am switch-user: switch to put USER_ID in the foreground, starting\n" +
                "  execution of that user if it is currently stopped.\n" +
                "\n" +
                "am stop-user: stop execution of USER_ID, not allowing it to run any\n" +
                "  code until a later explicit switch to it.\n" +
                "\n" +
                "<INTENT> specifications include these flags and arguments:\n" +
                "    [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
                "    [-c <CATEGORY> [-c <CATEGORY>] ...]\n" +
                "    [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]\n" +
                "    [--esn <EXTRA_KEY> ...]\n" +
                "    [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]\n" +
                "    [--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" +
                "    [--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]\n" +
                "    [--ef <EXTRA_KEY> <EXTRA_FLOAT_VALUE> ...]\n" +
                "    [--eu <EXTRA_KEY> <EXTRA_URI_VALUE> ...]\n" +
                "    [--ecn <EXTRA_KEY> <EXTRA_COMPONENT_NAME_VALUE>]\n" +
                "    [--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]\n" +
                "    [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" +
                "    [--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]\n" +
                "    [-n <COMPONENT>] [-f <FLAGS>]\n" +
                "    [--grant-read-uri-permission] [--grant-write-uri-permission]\n" +
                "    [--debug-log-resolution] [--exclude-stopped-packages]\n" +
                "    [--include-stopped-packages]\n" +
                "    [--activity-brought-to-front] [--activity-clear-top]\n" +
                "    [--activity-clear-when-task-reset] [--activity-exclude-from-recents]\n" +
                "    [--activity-launched-from-history] [--activity-multiple-task]\n" +
                "    [--activity-no-animation] [--activity-no-history]\n" +
                "    [--activity-no-user-action] [--activity-previous-is-top]\n" +
                "    [--activity-reorder-to-front] [--activity-reset-task-if-needed]\n" +
                "    [--activity-single-top] [--activity-clear-task]\n" +
                "    [--activity-task-on-home]\n" +
                "    [--receiver-registered-only] [--receiver-replace-pending]\n" +
                "    [--selector]\n" +
                "    [<URI> | <PACKAGE> | <COMPONENT>]\n"
                );
    }
}

cmds/media/Android.mk

0 → 100644
+15 −0
Original line number Diff line number Diff line
# Copyright 2013 The Android Open Source Project
#
LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_MODULE := media_cmd
include $(BUILD_JAVA_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := media
LOCAL_SRC_FILES := media
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_MODULE_TAGS := optional
include $(BUILD_PREBUILT)
+0 −0

Empty file added.

cmds/media/NOTICE

0 → 100644
+190 −0

File added.

Preview size limit exceeded, changes collapsed.

cmds/media/media

0 → 100755
+6 −0
Original line number Diff line number Diff line
# Script to start "media_cmd" on the device, which has a very rudimentary
# shell.
#
base=/system
export CLASSPATH=$base/framework/media_cmd.jar
exec app_process $base/bin com.android.commands.media.Media "$@"
Loading