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,主要参数包括
[-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的运转原理,接下来会仔细分析。
参考链接
- Android应用程序内部启动Activity过程(startActivity)的源代码分析
- 024android初级篇之Android常用调试命令
相关源码
- am(frameworks/base/cmds/am/src/com/android/commands/am)
- startActivity:/frameworks/base/core/java/android/app/ActivityManagerNative.java