前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >025android初级篇之Android am命令的实现

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

作者头像
上善若水.夏
发布2018-09-28 10:40:36
1.4K0
发布2018-09-28 10:40:36
举报
文章被收录于专栏:上善若水上善若水

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

am命令一个重要的调试工具,主要功能包括如下:

启动停止Activity Service,启动Broadcast, 查看管理这些信息。

am命令

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

代码语言:javascript
复制
#!/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的程序,使其在虚拟机中运行。

命令使用

代码语言:javascript
复制
usage: am [subcommand] [options]
usage: am start [-D] [-W] [-P <FILE>] [--start-profiler <FILE>]
               [--sampling INTERVAL] [-R COUNT] [-S] [--opengl-trace]
               [--user <USER_ID> | current] <INTENT>
       am startservice [--user <USER_ID> | current] <INTENT>
       am stopservice [--user <USER_ID> | current] <INTENT>
       am force-stop [--user <USER_ID> | all | current] <PACKAGE>
       am kill [--user <USER_ID> | all | current] <PACKAGE>
       am kill-all
       am broadcast [--user <USER_ID> | all | current] <INTENT>
       am instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]
               [--user <USER_ID> | current]
               [--no-window-animation] [--abi <ABI>] <COMPONENT>
       am profile start [--user <USER_ID> current] <PROCESS> <FILE>
       am profile stop [--user <USER_ID> current] [<PROCESS>]
       am dumpheap [--user <USER_ID> current] [-n] <PROCESS> <FILE>
       am set-debug-app [-w] [--persistent] <PACKAGE>
       am clear-debug-app
       am monitor [--gdb <port>]
       am hang [--allow-restart]
       am restart
       am idle-maintenance
       am screen-compat [on|off] <PACKAGE>
       am to-uri [INTENT]
       am to-intent-uri [INTENT]
       am to-app-uri [INTENT]
       am switch-user <USER_ID>
       am start-user <USER_ID>
       am stop-user <USER_ID>
       am stack start <DISPLAY_ID> <INTENT>
       am stack movetask <TASK_ID> <STACK_ID> [true|false]
       am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>
       am stack list
       am stack info <STACK_ID>
       am lock-task <TASK_ID>
       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 <FILE>: start profiler and send results to <FILE>
    --sampling INTERVAL: use sample profiling with INTERVAL microseconds
        between samples (use with --start-profiler)
    -P <FILE>: like above, but profiling stops when app goes idle
    -R: repeat the activity launch <COUNT> 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 <USER_ID> | current: Specify which user to run as; if not
        specified then run as the current user.

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

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

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

am kill: Kill all processes associated with <PACKAGE>.  Only kills.
  processes that are safe to kill -- that is, will not impact the user
  experience.
    --user <USER_ID> | 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 <USER_ID> | all | current: Specify which user to send to; if not
        specified then send to all users.
    --receiver-permission <PERMISSION>: Require receiver to hold permission.

am instrument: start an Instrumentation.  Typically this target <COMPONENT>
  is the form <TEST_PACKAGE>/<RUNNER_CLASS>.  Options are:
    -r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT).  Use with
        [-e perf true] to generate raw output for performance measurements.
    -e <NAME> <VALUE>: set argument <NAME> to <VALUE>.  For test runners a
        common form is [-e <testrunner_flag> <value>[,<value>...]].
    -p <FILE>: write profiling data to <FILE>
    -w: wait for instrumentation to finish before returning.  Required for
        test runners.
    --user <USER_ID> | current: Specify user instrumentation runs in;
        current user if not specified.
    --no-window-animation: turn off window animations while running.
    --abi <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 <PROCESS> argument
  may be either a process name or pid.  Options are:
    --user <USER_ID> | 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 <PROCESS> argument may
  be either a process name or pid.  Options are:
    -n: dump native heap instead of managed heap
    --user <USER_ID> | current: When supplying a process name,
        specify user of process to dump; uses current user if not specified.

am set-debug-app: set application <PACKAGE> 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 <PACKAGE>.

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 <DISPLAY_ID> using <INTENT>.

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

am stack resize: change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>.

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

am stack info: display the information about activity stack <STACK_ID>.

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

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

<INTENT> specifications include these flags and arguments:
    [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]
    [-c <CATEGORY> [-c <CATEGORY>] ...]
    [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]
    [--esn <EXTRA_KEY> ...]
    [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]
    [--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]
    [--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]
    [--ef <EXTRA_KEY> <EXTRA_FLOAT_VALUE> ...]
    [--eu <EXTRA_KEY> <EXTRA_URI_VALUE> ...]
    [--ecn <EXTRA_KEY> <EXTRA_COMPONENT_NAME_VALUE>]
    [--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]
    [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]
    [--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]
    [--esa <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]]
        (to embed a comma into a string escape it using "\,")
    [-n <COMPONENT>] [-p <PACKAGE>] [-f <FLAGS>]
    [--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]
    [<URI> | <PACKAGE> | <COMPONENT>]

源码解析

代码入口main

代码语言:javascript
复制
 public static void main(String[] args) {
    (new Am()).run(args);
}

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

代码执行run()

代码语言:javascript
复制
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 {

代码语言:javascript
复制
    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 + "'");
    }
}

我们看到这段代码是多分支实现对命令的解析,调用具体的方法,解析执行相应的指令。

父类中实现的几个参数处理的函数

代码语言:javascript
复制
protected String[] mArgs;  存放所有的参数
private int mNextArg;      当前正在处理的参数位置
private String mCurArgData; 用于帮助参数的处理

方法 runStart() 启动Activity

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

private Intent makeIntent(int defUser)

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

<INTENT> specifications include these flags and arguments:

代码语言:javascript
复制
[-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]           //分别跟action属性,data属性,type属性
[-c <CATEGORY> [-c <CATEGORY>] ...]                       //可以跟多个category属性
[-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]            //extra属性的键值对
[--esn <EXTRA_KEY> ...]                                    //跟一个key参数,extra属性的键值对,值为null
[--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]                //extra属性的键值对,值为boolean类型
[--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]
[--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]
[--ef <EXTRA_KEY> <EXTRA_FLOAT_VALUE> ...]
[--eu <EXTRA_KEY> <EXTRA_URI_VALUE> ...]
[--ecn <EXTRA_KEY> <EXTRA_COMPONENT_NAME_VALUE>]
[--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]] //extra属性的键值对,值为int数组
[--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]
[--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]
[--esa <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]]
    (to embed a comma into a string escape it using "\,")
[-n <COMPONENT>] [-p <PACKAGE>] [-f <FLAGS>]            //组件名   包名  标识位

[--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]
[<URI> | <PACKAGE> | <COMPONENT>]

/Intent的FLAG属性值/

代码语言:javascript
复制
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

代码语言:javascript
复制
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
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016.01.21 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • am命令
  • 命令使用
  • 源码解析
    • 代码入口main
      • 代码执行run()
      • onRun()
      • 方法 runStart() 启动Activity
        • private Intent makeIntent(int defUser)
          • startActivityAsUser
          • 参考链接
          • 相关源码
          相关产品与服务
          腾讯云代码分析
          腾讯云代码分析(内部代号CodeDog)是集众多代码分析工具的云原生、分布式、高性能的代码综合分析跟踪管理平台,其主要功能是持续跟踪分析代码,观测项目代码质量,支撑团队传承代码文化。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档