025android初级篇之Android am命令的实现

025android初级篇之Android am命令的实现

am命令一个重要的调试工具,主要功能包括如下:
启动停止Activity Service,启动Broadcast, 查看管理这些信息。

am命令

am命令本身是一个shell脚本,具体内容如下:

#!/system/bin/sh
#
# Script to start "am" on the device, which has a very rudimentary
# shell.
#
base=/system
export CLASSPATH=$base/framework/am.jar
exec app_process $base/bin com.android.commands.am.Am "$@"

在android中可以使用app_process命令启动java的程序,使其在虚拟机中运行。

命令使用

usage: am [subcommand] [options]
usage: am start [-D] [-W] [-P ] [--start-profiler ]
               [--sampling INTERVAL] [-R COUNT] [-S] [--opengl-trace]
               [--user  | current] 
       am startservice [--user  | current] 
       am stopservice [--user  | current] 
       am force-stop [--user  | all | current] 
       am kill [--user  | all | current] 
       am kill-all
       am broadcast [--user  | all | current] 
       am instrument [-r] [-e  ] [-p ] [-w]
               [--user  | current]
               [--no-window-animation] [--abi ] 
       am profile start [--user  current]  
       am profile stop [--user  current] []
       am dumpheap [--user  current] [-n]  
       am set-debug-app [-w] [--persistent] 
       am clear-debug-app
       am monitor [--gdb ]
       am hang [--allow-restart]
       am restart
       am idle-maintenance
       am screen-compat [on|off] 
       am to-uri [INTENT]
       am to-intent-uri [INTENT]
       am to-app-uri [INTENT]
       am switch-user 
       am start-user 
       am stop-user 
       am stack start  
       am stack movetask   [true|false]
       am stack resize  
       am stack list
       am stack info 
       am lock-task 
       am lock-task stop
       am get-config

am start: start an Activity.  Options are:
    -D: enable debugging
    -W: wait for launch to complete
    --start-profiler : start profiler and send results to 
    --sampling INTERVAL: use sample profiling with INTERVAL microseconds
        between samples (use with --start-profiler)
    -P : like above, but profiling stops when app goes idle
    -R: repeat the activity launch  times.  Prior to each repeat,
        the top activity will be finished.
    -S: force stop the target app before starting the activity
    --opengl-trace: enable tracing of OpenGL functions
    --user  | current: Specify which user to run as; if not
        specified then run as the current user.

am startservice: start a Service.  Options are:
    --user  | current: Specify which user to run as; if not
        specified then run as the current user.

am stopservice: stop a Service.  Options are:
    --user  | current: Specify which user to run as; if not
        specified then run as the current user.

am force-stop: force stop everything associated with .
    --user  | all | current: Specify user to force stop;
        all users if not specified.

am kill: Kill all processes associated with .  Only kills.
  processes that are safe to kill -- that is, will not impact the user
  experience.
    --user  | all | current: Specify user whose processes to kill;
        all users if not specified.

am kill-all: Kill all background processes.

am broadcast: send a broadcast Intent.  Options are:
    --user  | all | current: Specify which user to send to; if not
        specified then send to all users.
    --receiver-permission : Require receiver to hold permission.

am instrument: start an Instrumentation.  Typically this target 
  is the form /.  Options are:
    -r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT).  Use with
        [-e perf true] to generate raw output for performance measurements.
    -e  : set argument  to .  For test runners a
        common form is [-e  [,...]].
    -p : write profiling data to 
    -w: wait for instrumentation to finish before returning.  Required for
        test runners.
    --user  | current: Specify user instrumentation runs in;
        current user if not specified.
    --no-window-animation: turn off window animations while running.
    --abi : Launch the instrumented process with the selected ABI.
        This assumes that the process supports the selected ABI.

am profile: start and stop profiler on a process.  The given  argument
  may be either a process name or pid.  Options are:
    --user  | current: When supplying a process name,
        specify user of process to profile; uses current user if not specified.

am dumpheap: dump the heap of a process.  The given  argument may
  be either a process name or pid.  Options are:
    -n: dump native heap instead of managed heap
    --user  | current: When supplying a process name,
        specify user of process to dump; uses current user if not specified.

