025android初級(jí)篇之Android am命令的實(shí)現(xiàn)
am命令一個(gè)重要的調(diào)試工具,主要功能包括如下:
啟動(dòng)停止Activity Service国章,啟動(dòng)Broadcast, 查看管理這些信息。
am命令
am命令本身是一個(gè)shell腳本叽奥,具體內(nèi)容如下:
#!/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命令啟動(dòng)java的程序俱两,使其在虛擬機(jī)中運(yùn)行饱狂。
命令使用
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
public static void main(String[] args) {
(new Am()).run(args);
}
像通常的java程序那樣,命令的入口是從方法main開始宪彩。其主體內(nèi)容是調(diào)用類的run()方法休讳,以命令行參數(shù)為參數(shù)。
代碼執(zhí)行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);
}
}
參數(shù)檢查及進(jìn)行出錯(cuò)處理尿孔,調(diào)用onRun()方法進(jìn)行具體的操作
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 + "'");
}
}
我們看到這段代碼是多分支實(shí)現(xiàn)對(duì)命令的解析俊柔,調(diào)用具體的方法,解析執(zhí)行相應(yīng)的指令活合。
父類中實(shí)現(xiàn)的幾個(gè)參數(shù)處理的函數(shù)
protected String[] mArgs; 存放所有的參數(shù)
private int mNextArg; 當(dāng)前正在處理的參數(shù)位置
private String mCurArgData; 用于幫助參數(shù)的處理
方法 runStart() 啟動(dòng)Activity
此方法的主要功能是根據(jù)傳遞的參數(shù)構(gòu)建Intent雏婶,從而啟動(dòng)Activity。
private Intent makeIntent(int defUser)
根據(jù)傳遞過(guò)來(lái)的參數(shù)構(gòu)建Intent白指,主要參數(shù)包括
<INTENT> specifications include these flags and arguments:
[-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>] //分別跟action屬性留晚,data屬性,type屬性
[-c <CATEGORY> [-c <CATEGORY>] ...] //可以跟多個(gè)category屬性
[-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...] //extra屬性的鍵值對(duì)
[--esn <EXTRA_KEY> ...] //跟一個(gè)key參數(shù)告嘲,extra屬性的鍵值對(duì)错维,值為null
[--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...] //extra屬性的鍵值對(duì)憨闰,值為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屬性的鍵值對(duì),值為int數(shù)組
[--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>] //組件名 包名 標(biāo)識(shí)位
[--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屬性值/
FLAG_GRANT_READ_URI_PERMISSION
如果設(shè)置這個(gè)標(biāo)記,Intent的接受者將會(huì)被賦予讀取Intent中URI數(shù)據(jù)的權(quán)限和lipData中的URIs的權(quán)限需五。當(dāng)應(yīng)用與Intent的ClipData時(shí)鹉动,所有的URIs和data的所有遞歸遍歷或者其他Intent的ClipData數(shù)據(jù)都會(huì)被授權(quán)。
FLAG_GRANT_WRITE_URI_PERMISSION
同F(xiàn)LAG_GRANT_READ_URI_PERMISSION只是相應(yīng)的賦予的是寫權(quán)限
FLAG_FROM_BACKGROUND
由調(diào)用者設(shè)置宏邮,表示這個(gè)Intent來(lái)自一個(gè)后臺(tái)操作泽示,而不是用戶交互
FLAG_DEBUG_LOG_RESOLUTION
用來(lái)調(diào)試,當(dāng)設(shè)置這個(gè)標(biāo)志的時(shí)候蜜氨,在解析這個(gè)intent的時(shí)候械筛,將會(huì)打出打印信息(queryIntent函數(shù))
FLAG_EXCLUDE_STOPPED_PACKAGES
如果設(shè)置,這個(gè)intent將不會(huì)去匹配這個(gè)package中當(dāng)前停止的組件飒炎。也就是當(dāng)我們查找到一堆合適的Intent時(shí)候埋哟,如果某個(gè)已經(jīng)停止,則將會(huì)將其從合適的Intent中刪除
FLAG_INCLUDE_STOPPED_PACKAGES
如果設(shè)置郎汪,這個(gè)intent將也匹配這個(gè)package中當(dāng)前停止的組件赤赊。也就是當(dāng)我們查找到一堆合適的Intent時(shí)候,如果某個(gè)已經(jīng)停止煞赢,也不會(huì)將其從合適的Intent中刪除
FLAG_ACTIVITY_NO_HISTORY
不把它保存到history堆棧抛计,一旦用戶離開了這個(gè)activity,這個(gè)activity將會(huì)結(jié)束照筑,這個(gè)屬性可以通過(guò)在AndroidManifest的activity標(biāo)簽中使用noHistory設(shè)置
FLAG_ACTIVITY_SINGLE_TOP
如果當(dāng)前棧頂?shù)腶ctivity就是要啟動(dòng)的activity吹截,則這個(gè)activity將不會(huì)再加載
FLAG_ACTIVITY_NEW_TASK
設(shè)置這個(gè)標(biāo)志,要啟動(dòng)的activity將會(huì)在一個(gè)新的task中啟動(dòng)凝危。一個(gè)task定義了一個(gè)用戶可以移動(dòng)的activity的原子組波俄。task可以移動(dòng)到前臺(tái)或者后臺(tái).一個(gè)task中的所有activity經(jīng)常保持同樣的次序。
當(dāng)使用這個(gè)標(biāo)記的時(shí)候蛾默,如果已經(jīng)有一個(gè)task在運(yùn)行你要啟動(dòng)的activity,這是將不會(huì)啟動(dòng)新的activity,而是把這個(gè)擁有你要啟動(dòng)activity的task切換到前臺(tái)懦铺,保持它最后操作是的狀態(tài)。查看FLAG_ACTIVITY_MULTIPLE_TASK來(lái)關(guān)閉這個(gè)行為趴生。
當(dāng)調(diào)用者組要從啟動(dòng)的activity返回一個(gè)結(jié)果時(shí)不能使用這個(gè)標(biāo)志
FLAG_ACTIVITY_MULTIPLE_TASK
不建議使用此標(biāo)記阀趴,除非你自己實(shí)現(xiàn)了應(yīng)用程序的啟動(dòng)器。結(jié)合FLAG_ACTIVITY_NEW_TASK這個(gè)標(biāo)記苍匆,即使要啟動(dòng)的activity已經(jīng)存在一個(gè)task在運(yùn)行刘急,也會(huì)新啟動(dòng)一個(gè)task來(lái)運(yùn)行要啟動(dòng)的activity
系統(tǒng)缺省是不帶任務(wù)管理器的,所以當(dāng)你使用這個(gè)標(biāo)簽的時(shí)候浸踩,你必須確保你能從你啟動(dòng)的task中返回回來(lái)叔汁。
如果沒(méi)有設(shè)置FLAG_ACTIVITY_NEW_TASK,這個(gè)標(biāo)記被忽略
FLAG_ACTIVITY_FORWARD_RESULT
一個(gè)Intene如果設(shè)置了這個(gè)標(biāo)記,并且用于從一個(gè)已經(jīng)存在的activity中啟動(dòng)一個(gè)activity据块,那么已經(jīng)存在的這個(gè)activity的reply將會(huì)傳給新啟動(dòng)的activity.例如假設(shè)有A码邻、B、C三個(gè)activity A啟動(dòng)B另假,假如A的結(jié)果是給C的像屋,當(dāng)A啟動(dòng)B的時(shí)候設(shè)置了這個(gè)標(biāo)志時(shí),C調(diào)用setResult設(shè)置的結(jié)果也是返回給A边篮,而不是B
FLAG_ACTIVITY_PREVIOUS_IS_TOP
這個(gè)標(biāo)志好像沒(méi)什么用己莺,用于在獲取棧頂ActivityRecord的時(shí)候,如果其等于該ActivityRecord戈轿,則繼續(xù)獲取下一個(gè)
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
新啟動(dòng)的actiivty不添加到最近應(yīng)用列表凌受,也即我們從最近應(yīng)用里面查看不到我們啟動(dòng)的這個(gè)activity
FLAG_ACTIVITY_BROUGHT_TO_FRONT
這個(gè)標(biāo)記一般不是由應(yīng)用程序自己設(shè)置的,而是由系統(tǒng)為你設(shè)置思杯。 這個(gè)標(biāo)記只看到在ActivityStack.java中的startActivityUncheckedLocked設(shè)置了這個(gè)標(biāo)記胜蛉,但是沒(méi)看到其他地方使用它來(lái)做具體的用途判斷等。
FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
同F(xiàn)LAG_ACTIVITY_BROUGHT_TO_FRONT色乾,這個(gè)標(biāo)記由系統(tǒng)設(shè)置誊册,也沒(méi)看到具體使用到這個(gè)標(biāo)記的地方
FLAG_ACTIVITY_NO_USER_ACTION
在啟動(dòng)一個(gè)activity時(shí),會(huì)從一個(gè)activity切換到另一個(gè)activity杈湾,如果設(shè)置了這個(gè)標(biāo)記解虱,在前一個(gè)activity 暫停的時(shí)候不會(huì)調(diào)用它的onUserLeaveHint函數(shù)
一般而言,activity可以通過(guò)依賴這個(gè)回調(diào)來(lái)明確的知道他們的activity已經(jīng)從前臺(tái)移除漆撞。這個(gè)回調(diào)給了activity在其生命周期中一個(gè)合適的時(shí)機(jī)來(lái)不讓它錯(cuò)過(guò)它想顯示的一些東西,如閃爍一下LED
如果一個(gè)activity不是由一個(gè)用戶驅(qū)動(dòng)啟動(dòng)的于宙,如電話來(lái)了浮驳,或者鬧鐘的處理activity,必須使用這個(gè)標(biāo)記捞魁,確保暫停的activity不認(rèn)為用戶已經(jīng)知道這個(gè)通知
FLAG_ACTIVITY_REORDER_TO_FRONT
如果設(shè)置這個(gè)標(biāo)記至会,新啟動(dòng)的activity將會(huì)被放到它所屬task的最前面
例如,假如有一個(gè)task包含4個(gè)activity:A,B,C,D.如果D通過(guò)調(diào)用startActivity()來(lái)啟動(dòng)B谱俭,如果使用了這個(gè)標(biāo)記奉件,B將會(huì)排在這個(gè)task的最上面,也即現(xiàn)在的順序變成了A,C,D,B.
如果使用了FLAG_ACTIVITY_CLEAR_TOP昆著,這個(gè)標(biāo)記將會(huì)被忽略
FLAG_ACTIVITY_NO_ANIMATION
如果設(shè)置這個(gè)標(biāo)志县貌,activity切換時(shí)將不使用動(dòng)畫遷移,但這并不表示以后將不會(huì)再顯示動(dòng)畫遷移凑懂,如果其他的activity切換且沒(méi)有設(shè)置這個(gè)標(biāo)志時(shí)煤痕,還是會(huì)顯示動(dòng)畫遷移的。當(dāng)我們有一系列的activity要切換,且我們?cè)谀承゛ctivity切換時(shí)不想顯示動(dòng)畫遷移時(shí),這個(gè)標(biāo)志就有用了。
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的啟動(dòng)瘩例,還是通過(guò)IActivityManager 代理類調(diào)用startActivityAndWait 或 startActivityAsUser 實(shí)現(xiàn)。
具體ActivityManager的運(yùn)轉(zhuǎn)原理,接下來(lái)會(huì)仔細(xì)分析埠巨。
參考鏈接
- Android應(yīng)用程序內(nèi)部啟動(dòng)Activity過(guò)程(startActivity)的源代碼分析
- 024android初級(jí)篇之Android常用調(diào)試命令