在Android系统中,可以用am命令来启动一个组件。例如,可以用下面的命令启动Camera:
# am start -n com.android.camera/com.android.camera.Camera
传送门:
Android开发-使用am命令启动Activity,Service等组件,以及发送广播等操作
Android源码分析-ActivityManagerService(AMS)源码分析
am是client端:
从代码实现上来说,在Android系统中,Android Framework层的各个service作为服务端,而使用者通过RPC(远程过程调用)调用这些服务,使用者就是Client端。
从进程间通信角度来说,Android Framework层的各个service作为服务端,提供具体的功能;同时,应用程序为了访问这些service,需要通过binder机制与service进行通信,这些运行在app端的代码就是client端(诸如ActivityManagerProxy等各种服务代理)。
具体到今天分析的am来说,am作为client端,与Framework的server端的AMS通过binder进行交互;从而实现AMS提供的各种功能,如图:
am的编译:
# Copyright 2008 The Android Open Source Project # LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_MODULE := am include $(BUILD_JAVA_LIBRARY) include $(CLEAR_VARS) ALL_PREBUILT += $(TARGET_OUT)/bin/am $(TARGET_OUT)/bin/am : $(LOCAL_PATH)/am | $(ACP) $(transform-prebuilt-to-target) NOTICE_FILE := NOTICE files_noticed := bin/am # Generate rules for a single file. The argument is the file path relative to # the installation root define make-notice-file $(TARGET_OUT_NOTICE_FILES)/src/$(1).txt: $(LOCAL_PATH)/$(NOTICE_FILE) @echo Notice file: $$< -- $$@ @mkdir -p $$(dir $$@) @cat $$< >> $$@ $(TARGET_OUT_NOTICE_FILES)/hash-timestamp: $(TARGET_OUT_NOTICE_FILES)/src/$(1).txt endef $(foreach file,$(files_noticed),$(eval $(call make-notice-file,$(file))))
Am类相关代码的分析:
Am类图如下:
说明(主要对Am类进行说明):
1. Am类:即am命令的入口类,有main方法。Am是client端组件,拥有一个远程代理组建mAm;
2. 数据成员mAm:
mAm:Am类通过mAm来实现相关的功能,包括启动一个activity或service,发送一个广播等。
mAm的真正实体类型是AcitivtyManagerProxy类型,因为mActivityManager是一个接口,无法实例化,而继承自mActivityManager的AcitivtyManagerProxy可以实例化。
mArgs:即am命令的参数;
3. 方法:
runStartService:启动一个service;
sendBroadcast:发送一个广播;
其余相关组件,请参考:
run方法的分析:
am是可执行程序,其对应的实现在Am.java中,当然有main方法。在main方法中,调用了run方法。
main方法调用run,代码如下:
public static void main(String[] args) {
try {
(new Am()).run(args);
}
......
}
而在run方法中,对命令行参数进行解析:
private void run(String[] args) throws Exception {
if (args.length < 1) {
showUsage();
return;
}
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;
if (op.equals("start")) {
runStart();
} else if (op.equals("startservice")) {
runStartService();
}
......
}
其中,
1. mAm = ActivityManagerNative.getDefault(); 通过rpc方式,返回了ActivityManagerProxy的一个实例;
2. showUsage:显示了am的用法;
3. runStart:当命令行参数的option是start时(例如,本篇文章最开始的 am start 命令),执行该方法;
4. runStartService:顾名思义,启动一个service。
我们主要分析runStart。
runStart方法的分析:
runStart的主要功能是根据输入的参数,来构建mAm的startActivity的参数。
我们知道,要strat 一个acitivty,从client的角度来看,需要通过ActivityManagerProxy调用到AMS的
startActivity方法中,
现在,mAm就是ActivityManagerProxy的实例。
过程如下:
(1)intent的构建:
Intent intent = makeIntent();
(2)停止当前的应用:
根据是否停止的标志来判断,
if (mStopOption) {......
mAm.forceStopPackage(packageName); Thread.sleep(250);}
(3)调用mAm的startActivity:
if (mWaitOption) { result = mAm.startActivityAndWait(null, intent, mimeType, null, null, 0, mStartFlags, mProfileFile, fd, null); res = result.result; } else { res = mAm.startActivity(null, intent, mimeType, null, null, 0, mStartFlags, mProfileFile, fd, null); }
这样,就调用到了mAm(即ActivityManagerProxy)的对应的startActivity方法中了。
关于startActivity的源码,可以参考:
Android源码分析-ActivityManagerService(AMS)源码分析