am set-debug-app: set application  to debug.  Options are:
    -w: wait for debugger when application starts
    --persistent: retain this value

am clear-debug-app: clear the previously set-debug-app.

am bug-report: request bug report generation; will launch UI
    when done to select where it should be delivered.

am monitor: start monitoring for crashes or ANRs.
    --gdb: start gdbserv on the given port at crash/ANR

am hang: hang the system.
    --allow-restart: allow watchdog to perform normal system restart

am restart: restart the user-space system.

am idle-maintenance: perform idle maintenance now.

am screen-compat: control screen compatibility mode of .

am to-uri: print the given Intent specification as a URI.

am to-intent-uri: print the given Intent specification as an intent: URI.

am to-app-uri: print the given Intent specification as an android-app: URI.

am switch-user: switch to put USER_ID in the foreground, starting
  execution of that user if it is currently stopped.

am start-user: start USER_ID in background if it is currently stopped,
  use switch-user if you want to start the user in foreground.

am stop-user: stop execution of USER_ID, not allowing it to run any
  code until a later explicit start or switch to it.

am stack start: start a new activity on  using .

am stack movetask: move  from its current stack to the top (true) or   bottom (false) of

am stack resize: change  size and position to .

am stack list: list all of the activity stacks and their sizes.

am stack info: display the information about activity stack .

am lock-task: bring  to the front and don't allow other tasks to run

am get-config: retrieve the configuration and any recent configurations
  of the device

 specifications include these flags and arguments:
    [-a ] [-d ] [-t ]
    [-c  [-c ] ...]
    [-e|--es   ...]
    [--esn  ...]
    [--ez   ...]
    [--ei   ...]
    [--el   ...]
    [--ef   ...]
    [--eu   ...]
    [--ecn  ]
    [--eia  [, [, [, [,] [-p ] [-f ]
    [--grant-read-uri-permission] [--grant-write-uri-permission]
    [--grant-persistable-uri-permission] [--grant-prefix-uri-permission]
    [--debug-log-resolution] [--exclude-stopped-packages]
    [--include-stopped-packages]
    [--activity-brought-to-front] [--activity-clear-top]
    [--activity-clear-when-task-reset] [--activity-exclude-from-recents]
    [--activity-launched-from-history] [--activity-multiple-task]
    [--activity-no-animation] [--activity-no-history]
    [--activity-no-user-action] [--activity-previous-is-top]
    [--activity-reorder-to-front] [--activity-reset-task-if-needed]
    [--activity-single-top] [--activity-clear-task]
    [--activity-task-on-home]
    [--receiver-registered-only] [--receiver-replace-pending]
    [--selector]
    [ |  | ]

源码解析

代码入口main

 public static void main(String[] args) {
    (new Am()).run(args);
}

像通常的java程序那样,命令的入口是从方法main开始。其主体内容是调用类的run()方法,以命令行参数为参数。

代码执行run()

public void run(String[] args) {
    if (args.length < 1) {
        onShowUsage(System.out);
        return;
    }

    mArgs = args;
    mNextArg = 0;
    mCurArgData = null;

    try {
        onRun();
    } catch (IllegalArgumentException e) {
        onShowUsage(System.err);
        System.err.println();
        System.err.println("Error: " + e.getMessage());
    } catch (Exception e) {
        e.printStackTrace(System.err);
        System.exit(1);
    }
}

参数检查及进行出错处理,调用onRun()方法进行具体的操作

onRun()

@Override
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?");
    }

    String op = nextArgRequired();

    if (op.equals("start")) {
        runStart();
    } else if (op.equals("startservice")) {
        runStartService();
    } else if (op.equals("stopservice")) {
        runStopService();
    } 
     ......  
    else if (op.equals("get-config")) {
        runGetConfig();
    } else {
        showError("Error: unknown command '" + op + "'");
    }
}

我们看到这段代码是多分支实现对命令的解析,调用具体的方法,解析执行相应的指令。
父类中实现的几个参数处理的函数

protected String[] mArgs;  存放所有的参数
private int mNextArg;      当前正在处理的参数位置
private String mCurArgData; 用于帮助参数的处理

方法 runStart() 启动Activity

此方法的主要功能是根据传递的参数构建Intent,从而启动Activity。

private Intent makeIntent(int defUser)

根据传递过来的参数构建Intent,主要参数包括

specifications include these flags and arguments:

[-a ] [-d ] [-t ]           //分别跟action属性,data属性,type属性
[-c  [-c ] ...]                       //可以跟多个category属性
[-e|--es   ...]            //extra属性的键值对
[--esn  ...]                                    //跟一个key参数,extra属性的键值对,值为null
[--ez   ...]                //extra属性的键值对,值为boolean类型
[--ei   ...]
[--el   ...]
[--ef   ...]
[--eu   ...]
[--ecn  ]
[--eia  [, [, [, [,] [-p ] [-f ]            //组件名   包名  标识位

[--grant-read-uri-permission] [--grant-write-uri-permission]
[--grant-persistable-uri-permission] [--grant-prefix-uri-permission]
[--debug-log-resolution] [--exclude-stopped-packages]
[--include-stopped-packages]
[--activity-brought-to-front] [--activity-clear-top]
[--activity-clear-when-task-reset] [--activity-exclude-from-recents]
[--activity-launched-from-history] [--activity-multiple-task]
[--activity-no-animation] [--activity-no-history]
[--activity-no-user-action] [--activity-previous-is-top]
[--activity-reorder-to-front] [--activity-reset-task-if-needed]
[--activity-single-top] [--activity-clear-task]
[--activity-task-on-home]
[--receiver-registered-only] [--receiver-replace-pending]
[--selector]
[ |  | ]

/Intent的FLAG属性值/

FLAG_GRANT_READ_URI_PERMISSION
如果设置这个标记,Intent的接受者将会被赋予读取Intent中URI数据的权限和lipData中的URIs的权限。当应用与Intent的ClipData时,所有的URIs和data的所有递归遍历或者其他Intent的ClipData数据都会被授权。

FLAG_GRANT_WRITE_URI_PERMISSION
同FLAG_GRANT_READ_URI_PERMISSION只是相应的赋予的是写权限

FLAG_FROM_BACKGROUND
由调用者设置,表示这个Intent来自一个后台操作,而不是用户交互

FLAG_DEBUG_LOG_RESOLUTION
用来调试,当设置这个标志的时候,在解析这个intent的时候,将会打出打印信息(queryIntent函数)

FLAG_EXCLUDE_STOPPED_PACKAGES
如果设置,这个intent将不会去匹配这个package中当前停止的组件。也就是当我们查找到一堆合适的Intent时候,如果某个已经停止,则将会将其从合适的Intent中删除

FLAG_INCLUDE_STOPPED_PACKAGES
如果设置,这个intent将也匹配这个package中当前停止的组件。也就是当我们查找到一堆合适的Intent时候,如果某个已经停止,也不会将其从合适的Intent中删除

FLAG_ACTIVITY_NO_HISTORY
不把它保存到history堆栈,一旦用户离开了这个activity,这个activity将会结束,这个属性可以通过在AndroidManifest的activity标签中使用noHistory设置

FLAG_ACTIVITY_SINGLE_TOP
如果当前栈顶的activity就是要启动的activity,则这个activity将不会再加载

FLAG_ACTIVITY_NEW_TASK
设置这个标志,要启动的activity将会在一个新的task中启动。一个task定义了一个用户可以移动的activity的原子组。task可以移动到前台或者后台.一个task中的所有activity经常保持同样的次序。
当使用这个标记的时候,如果已经有一个task在运行你要启动的activity,这是将不会启动新的activity,而是把这个拥有你要启动activity的task切换到前台,保持它最后操作是的状态。查看FLAG_ACTIVITY_MULTIPLE_TASK来关闭这个行为。
当调用者组要从启动的activity返回一个结果时不能使用这个标志

FLAG_ACTIVITY_MULTIPLE_TASK
不建议使用此标记,除非你自己实现了应用程序的启动器。结合FLAG_ACTIVITY_NEW_TASK这个标记,即使要启动的activity已经存在一个task在运行,也会新启动一个task来运行要启动的activity
系统缺省是不带任务管理器的,所以当你使用这个标签的时候,你必须确保你能从你启动的task中返回回来。
如果没有设置FLAG_ACTIVITY_NEW_TASK,这个标记被忽略

FLAG_ACTIVITY_FORWARD_RESULT
一个Intene如果设置了这个标记,并且用于从一个已经存在的activity中启动一个activity,那么已经存在的这个activity的reply将会传给新启动的activity.例如假设有A、B、C三个activity A启动B,假如A的结果是给C的,当A启动B的时候设置了这个标志时,C调用setResult设置的结果也是返回给A,而不是B

FLAG_ACTIVITY_PREVIOUS_IS_TOP
这个标志好像没什么用,用于在获取栈顶ActivityRecord的时候,如果其等于该ActivityRecord,则继续获取下一个

FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
新启动的actiivty不添加到最近应用列表,也即我们从最近应用里面查看不到我们启动的这个activity

FLAG_ACTIVITY_BROUGHT_TO_FRONT
这个标记一般不是由应用程序自己设置的,而是由系统为你设置。 这个标记只看到在ActivityStack.java中的startActivityUncheckedLocked设置了这个标记,但是没看到其他地方使用它来做具体的用途判断等。

FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
同FLAG_ACTIVITY_BROUGHT_TO_FRONT,这个标记由系统设置,也没看到具体使用到这个标记的地方

FLAG_ACTIVITY_NO_USER_ACTION
在启动一个activity时,会从一个activity切换到另一个activity,如果设置了这个标记,在前一个activity 暂停的时候不会调用它的onUserLeaveHint函数
一般而言,activity可以通过依赖这个回调来明确的知道他们的activity已经从前台移除。这个回调给了activity在其生命周期中一个合适的时机来不让它错过它想显示的一些东西,如闪烁一下LED
如果一个activity不是由一个用户驱动启动的,如电话来了,或者闹钟的处理activity,必须使用这个标记,确保暂停的activity不认为用户已经知道这个通知

FLAG_ACTIVITY_REORDER_TO_FRONT
如果设置这个标记,新启动的activity将会被放到它所属task的最前面
例如,假如有一个task包含4个activity:A,B,C,D.如果D通过调用startActivity()来启动B,如果使用了这个标记,B将会排在这个task的最上面,也即现在的顺序变成了A,C,D,B.
如果使用了FLAG_ACTIVITY_CLEAR_TOP,这个标记将会被忽略

FLAG_ACTIVITY_NO_ANIMATION
如果设置这个标志,activity切换时将不使用动画迁移,但这并不表示以后将不会再显示动画迁移,如果其他的activity切换且没有设置这个标志时,还是会显示动画迁移的。当我们有一系列的activity要切换,且我们在某些activity切换时不想显示动画迁移时,这个标志就有用了。

startActivityAsUser

private IActivityManager mAm;
mAm = ActivityManagerNative.getDefault();
。。。
if (mWaitOption) {
    result = mAm.startActivityAndWait(null, null, intent, mimeType,
                null, null, 0, mStartFlags, profilerInfo, null, mUserId);
    res = result.result;
} else {
    res = mAm.startActivityAsUser(null, null, intent, mimeType,
            null, null, 0, mStartFlags, profilerInfo, null, mUserId);
}

具体Activity的启动,还是通过IActivityManager 代理类调用startActivityAndWait 或 startActivityAsUser 实现。
具体ActivityManager的运转原理,接下来会仔细分析。

参考链接

  1. Android应用程序内部启动Activity过程(startActivity)的源代码分析
  2. 024android初级篇之Android常用调试命令

相关源码

  1. am(frameworks/base/cmds/am/src/com/android/commands/am)
  2. startActivity:/frameworks/base/core/java/android/app/ActivityManagerNative.java

你可能感兴趣的:(025android初级篇之Android am命令的实现)