ActivityManagerService的学习笔记
2017-09-13 18:47
1701 查看
参考地址:http://blog.csdn.net/innost/article/details/47254381
AMS由ActivityManagerNative(以后简称AMN)类派生,并实现Watchdog.Monitor和BatteryStatsImpl.BatteryCallback接口。而AMN由Binder派生,实现了IActivityManager接口。
客户端使用ActivityManager类。由于AMS是系统核心服务,很多API不能开放供客户端使用,所以设计者没有让ActivityManager直接加入AMS家族。在ActivityManager类内部通过调用AMN的getDefault函数得到一个ActivityManagerProxy对象,通过它可与AMS通信。
1.SystemServer的ServerThread线程的 run() 方法调用ActivityManagerService.main 创建ActivityManagerServiceContext对象
2.ActivityManagerService.setSystemProcess();//SystemServer进程可加 到AMS中,并被ActivityManagerService管理;
3.ActivityManagerService.installSystemProviders();//将SettingsProvider放到SystemServer进程中来运行
4.ActivityManagerService.self().setWindowManager(wm);//保存WindowManagerService(WMS)
5.与WMS交互,弹出“启动进度“对话框;
6.ActivityManagerService.self().systemReady;//启动启动systemUi,AMS是系统的核心,只有它准备好后,才能调用其他服务的systemReady
在main函数中,我们又列出了4个关键函数:
1⃣️创建AThread线程;
2⃣️ActivityThread的systemMain函数;
3⃣️ ActivityThread.getSystemContext函数(System的上下文环境)
4⃣️AMS的startRunning函数
AThread线程名就叫“ActivityManager”,将支持消息循环及处理功能,且创建AMS,然后通知AMS的main函数;
AMS的构造函数分析:
创建BatteryStatsService(BSS)、UsageStatsService(USS)、mProcessStats (ProcessStats类型)、mProcessStatsThread线程,这些都与系统运行状况统计相关
创建/data/system目录,为mCompatModePackages(CompatModePackages类型)和mConfiguration(Configuration类型)等成员变量赋值。
ActivityThread是Android Framework中一个非常重要的类,它代表一个应用进程的主线程(对于应用进程来说,ActivityThread的main函数确实是由该进程的主线程执行),其职责就是调度及执行在该线程中运行的四大组件。
注意应用进程指那些运行APK的进程,它们由Zygote 派生(fork)而来,上面运行了dalvik虚拟机。与应用进程相对的就是系统进程(包括Zygote和SystemServer);
apk文件在/data/app目录下,则为应用APK
(1)ActivityThread.java::systemMain调用thread.attach(true);
应用进程
系统进程:SystemServer是一个特殊的应用进程
设置DDMS时看到的systemserver进程名为system_process,创建Instrumentation类(传递系统和组件之间的交互)、Application类(保存了一个全局的application状态,可理解为一种容器,内部包含四大组件,一个进程可以运行多个Application。)及Context类
systemMain函数将为SystemServer进程搭建一个和应用进程一样的Android运行环境。
SystemServer希望它内部的那些Service也通过Android运行环境交互,因此也需为它创建一个运行环境。由于SystemServer的特殊性,此处调用了systemMain函数,而普通的应用进程将在主线程中调用ActivityThread的main函数来创建Android运行环境。
ActivityThread虽然本意是代表进程的主线程,但是作为一个Java类,它的实例到底由什么线程创建,不是ActivityThread自己能做主的,所以在SystemServer中可以发现,ActivityThread对象由其他线程创建,而在应用进程中,ActivityThread将由主线程来创建。
* Instrumentaion是一个工具类。当它被启用时,系统先创建它,再通过它来创建其他组件。另外,系统和组件之间的交互也将通过Instrumentation来传递
* Application类保存了一个全局的application状态。
* Context是一个接口,通过它可以获取并操作Application对应的资源、类,甚至包含于Application中的四大组件。
· 首先也是最容易想到的目的是创建AMS对象。
· 另外一个目的比较隐晦,但是非常重要,那就是创建一个供SystemServer进程使用的Android运行环境。
· ActivityThread中有一个mLooper成员,它代表一个消息循环
· 对于ContextImpl,其成员变量表明它和资源、APK文件有关。
· 第一次执行init时,在LoadedApk构造函数中第四个表示ApplicationInfo的参数为null。
· 第二次执行init时,LoadedApk构造函数的第四个参数不为空,即该参数将真正指向一个实际的ApplicationInfo,该ApplicationInfo来源于framework-res.apk。
基于上面的信息,某些读者可能马上能想到:Context第一次执行init的目的仅仅是为了创建一个Android运行环境,而该Context并没有和实际的ApplicationInfo绑定。而第二次执行init前,先利用Context和PKMS交互得到一个实际的ApplicationInfo,然后再通过init将此Context和ApplicationInfo绑定。因为framework-res.apk(包括后面将介绍的SettingsProvider.apk)运行在SystemServer中。和其他所有apk一样,它的运行需要一个正确初始化的Android运行环境。
由于framework-res.apk是一个APK文件,和其他APK文件一样,它应该运行在一个进程中。而AMS是专门用于进程管理和调度的,所以运行APK的进程应该在AMS中有对应的管理结构。因此AMS下一步工作就是将这个运行环境和一个进程管理结构对应起来并交由AMS统一管理。
AMS中的进程管理结构是ProcessRecord。
Android提供了一个IApplicationThread接口,该接口定义了AMS和应用进程之间的交互函数
AMS通过它可以和应用进程进行交互,例如,AMS启动一个Activity的时候会调用该接口的scheduleLaunchActivity函数。
IApplicationThread的Binder服务端在应用进程中,因为AMS需要监听应用进程的死亡通知。
IApplicationThread仅仅是AMS和另外一个进程交互的接口,除此之外,AMS还需要更多的有关该进程的信息。在AMS中,进程的信息都保存在ProcessRecord数据结构中。那么,ProcessRecord是什么呢?先来看setSystemProcess的第二个关键点,即newProcessRecordLocked函数,其代码如下:
[–>ActivityManagerService.java::newProcessRecordLocked]
–>ProcessRecord.java::ProcessRecord
ProcessRecord除保存和应用进程通信的IApplicationThread对象外,还保存了进程名、不同状态对应的Oom_adj值及一个ApplicationInfo。一个进程虽然可运行多个Application,但是ProcessRecord一般保存该进程中先运行的那个Application的ApplicationInfo。
至此,已经创建了一个ProcessRecord对象,和其他应用进程不同的是,该对象对应的进程为SystemServer。为了彰显其特殊性,AMS为其中的一些成员变量设置了特定的值:
· 注册AMS、meminfo、gfxinfo等服务到ServiceManager中。
· 根据PKMS返回的ApplicationInfo初始化Android运行环境,并创建一个代表SystemServer进程的ProcessRecord,从此,SystemServer进程也并入AMS的管理范围内。
此时的SystemServer已经加载了framework-res.apk,现在又要加载另外一个APK文件,这就是多个APK运行在同一进程的典型案例。另外,通过installSystemProviders函数还能见识ContentProvider的安装过程。
[–>ActivityManagerService.java::installSystemProviders]
在代码中列出了两个关键调用,分别是:
· 调用generateApplicationProvidersLocked函数,该函数返回一个ProviderInfo List。
· 调用ActivityThread的installSystemProviders函数。ActivityThread可以看做是进程的Android运行环境,那么installSystemProviders表示为该进程安装ContentProvider。
(1) PMS中 queryContentProviders函数分析
[–>PackageManagerService.java::queryContentProviders]
由图6-7可知,SettingsProvider设置了其uid为“android.uid.system”,同时在application中设置了process名为“system”。而在framework-res.apk中也做了相同的设置。所以,现在可以确认SettingsProvider将和framework-res.apk运行在同一个进程,即SystemServer中。
提示从运行效率角度来说,这样做也是合情合理的。因为SystemServer的很多Service都依赖Settings数据库,把它们放在同一个进程中,可以降低由于进程间通信带来的效率损失。
(2)关于ContentProvider的介绍
前面介绍的从PKMS那里查询到的ProviderInfo还属于公有财产,现在我们要将它与AMS及ProcessRecord联系起来。
· AMS保存ProviderInfo的原因是它要管理ContentProvider。
· ProcessRecord保存ProviderInfo的原因是ContentProvider最终要落实到一个进程中。其实也是为了方便AMS管理,例如该进程一旦退出,AMS需要把其中的ContentProvider信息从系统中去除。
AMS及ProcessRecord均使用了一个新的数据结构ContentProviderRecord来管理ContentProvider信息。图6-8展示了ContentProviderRecord相应的数据结构。
–>ActivityThread.java::installSystemProviders
–>ActivityThread.java::installContentProviders
installContentProviders实际上是标准的ContentProvider安装时调用的程序。安装ContentProvider包括两方面的工作:
· 先在ActivityThread中通过installProvider得到一个ContentProvider实例。
· 向AMS发布这个ContentProvider实例。如此这般,一个APK中声明的ContentProvider才能登上历史舞台,发挥其该有的作用。
提示 上述工作其实和Binder Service类似,一个Binder Service也需要先创建,然后注册到ServiceManager中。
马上来看ActivityThread的installProvider函数。
(1) ActivityThread的installProvider函数分析
–>ActivityThread.java::installProvider]
· ContentProvider类本身只是一个容器,而跨进程调用的支持是通过内部类Transport实现的。Transport从ContentProviderNative派生,而ContentProvider的成员变量mTransport指向该Transport对象。ContentProvider的getIContentProvider函数即返回mTransport成员变量。
· ContentProviderNative从Binder派生,并实现了IContentProvider接口。其内部类ContentProviderProxy是供客户端使用的。
· ProviderClientRecord是ActivityThread提供的用于保存ContentProvider信息的一个数据结构。它的mLocalProvider用于保存ContentProvider对象,mProvider用于保存IContentProvider对象。另外一个成员mName用于保存该ContentProvider的一个authority。注意,ContentProvider可以定义多个authority,就好像一个网站有多个域名一样。
(2) ASM的 publishContentProviders分析
publishContentProviders函数用于向AMS注册ContentProviders,
–>ActivityManagerService.java::publishContentProviders
publishContentProviders的工作流程:
· 先根据调用者的pid找到对应的ProcessRecord对象。
· 该ProcessRecord的pubProviders中保存了ContentProviderRecord信息。该信息由前面介绍的AMS的generateApplicationProvidersLocked函数根据Package本身的信息生成。此处将判断要发布的ContentProvider是否由该Package声明。
· 如果判断返回成功,则将该ContentProvider及其对应的authority加到mProvidersByName中。注意,AMS中还有一个mProvidersByClass变量,该变量以ContentProvider的ComponentName为key,即系统提供多种方式找到某一个ContentProvider,一种是通过 authority,另一种方式就是指明ComponentName。
· mLaunchingProviders和最后的notifyAll函数用于通知那些等待ContentProvider所在进程启动的客户端进程。例如,进程A要查询一个数据库,需要通过进程B中的某个ContentProvider 来实施。如果B还未启动,那么AMS就需要先启动B。在这段时间内,A需要等待B启动并注册对应的ContentProvider。B一旦完成注册,就需要告知A退出等待以继续后续的查询工作。
systemReady第一阶段的工作并不轻松,其主要职责是发送并处理与PRE_BOOT_COMPLETED广播相关的事情。目前代码中还没有接收该广播的地方,不过从代码中的注释中可猜测到,该广播接收者的工作似乎和系统升级有关。
· 杀死那些竟然在AMS还未启动完毕就先启动的应用进程。注意,这些应用进程一定是APK所在的Java进程,因为只有应用进程才会向AMS注册,而一般Native(例如mediaserver)进程是不会向AMS注册的。
· 从Settings数据库中获取配置信息,目前只取4个配置参数,分别是:”debug_app”(设置需要debug的app的名称)、”wait_for_debugger”(如果为1,则等待调试器,否则正常启动debug_app)、”always_finish_activities”(当一个activity不再有地方使用时,是否立即对它执行destroy)、”font_scale”(用于控制字体放大倍数,这是Android 4.0新增的功能)。以上配置项由Settings数据库的System表提供。
(1)goingCallback的run函数分析
· 执行startSystemUi,在该函数内部启动SystemUIService,该Service和状态栏有关。
· 调用一些服务的systemReady函数。
· 启动Watchdog。
startSystemUi的代码如下:
[–>SystemServer.java::startSystemUi]
SystemUIService由SystemUi.apk提供,它实现了系统的状态栏。
(2) 启动Home界面
–>ActivityStack.java::resumeTopActivityLocked
->ActivityManagerService.java::startHomeActivityLocked
boolean startHomeActivityLocked() {
Intentintent = new Intent( mTopAction,
mTopData != null ? Uri.parse(mTopData) :null);
intent.setComponent(mTopComponent);
if(mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL)
intent.addCategory(Intent.CATEGORY_HOME);//添加Category为HOME类别
ActivityInfo aInfo =
intent.resolveActivityInfo(mContext.getPackageManager(),
STOCK_PM_FLAGS);
if(aInfo != null) {
intent.setComponent(new ComponentName(
aInfo.applicationInfo.packageName,aInfo.name));
ProcessRecordapp = getProcessRecordLocked(aInfo.processName,
aInfo.applicationInfo.uid);
//在正常情况下,app应该为null,因为刚开机,Home进程肯定还没启动
if(app == null || app.instrumentationClass == null) {
intent.setFlags(intent.getFlags()|
Intent.FLAG_ACTIVITY_NEW_TASK);
//启动Home
mMainStack.startActivityLocked(null, intent, null, null, 0, aInfo,
null, null, 0, 0, 0, false, false,null);
}
}//if(aInfo != null)判断结束
return true;
}
(3) 发送ACTION_BOOT_COMPLETED广播
当Home Activity启动后,ActivityStack的activityIdleInternal函数将被调用,其中有一句代码颇值得注意:
[–>ActivityStack.java::activityIdleInternal]
[–>ActivityManagerService.java::finishBooting]
· AMS的setSystemProcess函数:该函数注册AMS和meminfo等服务到ServiceManager中。另外,它为SystemServer创建了一个ProcessRecord对象。由于AMS是Java世界的进程管理及调度中心,要做到对Java进程一视同仁,尽管SystemServer贵为系统进程,此时也不得不将其并入AMS的管理范围内。
· AMS的installSystemProviders:为SystemServer加载SettingsProvider。
· AMS的systemReady:做系统启动完毕前最后一些扫尾工作。该函数调用完毕后,HomeActivity将呈现在用户面前。
[–>Am.java::main]
am启动一个activity
am start -W -n com.dfp.test/.TestActivity
–>Am.java::run
runStart函数用于处理Activity启动请求
–>ActivityManagerService.java::startActivityAndWait
mMainStack为AMS的成员变量,类型为ActivityStack,该类是Activity调度的核心角色。正式分析它之前,有必要先介绍一下相关的基础知识。
1. Task、Back Stack、ActivityStack及Launch mode
用户在Android系统上想干的三件事情,分别用A、B、C表示,将每一件事情称为一个Task。一个Task还可细分为多个子步骤,即Activity。
(1) 关于Task及Back Stack的介绍
Android采用了Stack的方法管理这3个Activity。例如在A1启动A2后,A2入栈成为栈顶成员,A1成为栈底成员,而界面显示的是栈顶成员的内容。当按返回键时,A3出栈,这时候A2成为栈顶,界面显示也相应变成了A2。
以上是一个Task的情况。
对多Task的情况来说,系统只支持一个处于前台的Task,即用户当前看到的Activity所属的Task,其余的Task均处于后台,这些后台Task内部的Activity保持顺序不变。用户可以一次将整个Task挪到后台或者置为前台。
(2) 关于ActivityStack的介绍
· Task内部Activity的组织方式。由图6-11可知,Android通过先入后出的方式来组织Activity。数据结构中的Stack即以这种方式工作。
· 多个Task的组织及管理方式。
Android设计了一个ActivityStack类来负责上述工作,它的组成如图6-13所示。
· Activity由ActivityRecord表示,Task由TaskRecord表示。ActivityRecord的task成员指向该Activity所在的Task。state变量用于表示该Activity所处的状态(包括INITIALIZING、RESUMED、PAUSED等状态)。
· ActivityStack用mHistory这个ArrayList保存ActivityRecord。令人大跌眼镜的是,该mHistory保存了系统中所有Task的ActivityRecord,而不是针对某个Task进行保存。
· ActivityStack的mMainStack成员比较有意思,它代表此ActivityStack是否为主ActivityStack。有主必然有从,但是目前系统中只有一个ActivityStack,并且它的mMainStack为true。从ActivityStack的命名可推测,Android在开发之初也想用ActivityStack来管理单个Task中的ActivityRecord(在ActivityStack.java的注释中说过,该类为“State and management of asingle stack of activities”),但不知何故,在现在的代码实现将所有Task的ActivityRecord都放到mHistory中了,并且依然保留mMainStack。
· ActivityStack中没有成员用于保存TaskRecord。
由上述内容可知,ActivityStack采用数组的方式保存所有Task的ActivityRecord,并且没有成员保存TaskRecord。
ActivityStack中几个常用的搜索ActivityRecord的函数
–>ActivityStack.java::topRunningActivityLocked
类似的函数还有:
[–>ActivityStack.java::topRunningNonDelayedActivityLocked]
ActivityStack还提供findActivityLocked函数以根据Intent及ActivityInfo来查找匹配的ActivityRecord,同样,查找也是从mHistory尾端开始,相关代码如下:
[–>ActivityStack.java::findActivityLocked]
findTaskLocked是根据mHistory中ActivityRecord所属的Task的情况来进行相应的查找工作。
(3) 关于Launch Mode的介绍
Launch Mode用于描述Activity的启动模式,目前一共有4种模式,分别是standard、singleTop、singleTask和singleInstance。启动模式就是用于控制Activity和Task关系的。
· standard:一个Task中可以有多个相同类型的Activity。注意,此处是相同类型的Activity,而不是同一个Activity对象。例如在Task中有A、B、C、D4个Activity,如果再启动A类Activity, Task就会变成A、B、C、D、A。最后一个A和第一个A是同一类型,却并非同一对象。另外,多个Task中也可以有同类型的Activity。
· singleTop:当某Task中有A、B、C、D4个Activity时,如果D想再启动一个D类型的Activity,那么Task将是什么样子呢?在singleTop模式下,Task中仍然是A、B、C、D,只不过D的onNewIntent函数将被调用以处理这个新Intent,而在standard模式下,则Task将变成A、B、C、D、D,最后的D为新创建的D类型Activity对象。在singleTop这种模式下,只有目标Acitivity当前正好在栈顶时才有效,例如只有处于栈顶的D启动时才有用,如果D启动不处于栈顶的A、B、C等,则无效。
· singleTask:在这种启动模式下,该Activity只存在一个实例,并且将和一个Task绑定。当需要此Activity时,系统会以onNewIntent方式启动它,而不会新建Task和Activity。注意,该Activity虽只有一个实例,但是在Task中除了它之外,还可以有其他的Activity。
· singleInstance:它是singleTask的加强版,即一个Task只能有这么一个设置了singleInstance的Activity,不能再有别的Activity。而在singleTask模式中,Task还可以有其他的Activity。
Android还有其他一些标志用于控制Activity及Task之间的关系:
· FLAG_ACTIVITY_NEW_TASK:将目标Activity放到一个新的Task中。
· FLAG_ACTIVITY_CLEAR_TASK:当启动一个Activity时,先把和目标Activity有关联的Task“干掉“,然后启动一个新的Task,并把目标Activity放到新的Task中。该标志必须和FLAG_ACTIVITY_NEW_TASK标志一起使用。
· FLAG_ACTIVITY_CLEAR_TOP:当启动一个不处于栈顶的Activity时候,先把排在它前面的Activity“干掉”。例如Task有A、B、C、D4个Activity,要要启动B,直接把C、D“干掉”,而不是新建一个B。
2. ActivityStack的startActivityMayWait函数分析
startActivityMayWait函数的目标是启动com.dfp.test.TestActivity,假设系统之前没有启动过该Activity,本例最终的结果将是:
· 由于在am中设置了FLAG_ACTIVITY_NEW_TASK标志,因此除了会创建一个新的ActivityRecord外,还会新创建一个TaskRecord。
· 还需要启动一个新的应用进程以加载并运行com.dfp.test.TestActivity的一个实例。
· 如果TestActivity不是Home,还需要停止当前正在显示的Activity。
好了,将这个函数分三部分进行介绍,先来分析第一部分。
(1) startActivityMayWait分析之一
[–>ActivityStack.java::startActivityMayWait]
final int startActivityMayWait(IApplicationThread caller, int callingUid,
Intent intent, String resolvedType, Uri[] grantedUriPermissions,
int grantedMode, IBinder resultTo,
String resultWho, int requestCode, boolean onlyIfNeeded,
boolean debug, String profileFile, ParcelFileDescriptor profileFd,
boolean autoStopProfiler, WaitResult outResult, Configuration config) {
……
//在本例中,已经指明了Component,这样可省去为Intent匹配搜索之苦
booleancomponentSpecified = intent.getComponent() != null;
//尝试分析该函数
ActivityInfoaInfo = resolveActivity(intent, resolvedType, debug,
profileFile, profileFd,autoStopProfiler);
……//待续
(2) startActivityMayWait分析之二
//调用此函数启动Activity,将返回值保存到res
int res = startActivityLocked(caller, intent,resolvedType,
grantedUriPermissions, grantedMode, aInfo,
resultTo, resultWho, requestCode, callingPid, callingUid,
onlyIfNeeded, componentSpecified, null);
//如果configuration发生变化,则调用AMS的updateConfigurationLocked
//进行处理。关于这部分内容,读者学完本章后可自行分析
if(mConfigWillChange && mMainStack) {
mService.enforceCallingPermission(
android.Manifest.permission.CHANGE_CONFIGURATION,
“updateConfiguration()”);
mConfigWillChange= false;
mService.updateConfigurationLocked(config,null, false);
}
启动Activity的核心函数是startActivityLocked,该函数异常复杂
(3) startActivityMayWait分析之三
if(outResult != null) {
outResult.result = res;//设置启动结果
if(res == IActivityManager.START_SUCCESS) {
//将该结果加到mWaitingActivityLaunched中保存
mWaitingActivityLaunched.add(outResult);
do {
try {
mService.wait();//等待启动结果
}
} while (!outResult.timeout && outResult.who == null);
}else if (res == IActivityManager.START_TASK_TO_FRONT) {
……//处理START_TASK_TO_FRONT结果,读者可自行分析
}
}//if(outResult!= null)结束
return res;
}
}
第三阶段的工作就是根据返回值做一些处理,那么res返回成功(即res== IActivityManager.START_SUCCESS的时候)后为何还需要等待呢?
这是因为目标Activity要运行在一个新的应用进程中,就必须等待那个应用进程正常启动并处理相关请求。注意,只有am设置了-W选项,才会进入wait这一状态。
startActivityLocked函数的主要工作包括:
· 处理sourceRecord及resultRecord。其中,sourceRecord表示发起本次请求的Activity,resultRecord表示接收处理结果的Activity(启动一个Activity肯定需要它完成某项事情,当目标Activity将事情成后,就需要告知请求者该事情的处理结果)。在一般情况下,sourceRecord和resultRecord应指向同一个Activity。
· 处理app Switch。如果AMS当前禁止app switch,则只能把本次启动请求保存起来,以待允许app switch时再处理。从代码中可知,AMS在处理本次请求前,会先调用doPendingActivityLaunchesLocked函数,在该函数内部将启动之前因系统禁止app switch而保存的Pending请求。
· 调用startActivityUncheckedLocked处理本次Activity启动请求
[–>ActivityManagerService.java::stopAppSwitches]
· 此处控制机制名叫app switch,而不是activity switch。为什么呢?因为如果从受保护的activity中启动另一个activity,那么这个新activity的目的应该是针对同一任务,这次启动就不应该受app switch的制约,反而应该对其大开绿灯。目前,在执行Settings中设置设备策略(DevicePolicy)时就会stopAppSwitch。
· 执行stopAppSwitch后,应用程序应该调resumeAppSwitches以允许app switch,但是为了防止应用程序有意或无意忘记resume app switch,系统设置了一个超时(5秒)消息,过了此超时时间,系统将处理相应的消息,其内部会resume app switch。
[–>ActivityManagerService::resumeAppSwitches]
在resumeAppSwitches中只设置mAppSwitchesAllowedTime的值为0,它并不处理在stop和resume这段时间内积攒起的Pending请求,那么这些请求是在何时被处理的呢?
· 从前面代码可知,如果在执行resume app switch后,又有新的请求需要处理,则先处理那些pending的请求(调用doPendingActivityLaunchesLocked)。
· 在resumeAppSwitches中并未撤销stopAppSwitches函数中设置的超时消息,所以在处理那条超时消息的过程中,也会处理pending的请求。
在本例中,由于不考虑app switch的情况,那么接下来的工作就是调用startActivityUncheckedLocked函数来处理本次activity的启动请求。此时,我们已经创建了一个ActivityRecord用于保存目标Activity的相关信息。
接下来的工作就是调用startActivityUncheckedLocked函数来处理本次activity的启动请求。此时,我们已经创建了一个ActivityRecord用于保存目标Activity的相关信息。
(1) startActivityUncheckedLocked分析之一
startActivityUncheckedLocked第一阶段的工作还算简单,主要确定是否需要为新的Activity创建一个Task,即是否设置FLAG_ACTIVITY_NEW_TASK标志。
(2) startActivityUncheckedLocked分析之二
(3) startActivityUncheckLocked分析之三
(4) startActivityLocked函数分析
[–>ActivityStack.java::startActivityLocked]
startActivityUncheckedLocked函数的功能:创建ActivityRecord和TaskRecord并将ActivityRecord添加到mHistory末尾,然后调用resumeTopActivityLocked启动它。
resumeTopActivityLocked函数中有两个非常重要的关键点:
· 如果mResumedActivity不为空,则需要先暂停(pause)这个Activity。由代码中的注释可知,mResumedActivity代表上一次启动的(即当前正显示的)Activity。现在要启动一个新的Activity,须先停止当前Activity,这部分工作由startPausingLocked函数完成。
· 那么,mResumedActivity什么时候为空呢?当然是在启动全系统第一个Activity时,即启动Home界面的时候。除此之外,该值都不会为空。
先分析第二个关键点,即mResumedActivity为null的情况选择分析此种情况的原因是:如果先分析startPausingLocked,则后续分析会牵扯三个进程,即当前Activity所在进程、AMS所在进程及目标进程,分析的难度相当大。
好了,继续我们的分析。resumeTopActivityLocked最后将调用另外一个startSpecificActivityLocked,该函数将真正创建一个应用进程。
1) startSpecificActivityLocked分析
[–>ActivityStack.java::startSpecificActivityLocked]
(2) startProcessLocked分析
[–>ActivityManagerService.java::startProcessLocked]
在以上代码中列出两个关键点,其中第一点和FLAG_FROM_BACKGROUND有关,相关知识点如下:
· FLAG_FROM_BACKGROUND标识发起这次启动的Task属于后台任务。很显然,手机中没有界面供用户操作位于后台Task中的Activity。如果没有设置该标志,那么这次启动请求就是由前台Task因某种原因而触发的(例如用户单击某个按钮)。
· 如果一个应用进程在1分钟内连续崩溃超过2次,则AMS会将其ProcessRecord加入所谓的mBadProcesses中。一个应用崩溃后,系统会弹出一个警告框以提醒用户。但是,如果一个后台Task启动了一个“BadProcess”,然后该Process崩溃,结果弹出一个警告框,那么用户就会觉得很奇怪:“为什么突然弹出一个框?”因此,此处将禁止后台Task启动“Bad Process”。如果用户主动选择启动(例如单击一个按钮),则不能禁止该操作,并且要把应用进程从mBadProcesses中移除,以给它们“重新做人”的机会。当然,要是该应用每次启动时都会崩溃,这其实是一种安全机制,防止不健全的程序不断启动可能会崩溃的组件,但是这种机制并不限制用户的行为。
[–>ActivityManagerService.java::startProcessLocked]
[–>ActivityThread.java::main]
在main函数内部将创建一个消息循环Loop,接着调用ActivityThread的attach函数,最终将主线程加入消息循环。
我们在分析AMS的setSystemProcess时曾分析过ActivityThread的attach函数,那时传入的参数值为true。现在来看设置其为false的情况:
[–>ActivityThread.java::attach]
我们知道,AMS创建一个应用进程后,会设置一个超时时间(一般是10秒)。如果超过这个时间,应用进程还没有和AMS交互,则断定该进程创建失败。所以,应用进程启动后,需要尽快和AMS交互,即调用AMS的attachApplication函数。在该函数内部将调用attachApplicationLocked,所以此处直接分析attachApplicationLocked,先看其第一阶段的工作。
(1) attachApplicationLocked分析之一
[–>ActivityManagerService.java::attachApplicationLocked]
attachApplicationLocked第一阶段的工作比较简单:
· 设置代表该应用进程的ProcessRecrod对象的一些成员变量,例如用于和应用进程交互的thread对象、进程调度优先级及oom_adj的值等。
· 从消息队列中撤销PROC_START_TIMEOUT_MSG。
至此,该进程启动成功,但是这一阶段的工作仅针对进程本身(如设置调度优先级,oom_adj等),还没有涉及和Activity启动相关的内容,这部分工作将在第二阶段完成。
(2) attachApplicationLocked分析之二
[–>ActivityManagerService.java::attachApplicationLocked]
第二阶段的工作主要是为调用ApplicationThread的bindApplication做准备
此处先来看它的原型:
(3) attachApplicationLocked分析之三
attachApplicationLocked第三阶段的工作就是通知应用进程启动Activity和Service等组件,其中用于启动Activity的函数是ActivityStack realStartActivityLocked。
此处先来分析应用进程的bindApplication,该函数将为应用进程绑定一个Application。
提示还记得AMS中System Context执行的两次init吗?第二次init的功能就是将Context和对应的Application绑定在一起。
(4) ApplicationThread的bindApplication分析
bindApplication在ApplicationThread中的实现,其代码如下:
[–>ActivityThread.java::bindApplication]
ApplicationThread接收到来自AMS的指令后,均会将指令中的参数封装到一个数据结构中,然后通过发送消息的方式转交给主线程去处理。BIND_APPLICATION最终将由handleBindApplication函数处理。该函数并不复杂,但是其中有些点是值得关注的,这些点主要是初始化应用进程的一些参数。handleBindApplication函数的代码如下:
[–>ActivityThread.java::handleBindApplication]
由以上代码可知,bindApplication函数将设置一些初始化参数,其中最重要的有:
· 创建一个Application对象,该对象是本进程中运行的第一个Application。
· 如果该Application有ContentProvider,则应安装它们。
提示从以上代码可知,ContentProvider的创建就在bindApplication函数中,其时机早于其他组件的创建。
(5) 应用进程的创建及初始化总结
本节从应用进程的入口函数main开始,分析了应用进程和AMS之间的两次重要交互,它们分别是:
· 在应用进程启动后,需要尽快调用AMS的attachApplication函数,该函数是这个刚呱呱坠地的应用进程第一次和AMS交互。此时的它还默默“无名”,连一个确定的进程名都没有。不过没关系,attachApplication函数将根据创建该应用进程之前所保存的ProcessRecord为其准备一切“手续”。
· attachApplication准备好一切后,将调用应用进程的bindApplication函数,在该函数内部将发消息给主线程,最终该消息由handleBindApplication处理。handleBindApplication将为该进程设置进程名,初始化一些策略和参数信息等。另外,它还创建一个Application对象。同时,如果该Application声明了ContentProvider,还需要为该进程安装ContentProvider。
[–>ActivityStack.java::realStartActivityLocked]
scheduleLaunchActivity用于和应用进程交互,通知它启动目标Activity。而completeResumeLocked将继续AMS的处理流程。
(1) scheduleLaunchActivity函数分析
[–>ActivityThread.java::scheduleLaunchActivity]
[–>ActivityThread.java::scheduleLaunchActivity]
[–>ActivityThread.java::handleLaunchActivity]
handleLaunchActivity的工作包括:
· 首先调用performLaunchActivity,该在函数内部通过Java反射机制创建目标Activity,然后调用它的onCreate及onStart函数。
· 调用handleResumeActivity,会在其内部调用目标Activity的onResume函数。除此之外,handleResumeActivity还完成了一件很重要的事情,见下面的代码:
[–>ActivityThread.java::handleResumeActivity]
根据第2章对MessageQueue的分析,当消息队列中没有其他要处理的消息时,将处理以上代码中通过addIdleHandler添加的Idler对象,也就是说,Idler对象的优先级最低,这是不是说它的工作不重要呢?非也。至少在handleResumeActivity函数中添加的这个Idler并不不简单,其代码如下:
[–>ActivityThread.java::Idler]
由以上代码可知,Idler将为那些已经完成onResume的Activity调用AMS的activityIdle函数。该函数是Activity成功创建并启动的流程中与AMS交互的最后一步。虽然对应用进程来说,Idler处理的优先级最低,但AMS似乎不这么认为,因为它还设置了超时等待,以处理应用进程没有及时调用activityIdle的情况。这个超时等待即由realStartActivityLocked中最后一个关键点completeResumeLocked函数设置。
(2) completeResumeLocked函数分析
[–>ActivityStack.java::completeResumeLocked]
AMS给了应用进程10秒的时间,希望它在10秒内调用activityIdle函数。这个时间不算长,和前面AMS等待应用进程启动的超时时间一样。所以,笔者有些困惑,为什么要把这么重要的操作放到idler中去做。
下面来看activityIdle函数,在其内部将调用ActivityStack activityIdleInternal。
(3) activityIdleInternal函数分析
[–>ActivityStack.java::activityIdleInternal]
final ActivityRecord activityIdleInternal(IBindertoken, boolean fromTimeout,
Configuration config) {
/*
如果应用进程在超时时间内调用了activityIdleInternal函数,则fromTimeout为false
否则,一旦超时,在IDLE_TIMEOUT_MSG的消息处理中也会调用该函数,并设置fromTimeout
为true
*/
ActivityRecord res = null;
ArrayList stops = null;
ArrayList finishes = null;
ArrayList thumbnails = null;
int NS =0;
int NF =0;
int NT =0;
IApplicationThread sendThumbnail = null;
booleanbooting = false;
booleanenableScreen = false;
synchronized (mService) {
//从消息队列中撤销IDLE_TIMEOUT_MSG
if(token != null) mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
int index= indexOfTokenLocked(token);
if(index >= 0) {
ActivityRecord r = mHistory.get(index);
res =r;
//注意,只有fromTimeout为true,才会走执行下面的条件语句
if(fromTimeout) reportActivityLaunchedLocked(fromTimeout, r, -1, -1);
if(config != null) r.configuration =config;
/*
mLaunchingActivity是一个WakeLock,它能防止在操作Activity过程中掉电,同时
这个WakeLock又不能长时间使用,否则有可能耗费过多电量。所以,系统设置了一个超时
处理消息LAUNCH_TIMEOUT_MSG,超时时间为10秒。一旦目标Activity启动成功,
就需要需要释放 WakeLock
*/
if(mResumedActivity == r && mLaunchingActivity.isHeld()) {
mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
mLaunchingActivity.release();
}
r.idle = true;
mService.scheduleAppGcsLocked();
……
ensureActivitiesVisibleLocked(null, 0);
if(mMainStack) {
if(!mService.mBooted) {
mService.mBooted = true;
enableScreen = true;
}
}//if (mMainStack)判断结束
} else if(fromTimeout) {//注意,只有fromTimeout为true,才会走下面的case
reportActivityLaunchedLocked(fromTimeout, null, -1, -1);
}
/*
①processStoppingActivitiesLocked函数返回那些因本次Activity启动而
被暂停(paused)的Activity
*/
stops =processStoppingActivitiesLocked(true);
……
for (i=0;i
(1) startPausingLocked分析
[–>ActivityStack.java::startPausingLocked]
startPausingLocked将调用应用进程的schedulePauseActivity函数,并设置500毫秒的超时时间,所以应用进程需尽快完成相关处理。和scheduleLaunchActivity一样,schedulePauseActivity将向ActivityThread主线程发送PAUSE_ACTIVITY消息,最终该消息由handlePauseActivity来处理。
(2) handlePauseActivity分析
[–>ActivityThread.java::handlePauseActivity]
[–>ActivityManagerService.java::activityPaused]
[–>ActivityStack.java::activityPaused]
(3) completePauseLocked分析
[–>ActivityStack.java::completePauseLocked]
private final void completePauseLocked() {
ActivityRecord prev = mPausingActivity;
if (prev!= null) {
if(prev.finishing) {
prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
} elseif (prev.app != null) {
if(prev.configDestroy) {
destroyActivityLocked(prev, true, false);
} else {
//①将刚才被暂停的Activity保存到mStoppingActivities中
mStoppingActivities.add(prev);
if(mStoppingActivities.size() > 3) {
//如果被暂停的Activity超过3个,则发送IDLE_NOW_MSG消息,该消息最终
//由我们前面介绍的activeIdleInternal处理
scheduleIdleLocked();
}
}
//设置mPausingActivity为null,这是图6-14②、③分支的分割点
mPausingActivity = null;
}
//②resumeTopActivityLocked将启动目标Activity
if(!mService.isSleeping()) resumeTopActivityLocked(prev);
……
}
(4) stopActivityLocked分析
根据前面的介绍,此次目标Activity将走完onCreate、onStart和onResume流程,但是被暂停的Activity才刚走完onPause流程,那么它的onStop什么时候调用呢?
答案就在activityIdelInternal中,它将为mStoppingActivities中的成员调用stopActivityLocked函数。
[–>ActivityStack.java::stopActivityLocked]
对应进程的scheduleStopActivity函数将根据visible的情况,向主线程消息循环发送H. STOP_ACTIVITY_HIDE或H. STOP_ACTIVITY_SHOW消息。不论哪种情况,最终都由handleStopActivity来处理。
[–>ActivityThread.java::handleStopActivity]
(5) startPausingLocked总结
· 行程的起点是am。am是Android中很重要的程序,读者务必要掌握它的用法。我们利用am start命令,发起本次目标Activity的启动请求。
· 接下来进入ActivityManagerService和ActivityStack这两个核心类。对于启动Activity来说,这段行程又可分细分为两个阶段:第一阶段的主要工作就是根据启动模式和启动标志找到或创建ActivityRecord及对应的TaskRecord;第二阶段工作就是处理Activity启动或切换相关的工作。
· 首先讨论了AMS直接创建目标进程并运行Activity的流程,其中涉及目标进程的创建,在目标进程中Android运行环境的初始化,目标Activity的创建以及触发onCreate、onStart及onResume等其生命周期中重要函数调用等相关知识点。
· 接着又讨论了AMS先pause当前Activity,然后再创建目标进程并运行Activity的流程。其中牵扯到两个应用进程和AMS的交互,其难度之大可见一斑。
此处列出几个供读者深入研究的点:
· 各种启动模式、启动标志的处理流程。
· Configuration发生变化时Activity的处理,以及在Activity中对状态保存及恢复的处理流程。
· Activity生命周期各个阶段的转换及相关处理。Android 2.3以后新增的与Fragment的生命周期相关的转换及处理。
· 在应用程序运行过程中,可调用Context提供的registerReceiver函数注册一个广播接收者实例。本书将这种广播接收者称为动态注册者或动态接收者。与之相对应,当应用程序不再需要监听广播时(例如当应用程序退到后台时),则要调用unregisterReceiver函数撤销之前注册的BroadcastReceiver实例。
Android定义了三种不同类型的广播发送方式,它们分别是:
· 普通广播发送方式,由sendBroadcast及相关函数发送。以工作中的场景为例,当程序员们正埋头工作之时,如果有人大喊一声“吃午饭去”,前刻还在专心编码的人即作鸟兽散。这种方式即为普通广播发送方式,所有对“吃午饭”感兴趣的接收者都会响应。
· 串行广播发送方式,即ordered广播,由sendOrdedBroadcast及相关函数发送。在该类型方式下,按接收者的优先级将广播一个个地派发给接收者。只有等这一个接收者处理完毕,系统才将该广播派发给下一个接收者。其中,任意一个接收者都可以中止后续的派发流程。还是以工作中的场景为例:经常有项目经理(PM)深夜组织一帮人跟踪bug的状态。PM看见一个bug,问某程序员,“这个bug你能改吗?”如果得到的答案是“暂时不会”或“暂时没时间”,他会将目光转向下一个神情轻松者,直到找到一个担当者为止。这种方式即为ordered广播发送方式,很明显,它的特点是“一个一个来”。
· Sticky广播发送方式,由sendStickyBroadcast及相关函数发送。Sticky的意思是“粘”,其背后有一个很重要的考虑。我们举个例子:假设某广播发送者每5秒发送一次携带自己状态信息的广播,此时某个应用进程注册了一个动态接收者来监听该广播,那么该接收者的OnReceive函数何时被调用呢?在正常情况下需要等这一轮的5秒周期结束后才调用(因为发送者在本周期结束后会主动再发一个广播)。而在Sticky模式下,系统将马上派发该广播给刚注册的接收者。注意,这个广播是系统发送的,其中存储的是上一次广播发送者的状态信息。也就是说,在Sticky模式下,广播接收者能立即得到广播发送者的信息,而不用等到这一轮周期结束。其实就是系统会保存Sticky的广播[⑤],当有新广播接收者来注册时,系统就把Sticky广播发给它。
[–>ContextImpl.java::registerReceiver]
[–>ContextImpl.java::registerReceiverInternal]
以上代码列出了两个关键点:其一是准备一个IIntentReceiver对象;其二是调用AMS的registerReceiver函数。
· BroadcastReceiver内部有一个PendingResult类。该类是Android 2.3以后新增的,用于异步处理广播消息。例如,当BroadcastReceiver收到一个广播时,其onReceive函数将被调用。一般都是在该函数中直接处理该广播。不过,当该广播处理比较耗时,还可采用异步的方式进行处理,即先调用BroadcastReceiver的goAsync函数得到一个PendingResult对象,然后将该对象放到工作线程中去处理,这样onReceive就可以立即返回而不至于耽误太长时间(这一点对于onReceive函数被主线程调用的情况尤为有用)。在工作线程处理完这条广播后,需调用PendingResult的finish函数来完成整个广播的处理流程。
· 广播由AMS发出,而接收及处理工作却在另外一个进程中进行,整个过程一定涉及进程间通信。在图6-17中,虽然在BroadcastReceiver中定义了一个广播接收者,但是它与Binder没有有任何关系,故其并不直接参与进程间通信。与之相反,IIntentReceiver接口则和Binder有密切关系,故可推测广播的接收是由IIntentReceiver接口来完成的。确实,在整个流程中,首先接收到来自AMS的广播的将是该接口的Bn端,即LoadedApk.ReceiverDispather的内部类InnerReceiver。
registerReceiver的返回值是一个Intent,它指向一个匹配过滤条件(由filter参数指明)的Sticky Intent。即使有多个符合条件的Intent,也只返回一个。
[–>ActivityManagerService.java::registerReceiver]
· 在AMS中,BroadcastReceiver的过滤条件由BroadcastFilter表示,该类从IntentFilter派生。由于一个BroadcastReceiver可设置多个过滤条件(即多次为同一个BroadcastReceiver对象调用registerReceiver函数以设置不同的过滤条件),故AMS使用ReceiverList(从ArrayList派生)这种数据类型来表达这种一对多的关系。
· ReceiverList除了能存储多个BroadcastFilter外,还应该有成员指向某一个具体BroadcastReceiver,否则如何知道到底是哪个BroadcastReceiver设置的过滤条件呢?前面说过,BroadcastReceiver接收广播是通过IIntentReceiver接口进行的,故ReceiverList中有receiver成员变量指向IIntentReceiver。
· AMS提供mRegisterReceivers用于保存IIntentReceiver和对应ReceiverList的关系。此外,AMS还提供mReceiverResolver变量用于存储所有动态注册的BroadcastReceiver所设置的过滤条件。
(2) registerReceiver分析之二
[–>ActivityManagerService.java::registerReceiver]
//如果allSticky不为空,则表示有Sticky的Intent,需要立即调度广播发送
为每一个满足IntentFilter的Sticky的intent创建一个BroadcastRecord对象,并将其保存到mParllelBroadcasts数组中,最后,根据情况调度AMS发送广播。
(1) broadcastIntentLocked分析之一
我们分阶段来分析broadcastIntentLocked的工作,先来看第一阶段工作。
[–>ActivityManagerService.java::broadcastIntentLocked]
broadcastIntentLocked第一阶段的工作主要是处理一些特殊的广播消息
(2) broadcastIntentLocked分析之二
[–>ActivityManagerService.java::broadcastIntentLocked]
· 查询满足条件的动态广播接收者及静态广播接收者。
· 当本次广播不为ordered时,需要尽快发送该广播。另外,非ordered的广播都被AMS保存在mParallelBroadcasts中。
(3) broadcastIntentLocked分析之三
int ir = 0;
if(receivers != null) {
StringskipPackages[] = null;
……//处理PACKAGE_ADDED的Intent,系统不希望有些应用程序一安装就启动。
//这类程序的工作原理是什么呢?即在该程序内部监听PACKAGE_ADDED广播。如果系统
//没有这一招防备,则PKMS安装完程序后所发送的PAKCAGE_ADDED消息将触发该应用的启动
……//将动态注册的接收者registeredReceivers的元素合并到receivers中去
//处理完毕后,所有的接收者(无论动态还是静态注册的)都存储到receivers变量中了
if((receivers != null && receivers.size() > 0) || resultTo != null) {
//创建一个BroadcastRecord对象,注意它的receivers中包括所有的接收者
BroadcastRecord r = new BroadcastRecord(intent, callerApp,
callerPackage, callingPid, callingUid, requiredPermission,
receivers, resultTo, resultCode, resultData, map, ordered,
sticky, false);
booleanreplaced = false;
if (replacePending) {
……//替换mOrderedBroadcasts中旧的Intent
}//
if(!replaced) {//如果没有替换,则添加该条广播记录到mOrderedBroadcasts中
mOrderedBroadcasts.add(r);
scheduleBroadcastsLocked();//调度AMS进行广播发送工作
}
}
returnBROADCAST_SUCCESS;
}
注意任何广播对于静态注册者来说,都是ordered,而且该order是全局性的,并非只针对该广播的接收者,故从广播发出到静态注册者的onReceive函数被调用中间经历的这段时间相对较长。
· Client通过调用startService向Service端发送一个Intent,该Intent携带请求信息。而Service的onStartCommand会接受该Intent,并处理之。该方式是Android平台特有的,借助Intent来传递请求。
· Client调用bindService函数和一个指定的Service建立Binder关系,即绑定成功后,Client端将得到处理业务逻辑的Binder Bp端。此后Client直接调用Bp端提供的业务函数向Service端发出请求。注意,在这种方式中,Service的onBind函数被调用,如果该Service支持Binder,需返回一个IBinder对象给客户端。
这两种方式还影响Service对象的生命周期,简单总结如下:
· 对于以startService方式启动的Service对象,其生命周期一直延续到stopSelf或stopService被调用为止。
· 对于以bindService方式启动的Service对象,其生命周期延续到最后一个客户端调用完unbindService为止。
当系统内存不足时,系统如何处理Service。如果Service和UI某个部分绑定(例如类似通知栏中Music播放的信息),那么此Service优先级较高(可通过调用startForeground把自己变成一个前台Service),系统不会轻易杀死这些Service来回收内存。
· 调节进程的调度优先级和调度策略。
· 调节进程的OOM值。
一、ActivityManagerService基本概述
ActivityManagerService(以后简称AMS)是Android中最核心的服务,主要负责系统中四大组件的启动、切换、调度及应用进程的管理和调度等工作,其职责与操作系统中的进程管理和调度模块相类似。AMS由ActivityManagerNative(以后简称AMN)类派生,并实现Watchdog.Monitor和BatteryStatsImpl.BatteryCallback接口。而AMN由Binder派生,实现了IActivityManager接口。
客户端使用ActivityManager类。由于AMS是系统核心服务,很多API不能开放供客户端使用,所以设计者没有让ActivityManager直接加入AMS家族。在ActivityManager类内部通过调用AMN的getDefault函数得到一个ActivityManagerProxy对象,通过它可与AMS通信。
二、ActivityManagerService被的调用轨迹
–>SystemServer.java::ServerThread的run函数//①调用main函数,得到一个Context对象 context =ActivityManagerService.main(factoryTest); //②setSystemProcess:这样SystemServer进程可加到AMS中,并被它管理 ActivityManagerService.setSystemProcess(); //③installSystemProviders:将SettingsProvider放到SystemServer进程中来运行 ActivityManagerService.installSystemProviders(); //④在内部保存WindowManagerService(以后简称WMS) ActivityManagerService.self().setWindowManager(wm); //⑤和WMS交互,弹出“启动进度“对话框 ActivityManagerNative.getDefault().showBootMessage( context.getResources().getText( //该字符串中文为:“正在启动应用程序” com.android.internal.R.string.android_upgrading_starting_apps), false); //⑥AMS是系统的核心,只有它准备好后,才能调用其他服务的systemReady //注意,有少量服务在AMS systemReady之前就绪,它们不影响此处的分析 ActivityManagerService.self().systemReady(newRunnable() { publicvoid run() { startSystemUi(contextF);//启动systemUi。如此,状态栏就准备好了 if(batteryF != null) batteryF.systemReady(); if(networkManagementF != null) networkManagementF.systemReady(); ...... Watchdog.getInstance().start();//启动Watchdog ......//调用其他服务的systemReady函数 }
1.SystemServer的ServerThread线程的 run() 方法调用ActivityManagerService.main 创建ActivityManagerServiceContext对象
2.ActivityManagerService.setSystemProcess();//SystemServer进程可加 到AMS中,并被ActivityManagerService管理;
3.ActivityManagerService.installSystemProviders();//将SettingsProvider放到SystemServer进程中来运行
4.ActivityManagerService.self().setWindowManager(wm);//保存WindowManagerService(WMS)
5.与WMS交互,弹出“启动进度“对话框;
6.ActivityManagerService.self().systemReady;//启动启动systemUi,AMS是系统的核心,只有它准备好后,才能调用其他服务的systemReady
2.1 ActivityManagerService main分析
AMS的main函数将返回一个Context类型的对象,该对象在SystemServer中被其他服务大量使用,如获取该环境中的资源、Java类信息等;在main函数中,我们又列出了4个关键函数:
1⃣️创建AThread线程;
2⃣️ActivityThread的systemMain函数;
3⃣️ ActivityThread.getSystemContext函数(System的上下文环境)
4⃣️AMS的startRunning函数
2.1.1 AThread分析
AThread线程AThread线程名就叫“ActivityManager”,将支持消息循环及处理功能,且创建AMS,然后通知AMS的main函数;
AMS的构造函数分析:
创建BatteryStatsService(BSS)、UsageStatsService(USS)、mProcessStats (ProcessStats类型)、mProcessStatsThread线程,这些都与系统运行状况统计相关
创建/data/system目录,为mCompatModePackages(CompatModePackages类型)和mConfiguration(Configuration类型)等成员变量赋值。
2.1.2调用ActivityThread的systemMain函数
public static final ActivityThread systemMain() { …… //创建一个ActivityThread对象,其构造函数非常简单 ActivityThread thread = new ActivityThread(); thread.attach(true);//调用它的attach函数,注意传递的参数为true returnthread; }
ActivityThread是Android Framework中一个非常重要的类,它代表一个应用进程的主线程(对于应用进程来说,ActivityThread的main函数确实是由该进程的主线程执行),其职责就是调度及执行在该线程中运行的四大组件。
注意应用进程指那些运行APK的进程,它们由Zygote 派生(fork)而来,上面运行了dalvik虚拟机。与应用进程相对的就是系统进程(包括Zygote和SystemServer);
apk文件在/data/app目录下,则为应用APK
(1)ActivityThread.java::systemMain调用thread.attach(true);
private void attach(boolean system) { sThreadLocal.set(this); mSystemThread= system;//判断是否为系统进程 if(!system) { ......//应用进程的处理流程 } else {//系统进程的处理流程,该情况只在SystemServer中处理 //设置DDMS时看到的systemserver进程名为system_process android.ddm.DdmHandleAppName.setAppName("system_process"); try { //ActivityThread的几员大将出场,见后文的分析 mInstrumentation = new Instrumentation(); ContextImpl context = new ContextImpl(); //初始化context,注意第一个参数值为getSystemContext context.init(getSystemContext().mPackageInfo, null, this); Application app = //利用Instrumentation创建一个Application对象 Instrumentation.newApplication(Application.class,context); //一个进程支持多个Application,mAllApplications用于保存该进程中 //的Application对象 mAllApplications.add(app); mInitialApplication = app;//设置mInitialApplication app.onCreate();//调用Application的onCreate函数 }......//try/catch结束 }//if(!system)判断结束 //注册Configuration变化的回调通知 ViewRootImpl.addConfigCallback(newComponentCallbacks2() { publicvoid onConfigurationChanged(Configuration newConfig) { ......//当系统配置发生变化(如语言切换等)时,需要调用该回调 } public void onLowMemory() {} public void onTrimMemory(int level) {} }); }
应用进程
系统进程:SystemServer是一个特殊的应用进程
设置DDMS时看到的systemserver进程名为system_process,创建Instrumentation类(传递系统和组件之间的交互)、Application类(保存了一个全局的application状态,可理解为一种容器,内部包含四大组件,一个进程可以运行多个Application。)及Context类
2.1.3 ActivityThread中的getSystemContext函数分析
public ContextImpl getSystemContext() { synchronized(this) { if(mSystemContext == null) {//单例模式 ContextImplcontext = ContextImpl.createSystemContext(this); //LoadedApk是2.3引入的一个新类,代表一个加载到系统中的APK,“android”,其实就是framework-res.apk LoadedApkinfo = new LoadedApk(this, "android", context, null, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO); //初始化该ContextImpl对象 context.init(info, null, this); //初始化资源信息 context.getResources().updateConfiguration( getConfiguration(),getDisplayMetricsLocked( CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, false)); mSystemContext = context;//保存这个特殊的ContextImpl对象 } } returnmSystemContext; }
systemMain函数将为SystemServer进程搭建一个和应用进程一样的Android运行环境。
SystemServer希望它内部的那些Service也通过Android运行环境交互,因此也需为它创建一个运行环境。由于SystemServer的特殊性,此处调用了systemMain函数,而普通的应用进程将在主线程中调用ActivityThread的main函数来创建Android运行环境。
ActivityThread虽然本意是代表进程的主线程,但是作为一个Java类,它的实例到底由什么线程创建,不是ActivityThread自己能做主的,所以在SystemServer中可以发现,ActivityThread对象由其他线程创建,而在应用进程中,ActivityThread将由主线程来创建。
* Instrumentaion是一个工具类。当它被启用时,系统先创建它,再通过它来创建其他组件。另外,系统和组件之间的交互也将通过Instrumentation来传递
* Application类保存了一个全局的application状态。
* Context是一个接口,通过它可以获取并操作Application对应的资源、类,甚至包含于Application中的四大组件。
2.1.4 AMS的startRunning函数分析
public final void startRunning(String pkg, Stringcls, String action, String data) { synchronized(this) { if (mStartRunning) return; //如果已经调用过该函数,则直接返回 mStartRunning = true; //mTopComponent最终赋值为null mTopComponent = pkg != null && cls != null ? new ComponentName(pkg, cls) : null; mTopAction = action != null ? action : Intent.ACTION_MAIN; mTopData = data; //mTopData最终为null if(!mSystemReady) return; //此时mSystemReady为false,所以直接返回 } systemReady(null);//这个函数很重要,可惜不在本次startRunning中调用 }
2.1.5 ActivityManagerService的main函数总结
AMS的main函数的目的有两个:· 首先也是最容易想到的目的是创建AMS对象。
· 另外一个目的比较隐晦,但是非常重要,那就是创建一个供SystemServer进程使用的Android运行环境。
· ActivityThread中有一个mLooper成员,它代表一个消息循环
· 对于ContextImpl,其成员变量表明它和资源、APK文件有关。
2.2 AMS的setSystemProcess分析
public static void setSystemProcess() { try { ActivityManagerService m = mSelf; //向ServiceManager注册几个服务 ServiceManager.addService("activity",m); //用于打印内存信息 ServiceManager.addService("meminfo", new MemBinder(m)); /* Android4.0新增的,用于打印应用进程使用硬件显示加速方面的信息(Applications Graphics Acceleration Info)。读者通过adb shell dumpsys gfxinfo看看具体的 输出 */ ServiceManager.addService("gfxinfo", new GraphicsBinder(m)); if(MONITOR_CPU_USAGE)//该值默认为true,添加cpuinfo服务 ServiceManager.addService("cpuinfo", new CpuBinder(m)); //向SM注册权限管理服务PermissionController ServiceManager.addService("permission", newPermissionController(m)); /* 重要说明: 向PackageManagerService查询package名为"android"的ApplicationInfo。 注意这句调用:虽然PKMS和AMS同属一个进程,但是二者交互仍然借助Context。 其实,此处完全可以直接调用PKMS的函数。为什么要费如此周折呢 AMS将通过Binder发送请求给PKMS来完成查询功能,Android希望SystemServer中的服务也通过Android运行环境来交互。这更多是从设计上来考虑的,比如组件之间交互接口的统一及未来系统的可扩展性。 */ ApplicationInfo info = //使用AMS的mContext对象 mSelf.mContext.getPackageManager().getApplicationInfo( "android",STOCK_PM_FLAGS); //①调用ActivityThread的installSystemApplicationInfo函数 mSystemThread.**installSystemApplicationInfo**(info); synchronized (mSelf) { //②此处涉及AMS对进程的管理,见下文分析 **ProcessRecord** app = mSelf.newProcessRecordLocked( mSystemThread.getApplicationThread(), info, info.processName);//注意,最后一个参数为字符串,值为“system” app.persistent = true; app.pid = MY_PID; app.maxAdj = ProcessList.SYSTEM_ADJ; //③保存该ProcessRecord对象 mSelf.mProcessNames.put(app.processName, app.info.uid, app); synchronized (mSelf.mPidsSelfLocked) { mSelf.mPidsSelfLocked.put(app.pid, app); } //根据系统当前状态,调整进程的调度优先级和OOM_Adj,后续将详细分析该函数 mSelf.updateLruProcessLocked(app, true,true); } } ......//抛异常 }
2.2.1 ActivityThread的installSystemApplicationInfo函数分析
public voidinstallSystemApplicationInfo(ApplicationInfo info) { synchronized (this) { //返回的ContextImpl对象即之前在AMS的main函数一节中创建的那个对象 ContextImpl context = getSystemContext(); //又调用init初始化该Context,是不是重复调用init了? context.init(new LoadedApk(this, "android", context, info, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO), null, this); //创建一个Profiler对象,用于性能统计 mProfiler = new Profiler(); } }
· 第一次执行init时,在LoadedApk构造函数中第四个表示ApplicationInfo的参数为null。
· 第二次执行init时,LoadedApk构造函数的第四个参数不为空,即该参数将真正指向一个实际的ApplicationInfo,该ApplicationInfo来源于framework-res.apk。
基于上面的信息,某些读者可能马上能想到:Context第一次执行init的目的仅仅是为了创建一个Android运行环境,而该Context并没有和实际的ApplicationInfo绑定。而第二次执行init前,先利用Context和PKMS交互得到一个实际的ApplicationInfo,然后再通过init将此Context和ApplicationInfo绑定。因为framework-res.apk(包括后面将介绍的SettingsProvider.apk)运行在SystemServer中。和其他所有apk一样,它的运行需要一个正确初始化的Android运行环境。
由于framework-res.apk是一个APK文件,和其他APK文件一样,它应该运行在一个进程中。而AMS是专门用于进程管理和调度的,所以运行APK的进程应该在AMS中有对应的管理结构。因此AMS下一步工作就是将这个运行环境和一个进程管理结构对应起来并交由AMS统一管理。
AMS中的进程管理结构是ProcessRecord。
2.2.2 关于ProcessRecord和IApplicationThread的介绍
AMS启动一个位于其他进程的Activity,由于该Activity运行在另外一进程中,因此AMS势必要和该进程进行跨进程通信。答案自然是通过Binder进行通信。Android提供了一个IApplicationThread接口,该接口定义了AMS和应用进程之间的交互函数
AMS通过它可以和应用进程进行交互,例如,AMS启动一个Activity的时候会调用该接口的scheduleLaunchActivity函数。
IApplicationThread的Binder服务端在应用进程中,因为AMS需要监听应用进程的死亡通知。
public final void scheduleStopActivity(IBindertoken, boolean showWindow, intconfigChanges) { queueOrSendMessage(//该函数内部将给一个Handler发送对应的消息 showWindow ? H.STOP_ACTIVITY_SHOW : H.STOP_ACTIVITY_HIDE, token, 0, configChanges); }
IApplicationThread仅仅是AMS和另外一个进程交互的接口,除此之外,AMS还需要更多的有关该进程的信息。在AMS中,进程的信息都保存在ProcessRecord数据结构中。那么,ProcessRecord是什么呢?先来看setSystemProcess的第二个关键点,即newProcessRecordLocked函数,其代码如下:
[–>ActivityManagerService.java::newProcessRecordLocked]
final ProcessRecord newProcessRecordLocked(IApplicationThread thread, ApplicationInfo info, String customProcess) { String proc = customProcess != null ? customProcess : info.processName; BatteryStatsImpl.Uid.Proc ps = null; BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics(); synchronized (stats) { //BSImpl将为该进程创建一个耗电量统计项 ps =stats.getProcessStatsLocked(info.uid, proc); } //创建一个ProcessRecord对象,用于和其他进程通信的thread作为第一个参数 return new ProcessRecord(ps, thread, info, proc); }
–>ProcessRecord.java::ProcessRecord
ProcessRecord(BatteryStatsImpl.Uid.Proc_batteryStats, IApplicationThread_thread,ApplicationInfo _info, String _processName) { batteryStats = _batteryStats; //用于电量统计 info =_info; //保存ApplicationInfo processName = _processName; //保存进程名 //一个进程能运行多个Package,pkgList用于保存package名 pkgList.add(_info.packageName); thread= _thread;//保存IApplicationThread,通过它可以和应用进程交互 //下面这些xxxAdj成员变量和进程调度优先级及OOM_adj有关。以后再分析它的作用 maxAdj= ProcessList.EMPTY_APP_ADJ; hiddenAdj = ProcessList.HIDDEN_APP_MIN_ADJ; curRawAdj = setRawAdj = -100; curAdj= setAdj = -100; //用于控制该进程是否常驻内存(即使被杀掉,系统也会重启它),只有重要的进程才会有此待遇 persistent = false; removed= false; }
ProcessRecord除保存和应用进程通信的IApplicationThread对象外,还保存了进程名、不同状态对应的Oom_adj值及一个ApplicationInfo。一个进程虽然可运行多个Application,但是ProcessRecord一般保存该进程中先运行的那个Application的ApplicationInfo。
至此,已经创建了一个ProcessRecord对象,和其他应用进程不同的是,该对象对应的进程为SystemServer。为了彰显其特殊性,AMS为其中的一些成员变量设置了特定的值:
app.persistent = true;//设置该值为true app.pid =MY_PID;//设置pid为SystemServer的进程号 app.maxAdj= ProcessList.SYSTEM_ADJ;//设置最大OOM_Adj,系统进程默认值为-16 //另外,app的processName被设置成“system”
2.2.3 AMS的setSystemProcess总结
现在来总结回顾setSystemProcess的工作:· 注册AMS、meminfo、gfxinfo等服务到ServiceManager中。
· 根据PKMS返回的ApplicationInfo初始化Android运行环境,并创建一个代表SystemServer进程的ProcessRecord,从此,SystemServer进程也并入AMS的管理范围内。
2.3 AMS的installSystemProviders函数分析
Android提供了一个SettingsProvider来帮助开发者。该Provider在SettingsProvider.apk中,installSystemProviders就会加载该APK并把SettingsProvider放到SystemServer进程中来运行,SystemServer中很多Service都需要向它查询配置信息。此时的SystemServer已经加载了framework-res.apk,现在又要加载另外一个APK文件,这就是多个APK运行在同一进程的典型案例。另外,通过installSystemProviders函数还能见识ContentProvider的安装过程。
[–>ActivityManagerService.java::installSystemProviders]
public static final void installSystemProviders(){ List<ProviderInfo> providers; synchronized (mSelf) { /* 从mProcessNames找到进程名为“system”且uid为SYSTEM_UID的ProcessRecord, 返回值就是前面在installSystemApplication中创建的那个ProcessRecord,它代表 SystemServer进程 */ ProcessRecord app = mSelf.mProcessNames.get("system",Process.SYSTEM_UID); //①关键调用,见下文分析 providers= mSelf.generateApplicationProvidersLocked(app); if(providers != null) { ......//将非系统APK(即未设ApplicationInfo.FLAG_SYSTEM标志)提供的Provider //从providers列表中去掉 } if(providers != null) {//②为SystemServer进程安装Provider mSystemThread.installSystemProviders(providers); } //监视Settings数据库中Secure表的变化,目前只关注long_press_timeout配置的变化 mSelf.mCoreSettingsObserver = new CoreSettingsObserver(mSelf); //UsageStatsService的工作,以后再讨论 mSelf.mUsageStatsService.monitorPackages(); }
在代码中列出了两个关键调用,分别是:
· 调用generateApplicationProvidersLocked函数,该函数返回一个ProviderInfo List。
· 调用ActivityThread的installSystemProviders函数。ActivityThread可以看做是进程的Android运行环境,那么installSystemProviders表示为该进程安装ContentProvider。
1. AMS的 generateApplicationProvidersLocked函数分析
–>ActivityManagerService.java::generateApplicationProvidersLockeprivate final List<ProviderInfo> generateApplicationProvidersLocked( ProcessRecordapp) { List<ProviderInfo> providers = null; try { //①向PKMS查询满足要求的ProviderInfo,最重要的查询条件包括:进程名和进程uid providers = AppGlobals.getPackageManager(). queryContentProviders(app.processName, app.info.uid, STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS); } ...... if(providers != null) { finalint N = providers.size(); for(int i=0; i<N; i++) { //②AMS对ContentProvider的管理,见下文解释 ProviderInfo cpi = (ProviderInfo)providers.get(i); ComponentName comp = new ComponentName(cpi.packageName, cpi.name); ContentProviderRecord cpr = mProvidersByClass.get(comp); if(cpr == null) { cpr = new ContentProviderRecord(cpi, app.info, comp); //ContentProvider在AMS中用ContentProviderRecord来表示 mProvidersByClass.put(comp, cpr);//保存到AMS的mProvidersByClass中 } //将信息也保存到ProcessRecord中 app.pubProviders.put(cpi.name, cpr); //保存PackageName到ProcessRecord中 app.addPackage(cpi.applicationInfo.packageName); //对该APK进行dex优化 ensurePackageDexOpt(cpi.applicationInfo.packageName); } } returnproviders; }
(1) PMS中 queryContentProviders函数分析
[–>PackageManagerService.java::queryContentProviders]
public List<ProviderInfo>queryContentProviders(String processName, int uid,int flags) { ArrayList<ProviderInfo> finalList = null; synchronized (mPackages) { //还记得mProvidersByComponent的作用吗?它以ComponentName为key,保存了 //PKMS扫描APK得到的PackageParser.Provider信息。读者可参考图4-8 finalIterator<PackageParser.Provider> i = mProvidersByComponent.values().iterator(); while(i.hasNext()) { final PackageParser.Provider p = i.next(); //下面的if语句将从这些Provider中搜索本例设置的processName为“system”, //uid为SYSTEM_UID,flags为FLAG_SYSTEM的Provider if (p.info.authority != null && (processName == null ||(p.info.processName.equals(processName) &&p.info.applicationInfo.uid == uid)) && mSettings.isEnabledLPr(p.info, flags) && (!mSafeMode || ( p.info.applicationInfo.flags &ApplicationInfo.FLAG_SYSTEM) != 0)) { if (finalList == null) { finalList = newArrayList<ProviderInfo>(3); } //由PackageParser.Provider得到ProviderInfo,并添加到finalList中 //关于Provider类及ProviderInfo类,可参考图4-5 finalList.add(PackageParser.generateProviderInfo(p,flags)); } } } if(finalList != null) //最终结果按provider的initOrder排序,该值用于表示初始化ContentProvider的顺序 Collections.sort(finalList, mProviderInitOrderSorter); returnfinalList;//返回最终结果 }
由图6-7可知,SettingsProvider设置了其uid为“android.uid.system”,同时在application中设置了process名为“system”。而在framework-res.apk中也做了相同的设置。所以,现在可以确认SettingsProvider将和framework-res.apk运行在同一个进程,即SystemServer中。
提示从运行效率角度来说,这样做也是合情合理的。因为SystemServer的很多Service都依赖Settings数据库,把它们放在同一个进程中,可以降低由于进程间通信带来的效率损失。
(2)关于ContentProvider的介绍
前面介绍的从PKMS那里查询到的ProviderInfo还属于公有财产,现在我们要将它与AMS及ProcessRecord联系起来。
· AMS保存ProviderInfo的原因是它要管理ContentProvider。
· ProcessRecord保存ProviderInfo的原因是ContentProvider最终要落实到一个进程中。其实也是为了方便AMS管理,例如该进程一旦退出,AMS需要把其中的ContentProvider信息从系统中去除。
AMS及ProcessRecord均使用了一个新的数据结构ContentProviderRecord来管理ContentProvider信息。图6-8展示了ContentProviderRecord相应的数据结构。
2 ActivityThread 的installSystemProviders函数分析
在AMS和ProcessRecord中都保存了Provider信息,但这些仅仅都是一些信息,并不是ContentProvider,因此下面要创建一个ContentProvider实例(即SettingsProvider对象)。该工作由ActivityThread的installSystemProviders来完成,–>ActivityThread.java::installSystemProviders
public final void installSystemProviders(List<ProviderInfo>providers) { if(providers != null) //调用installContentProviders,第一个参数真实类型是Application installContentProviders(mInitialApplication, providers); }
–>ActivityThread.java::installContentProviders
private void installContentProviders( Context context, List<ProviderInfo> providers) { finalArrayList<IActivityManager.ContentProviderHolder> results = new ArrayList<IActivityManager.ContentProviderHolder>(); Iterator<ProviderInfo> i = providers.iterator(); while(i.hasNext()) { ProviderInfo cpi = i.next(); //①调用installProvider函数,得到一个IContentProvider对象 IContentProvider cp = installProvider(context, null, cpi, false); if (cp!= null) { IActivityManager.ContentProviderHolder cph = newIActivityManager.ContentProviderHolder(cpi); cph.provider = cp; //将返回的cp保存到results数组中 results.add(cph); synchronized(mProviderMap){ //mProviderRefCountMap,;类型为HashMap<IBinder,ProviderRefCount>, //主要通过ProviderRefCount对ContentProvider进行引用计数控制,一旦引用计数 //降为零,表示系统中没有地方使用该ContentProvider,要考虑从系统中注销它 mProviderRefCountMap.put(cp.asBinder(), new ProviderRefCount(10000)); } } } try { //②调用AMS的publishContentProviders注册这些ContentProvider,第一个参数 //为ApplicationThread ActivityManagerNative.getDefault().publishContentProviders( getApplicationThread(), results); } ...... }
installContentProviders实际上是标准的ContentProvider安装时调用的程序。安装ContentProvider包括两方面的工作:
· 先在ActivityThread中通过installProvider得到一个ContentProvider实例。
· 向AMS发布这个ContentProvider实例。如此这般,一个APK中声明的ContentProvider才能登上历史舞台,发挥其该有的作用。
提示 上述工作其实和Binder Service类似,一个Binder Service也需要先创建,然后注册到ServiceManager中。
马上来看ActivityThread的installProvider函数。
(1) ActivityThread的installProvider函数分析
–>ActivityThread.java::installProvider]
private IContentProvider installProvider(Contextcontext, IContentProvider provider, ProviderInfoinfo, boolean noisy) { //注意本例所传的参数:context为mInitialApplication,provider为null,info不为null, // noisy为false ContentProvider localProvider = null; if(provider == null) { Context c = null; ApplicationInfo ai = info.applicationInfo; /* 下面这个if判断的作用就是为该ContentProvider找到对应的Application。 在AndroidManifest.xml中,ContentProvider是Application的子标签,所以 ContentProvider和Application有一种对应关系。在本例中,传入的context( 其实是mInitialApplication)代表的是framework-res.apk,而Provider代表的 是SettingsProvider。而SettingsProvider.apk所对应的Application还未创建, 所以下面的判断语句最终会进入最后的else分支 */ if(context.getPackageName().equals(ai.packageName)) { c= context; }else if (mInitialApplication != null && mInitialApplication.getPackageName().equals(ai.packageName)){ c = mInitialApplication; } else { try{ //ai.packageName应该是SettingsProvider.apk的Package, //名为“com.android.providers.settings” //下面将创建一个Context,指向该APK c = context.createPackageContext(ai.packageName, Context.CONTEXT_INCLUDE_CODE); } }//if(context.getPackageName().equals(ai.packageName))判断结束 if (c == null) return null; try { /* 为什么一定要找到对应的Context呢?除了ContentProvider和Application的 对应关系外,还有一个决定性原因:即只有对应的Context才能加载对应APK的Java字节码, 从而可通过反射机制生成ContentProvider实例 */ finaljava.lang.ClassLoader cl = c.getClassLoader(); //通过Java反射机制得到真正的ContentProvider, //此处将得到一个SettingsProvider对象 localProvider=(ContentProvider)cl.loadClass(info.name).newInstance(); //从ContentProvider中取出其mTransport成员(见下文分析) provider =localProvider.getIContentProvider(); if (provider == null) return null; //初始化该ContentProvider,内部会调用其onCreate函数 localProvider.attachInfo(c, info); }...... }//if(provider == null)判断结束 synchronized (mProviderMap) { /* ContentProvider必须指明一个和多个authority,在第4章曾经提到过, 在URL中host:port的组合表示一个authority。这个单词不太好理解,可简单 认为它用于指定ContentProvider的位置(类似网站的域名) */ String names[] =PATTERN_SEMICOLON.split(info.authority); for (int i=0; i<names.length; i++) { ProviderClientRecord pr = newProviderClientRecord(names[i], provider, localProvider); try { //下面这句对linkToDeath的调用颇让人费解,见下文分析 provider.asBinder().linkToDeath(pr, 0); mProviderMap.put(names[i], pr); }...... }//for循环结束 if(localProvider != null) { // mLocalProviders用于存储由本进程创建的ContentProvider信息 mLocalProviders.put(provider.asBinder(), new ProviderClientRecord(null, provider, localProvider)); } }//synchronized 结束 return provider; }
· ContentProvider类本身只是一个容器,而跨进程调用的支持是通过内部类Transport实现的。Transport从ContentProviderNative派生,而ContentProvider的成员变量mTransport指向该Transport对象。ContentProvider的getIContentProvider函数即返回mTransport成员变量。
· ContentProviderNative从Binder派生,并实现了IContentProvider接口。其内部类ContentProviderProxy是供客户端使用的。
· ProviderClientRecord是ActivityThread提供的用于保存ContentProvider信息的一个数据结构。它的mLocalProvider用于保存ContentProvider对象,mProvider用于保存IContentProvider对象。另外一个成员mName用于保存该ContentProvider的一个authority。注意,ContentProvider可以定义多个authority,就好像一个网站有多个域名一样。
(2) ASM的 publishContentProviders分析
publishContentProviders函数用于向AMS注册ContentProviders,
–>ActivityManagerService.java::publishContentProviders
publicfinal void publishContentProviders(IApplicationThread caller, List<ContentProviderHolder>providers) { ...... synchronized(this){ //找到调用者所在的ProcessRecord对象 finalProcessRecord r = getRecordForAppLocked(caller); ...... finallong origId = Binder.clearCallingIdentity(); final intN = providers.size(); for (inti=0; i<N; i++) { ContentProviderHolder src = providers.get(i); ...... //①注意:先从该ProcessRecord中找对应的ContentProviderRecord ContentProviderRecord dst = r.pubProviders.get(src.info.name); if(dst != null) { ComponentName comp = newComponentName(dst.info.packageName, dst.info.name); //以ComponentName为key,保存到mProvidersByClass中 mProvidersByClass.put(comp, dst); String names[] = dst.info.authority.split(";"); for (int j = 0; j < names.length; j++) mProvidersByName.put(names[j], dst);//以authority为key,保存 //mLaunchingProviders用于保存处于启动状态的Provider int NL = mLaunchingProviders.size(); int j; for (j=0; j<NL; j++) { if (mLaunchingProviders.get(j) ==dst) { mLaunchingProviders.remove(j); j--; NL--; }// }//for (j=0; j<NL; j++)结束 synchronized (dst) { dst.provider = src.provider; dst.proc = r; dst.notifyAll(); }//synchronized结束 updateOomAdjLocked(r);//每发布一个Provider,需要调整对应进程的oom_adj }//for(int j = 0; j < names.length; j++)结束 }//for(int i=0; i<N; i++)结束 Binder.restoreCallingIdentity(origId); }// synchronized(this)结束 }
publishContentProviders的工作流程:
· 先根据调用者的pid找到对应的ProcessRecord对象。
· 该ProcessRecord的pubProviders中保存了ContentProviderRecord信息。该信息由前面介绍的AMS的generateApplicationProvidersLocked函数根据Package本身的信息生成。此处将判断要发布的ContentProvider是否由该Package声明。
· 如果判断返回成功,则将该ContentProvider及其对应的authority加到mProvidersByName中。注意,AMS中还有一个mProvidersByClass变量,该变量以ContentProvider的ComponentName为key,即系统提供多种方式找到某一个ContentProvider,一种是通过 authority,另一种方式就是指明ComponentName。
· mLaunchingProviders和最后的notifyAll函数用于通知那些等待ContentProvider所在进程启动的客户端进程。例如,进程A要查询一个数据库,需要通过进程B中的某个ContentProvider 来实施。如果B还未启动,那么AMS就需要先启动B。在这段时间内,A需要等待B启动并注册对应的ContentProvider。B一旦完成注册,就需要告知A退出等待以继续后续的查询工作。
2.4 ASM的systemReady分析
1. systemReady第一阶段的工作
public void systemReady(final RunnablegoingCallback) { synchronized(this){ ...... if(!mDidUpdate) {//判断是否为升级 if(mWaitingUpdate) return; //升级未完成,直接返回 //准备PRE_BOOT_COMPLETED广播 Intent intent = newIntent(Intent.ACTION_PRE_BOOT_COMPLETED); List<ResolveInfo> ris = null; //向PKMS查询该广播的接收者 ris= AppGlobals.getPackageManager().queryIntentReceivers( intent, null,0); ......//从返回的结果中删除那些非系统APK的广播接收者 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE); //读取/data/system/called_pre_boots.dat文件,这里存储了上次启动时候已经 //接收并处理PRE_BOOT_COMPLETED广播的组件。鉴于该广播的特殊性,系统希望 //该广播仅被这些接收者处理一次 ArrayList<ComponentName>lastDoneReceivers = readLastDonePreBootReceivers(); final ArrayList<ComponentName> doneReceivers= newArrayList<ComponentName>(); ......//从PKMS返回的接收者中删除那些已经处理过该广播的对象 for (int i=0; i<ris.size(); i++) { ActivityInfo ai = ris.get(i).activityInfo; ComponentName comp = newComponentName(ai.packageName, ai.name); doneReceivers.add(comp); intent.setComponent(comp); IIntentReceiver finisher = null; if (i == ris.size()-1) { //为最后一个广播接收者注册一个回调通知,当该接收者处理完广播后,将调用该 //回调 finisher = new IIntentReceiver.Stub() { public voidperformReceive(Intent intent, int resultCode, Stringdata, Bundle extras, boolean ordered, booleansticky) { mHandler.post(newRunnable() { public void run(){ synchronized(ActivityManagerService.this) { mDidUpdate = true; } //保存那些处理过该广播的接收者信息 writeLastDonePreBootReceivers(doneReceivers); showBootMessage(mContext.getText( R.string.android_upgrading_complete), false); systemReady(goingCallback); }//run结束 });// new Runnable结束 }//performReceive结束 };//finisher创建结束 }// if (i == ris.size()-1)判断结束 //发送广播给指定的接收者 broadcastIntentLocked(null, null, intent,null, finisher, 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID); if (finisher != null) mWaitingUpdate = true; } if(mWaitingUpdate) return; mDidUpdate= true; } mSystemReady = true; if(!mStartRunning) return; }//synchronized(this)结束
systemReady第一阶段的工作并不轻松,其主要职责是发送并处理与PRE_BOOT_COMPLETED广播相关的事情。目前代码中还没有接收该广播的地方,不过从代码中的注释中可猜测到,该广播接收者的工作似乎和系统升级有关。
2. systemReady第二阶段的工作
ArrayList<ProcessRecord>procsToKill = null; synchronized(mPidsSelfLocked) { for(int i=mPidsSelfLocked.size()-1; i>=0; i--) { ProcessRecord proc = mPidsSelfLocked.valueAt(i); //从mPidsSelfLocked中找到那些先于AMS启动的进程,哪些进程有如此能耐, //在AMS还未启动完毕就启动完了呢?对,那些声明了persistent为true的进程有可能 if(!isAllowedWhileBooting(proc.info)){ if (procsToKill == null) procsToKill = new ArrayList<ProcessRecord>(); procsToKill.add(proc); } }//for结束 }// synchronized结束 synchronized(this){ if(procsToKill != null) { for (int i=procsToKill.size()-1; i>=0; i--) { ProcessRecord proc = procsToKill.get(i); //把这些进程关闭,removeProcessLocked函数比较复杂,以后再分析 removeProcessLocked(proc, true, false); } } //至此,系统已经准备完毕 mProcessesReady = true; } synchronized(this) { if(mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) { }//和工厂测试有关,不对此进行讨论 } //查询Settings数据,获取一些配置参数 retrieveSettings();
· 杀死那些竟然在AMS还未启动完毕就先启动的应用进程。注意,这些应用进程一定是APK所在的Java进程,因为只有应用进程才会向AMS注册,而一般Native(例如mediaserver)进程是不会向AMS注册的。
· 从Settings数据库中获取配置信息,目前只取4个配置参数,分别是:”debug_app”(设置需要debug的app的名称)、”wait_for_debugger”(如果为1,则等待调试器,否则正常启动debug_app)、”always_finish_activities”(当一个activity不再有地方使用时,是否立即对它执行destroy)、”font_scale”(用于控制字体放大倍数,这是Android 4.0新增的功能)。以上配置项由Settings数据库的System表提供。
3. systemReady第三阶段的工作
//调用systemReady传入的参数,它是一个Runnable对象,下节将分析此函数 if (goingCallback != null) goingCallback.run(); synchronized (this) { if(mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { try{ //从PKMS中查询那些persistent为1的ApplicationInfo List apps = AppGlobals.getPackageManager(). getPersistentApplications(STOCK_PM_FLAGS); if (apps != null) { int N = apps.size(); int i; for (i=0; i<N; i++) { ApplicationInfo info = (ApplicationInfo)apps.get(i); //由于framework-res.apk已经由系统启动,所以这里需要把它去除 //framework-res.apk的packageName为"android" if (info != null && !info.packageName.equals("android")) addAppLocked(info);//启动该Application所在的进程 } } }...... } mBooting= true; //设置mBooting变量为true,其作用后面会介绍 try { if(AppGlobals.getPackageManager().hasSystemUidErrors()) { ......//处理那些Uid有错误的Application }...... //启动全系统第一个Activity,即Home mMainStack.resumeTopActivityLocked(null); }// synchronized结束 }
(1)goingCallback的run函数分析
ActivityManagerService.self().systemReady(newRunnable() { publicvoid run() { startSystemUi(contextF);//启动SystemUi //调用其他服务的systemReady函数 if(batteryF != null) batteryF.systemReady(); if(networkManagementF != null) networkManagementF.systemReady(); ...... Watchdog.getInstance().start();//启动Watchdog ......//调用其他服务的systemReady函数 }
· 执行startSystemUi,在该函数内部启动SystemUIService,该Service和状态栏有关。
· 调用一些服务的systemReady函数。
· 启动Watchdog。
startSystemUi的代码如下:
[–>SystemServer.java::startSystemUi]
static final void startSystemUi(Context context) { Intentintent = new Intent(); intent.setComponent(new ComponentName("com.android.systemui", "com.android.systemui.SystemUIService")); context.startService(intent); }
SystemUIService由SystemUi.apk提供,它实现了系统的状态栏。
(2) 启动Home界面
–>ActivityStack.java::resumeTopActivityLocked
final boolean resumeTopActivityLocked(ActivityRecord prev) { //找到下一个要启动的Activity ActivityRecord next = topRunningActivityLocked(null); finalboolean userLeaving = mUserLeaving; mUserLeaving = false; if (next== null) { //如果下一个要启动的ActivityRecord为空,则启动Home if(mMainStack) {//全系统就一个ActivityStack,所以mMainStack永远为true //mService指向AMS return mService.startHomeActivityLocked();//mService指向AMS } } ......//以后再详细分析 }
->ActivityManagerService.java::startHomeActivityLocked
boolean startHomeActivityLocked() {
Intentintent = new Intent( mTopAction,
mTopData != null ? Uri.parse(mTopData) :null);
intent.setComponent(mTopComponent);
if(mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL)
intent.addCategory(Intent.CATEGORY_HOME);//添加Category为HOME类别
//向PKMS查询满足条件的ActivityInfo
ActivityInfo aInfo =
intent.resolveActivityInfo(mContext.getPackageManager(),
STOCK_PM_FLAGS);
if(aInfo != null) {
intent.setComponent(new ComponentName(
aInfo.applicationInfo.packageName,aInfo.name));
ProcessRecordapp = getProcessRecordLocked(aInfo.processName,
aInfo.applicationInfo.uid);
//在正常情况下,app应该为null,因为刚开机,Home进程肯定还没启动
if(app == null || app.instrumentationClass == null) {
intent.setFlags(intent.getFlags()|
Intent.FLAG_ACTIVITY_NEW_TASK);
//启动Home
mMainStack.startActivityLocked(null, intent, null, null, 0, aInfo,
null, null, 0, 0, 0, false, false,null);
}
}//if(aInfo != null)判断结束
return true;
}
(3) 发送ACTION_BOOT_COMPLETED广播
当Home Activity启动后,ActivityStack的activityIdleInternal函数将被调用,其中有一句代码颇值得注意:
[–>ActivityStack.java::activityIdleInternal]
final ActivityRecord activityIdleInternal(IBindertoken, boolean fromTimeout, Configuration config) { booleanbooting = false; ...... if(mMainStack) { booting = mService.mBooting; //在systemReady的第三阶段工作中设置该值为true mService.mBooting = false; } ...... if(booting) mService.finishBooting();//调用AMS的finishBooting函数 }
[–>ActivityManagerService.java::finishBooting]
final void finishBooting() { IntentFilter pkgFilter = new IntentFilter(); pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); pkgFilter.addDataScheme("package"); mContext.registerReceiver(new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { ......//处理Package重启的广播 } }, pkgFilter); synchronized (this) { finalint NP = mProcessesOnHold.size(); if (NP> 0) { ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>(mProcessesOnHold); for(int ip=0; ip<NP; ip++)//启动那些等待启动的进程 startProcessLocked(procs.get(ip), "on-hold", null); } if(mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { //每15钟检查系统各应用进程使用电量的情况,如果某进程使用WakeLock时间 //过长,AMS将关闭该进程 Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG); mHandler.sendMessageDelayed(nmsg, POWER_CHECK_DELAY); //设置系统属性sys.boot_completed的值为1 SystemProperties.set("sys.boot_completed","1"); //发送ACTION_BOOT_COMPLETED广播 broadcastIntentLocked(null, null, newIntent(Intent.ACTION_BOOT_COMPLETED, null), null, null, 0, null,null, android.Manifest.permission.RECEIVE_BOOT_COMPLETED, false, false, MY_PID,Process.SYSTEM_UID); } } }
2.5 ActivityManagerService总结
· AMS的main函数:创建AMS实例,其中最重要的工作是创建Android运行环境,得到一个ActivityThread和一个Context对象。· AMS的setSystemProcess函数:该函数注册AMS和meminfo等服务到ServiceManager中。另外,它为SystemServer创建了一个ProcessRecord对象。由于AMS是Java世界的进程管理及调度中心,要做到对Java进程一视同仁,尽管SystemServer贵为系统进程,此时也不得不将其并入AMS的管理范围内。
· AMS的installSystemProviders:为SystemServer加载SettingsProvider。
· AMS的systemReady:做系统启动完毕前最后一些扫尾工作。该函数调用完毕后,HomeActivity将呈现在用户面前。
三、startActivity分析
3.1 am 脚本
am和pm(见4.4.2节)一样,也是一个脚本,它用来和AMS交互,如启动Activity、启动Service、发送广播等。其核心文件在Am.java中,代码如下:[–>Am.java::main]
public static void main(String[] args) { try { (new Am()).run(args);//构造一个Am对象,并调用run函数 }...... }
am启动一个activity
am start -W -n com.dfp.test/.TestActivity
–>Am.java::run
privatevoid run(String[] args) throws Exception { mAm =ActivityManagerNative.getDefault(); mArgs =args; String op= args[0]; mNextArg =1; if (op.equals("start")) runStart();//用于启动Activity else if ......//处理其他参数 }
runStart函数用于处理Activity启动请求
privatevoid runStart() throws Exception { Intentintent = makeIntent(); StringmimeType = intent.getType(); //获取mimeType, if(mimeType == null && intent.getData() != null && "content".equals(intent.getData().getScheme())) { mimeType = mAm.getProviderMimeType(intent.getData()); } if(mStopOption) { ......//处理-S选项,即先停止对应的Activity,再启动它 } //FLAG_ACTIVITY_NEW_TASK这个标签很重要 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); ParcelFileDescriptor fd = null; if(mProfileFile != null) { try{......//处理-P选项,用于性能统计 fd = ParcelFileDescriptor.open(......) }...... } IActivityManager.WaitResult result = null; int res; if(mWaitOption) {//mWaitOption控制是否等待启动结果,如果有-W选项,则该值为true //调用AMS的startActivityAndWait函数 result = mAm.startActivityAndWait(null,intent, mimeType, null, 0, null, null, 0,false, mDebugOption, mProfileFile, fd,mProfileAutoStop); res= result.result; } ...... ......//打印结果 }
3.2 AMS的startActivityAndWait函数分析
–>ActiivtyManagerService.java::startActivityAndWait原型publicfinal WaitResult startActivityAndWait( /* 在绝大多数情况下,一个Acitivity的启动是由一个应用进程发起的,IApplicationThread是 应用进程和AMS交互的通道,也可算是调用进程的标示,在本例中,AM并非一个应用进程,所以 传递的caller为null */ IApplicationThread caller, //Intent及resolvedType,在本例中,resolvedType为null Intentintent, String resolvedType, //下面两个参数和授权有关,读者可参考第3章对CopyboardService分析中介绍的授权知识 Uri[] grantedUriPermissions,//在本例中为null intgrantedMode,//在本例中为0 IBinder resultTo,//在本例中为null,用于接收startActivityForResult的结果 StringresultWho,//在本例中为null //在本例中为0,该值的具体意义由调用者解释。如果该值大于等于0,则AMS内部保存该值, //并通过onActivityResult返回给调用者 int requestCode, boolean onlyIfNeeded,//本例为false boolean debug,//是否调试目标进程 //下面3个参数和性能统计有关 StringprofileFile, ParcelFileDescriptor profileFd, booleanautoStopProfiler)
–>ActivityManagerService.java::startActivityAndWait
publicfinal WaitResult startActivityAndWait(IApplicationThread caller, Intent intent, String resolvedType, Uri[]grantedUriPermissions, int grantedMode, IBinder resultTo,StringresultWho, int requestCode, booleanonlyIfNeeded, boolean debug,String profileFile, ParcelFileDescriptor profileFd, booleanautoStopProfiler) { //创建WaitResult对象用于存储处理结果 WaitResult res = new WaitResult(); //mMainStack为ActivityStack类型,调用它的startActivityMayWait函数 mMainStack.startActivityMayWait(caller, -1, intent, resolvedType, grantedUriPermissions, grantedMode, resultTo, resultWho, requestCode, onlyIfNeeded, debug, profileFile, profileFd, autoStopProfiler, res, null);//最后一个参数为Configuration, //在本例中为null returnres; }
mMainStack为AMS的成员变量,类型为ActivityStack,该类是Activity调度的核心角色。正式分析它之前,有必要先介绍一下相关的基础知识。
1. Task、Back Stack、ActivityStack及Launch mode
用户在Android系统上想干的三件事情,分别用A、B、C表示,将每一件事情称为一个Task。一个Task还可细分为多个子步骤,即Activity。
(1) 关于Task及Back Stack的介绍
Android采用了Stack的方法管理这3个Activity。例如在A1启动A2后,A2入栈成为栈顶成员,A1成为栈底成员,而界面显示的是栈顶成员的内容。当按返回键时,A3出栈,这时候A2成为栈顶,界面显示也相应变成了A2。
以上是一个Task的情况。
对多Task的情况来说,系统只支持一个处于前台的Task,即用户当前看到的Activity所属的Task,其余的Task均处于后台,这些后台Task内部的Activity保持顺序不变。用户可以一次将整个Task挪到后台或者置为前台。
(2) 关于ActivityStack的介绍
· Task内部Activity的组织方式。由图6-11可知,Android通过先入后出的方式来组织Activity。数据结构中的Stack即以这种方式工作。
· 多个Task的组织及管理方式。
Android设计了一个ActivityStack类来负责上述工作,它的组成如图6-13所示。
· Activity由ActivityRecord表示,Task由TaskRecord表示。ActivityRecord的task成员指向该Activity所在的Task。state变量用于表示该Activity所处的状态(包括INITIALIZING、RESUMED、PAUSED等状态)。
· ActivityStack用mHistory这个ArrayList保存ActivityRecord。令人大跌眼镜的是,该mHistory保存了系统中所有Task的ActivityRecord,而不是针对某个Task进行保存。
· ActivityStack的mMainStack成员比较有意思,它代表此ActivityStack是否为主ActivityStack。有主必然有从,但是目前系统中只有一个ActivityStack,并且它的mMainStack为true。从ActivityStack的命名可推测,Android在开发之初也想用ActivityStack来管理单个Task中的ActivityRecord(在ActivityStack.java的注释中说过,该类为“State and management of asingle stack of activities”),但不知何故,在现在的代码实现将所有Task的ActivityRecord都放到mHistory中了,并且依然保留mMainStack。
· ActivityStack中没有成员用于保存TaskRecord。
由上述内容可知,ActivityStack采用数组的方式保存所有Task的ActivityRecord,并且没有成员保存TaskRecord。
ActivityStack中几个常用的搜索ActivityRecord的函数
–>ActivityStack.java::topRunningActivityLocked
/* topRunningActivityLocked: 找到栈中第一个与notTop不同的,并且不处于finishing状态的ActivityRecord。当notTop为 null时,该函数即返回栈中第一个需要显示的ActivityRecord。提醒读者,栈的出入口只能是栈顶。 虽然mHistory是一个数组,但是查找均从数组末端开始,所以其行为也粗略符合Stack的定义 */ final ActivityRecord topRunningActivityLocked(ActivityRecord notTop) { int i =mHistory.size()-1; while (i>= 0) { ActivityRecord r = mHistory.get(i); if (!r.finishing && r != notTop) return r; i--; } returnnull; }
类似的函数还有:
[–>ActivityStack.java::topRunningNonDelayedActivityLocked]
/* topRunningNonDelayedActivityLocked 与topRunningActivityLocked类似,但ActivityRecord要求增加一项,即delayeResume为 false */ final ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) { int i =mHistory.size()-1; while(i >= 0) { ActivityRecord r = mHistory.get(i); //delayedResume变量控制是否暂缓resume Activity if (!r.finishing && !r.delayedResume&& r != notTop) return r; i--; } returnnull; }
ActivityStack还提供findActivityLocked函数以根据Intent及ActivityInfo来查找匹配的ActivityRecord,同样,查找也是从mHistory尾端开始,相关代码如下:
[–>ActivityStack.java::findActivityLocked]
private ActivityRecord findActivityLocked(Intentintent, ActivityInfo info) { ComponentName cls = intent.getComponent(); if(info.targetActivity != null) cls= new ComponentName(info.packageName, info.targetActivity); final intN = mHistory.size(); for (inti=(N-1); i>=0; i--) { ActivityRecord r = mHistory.get(i); if (!r.finishing) if (r.intent.getComponent().equals(cls))return r; } return null; }
private ActivityRecord findTaskLocked(Intentintent, ActivityInfo info) { ComponentName cls = intent.getComponent(); if(info.targetActivity != null) cls= new ComponentName(info.packageName, info.targetActivity); TaskRecord cp = null; final intN = mHistory.size(); for (inti=(N-1); i>=0; i--) { ActivityRecord r = mHistory.get(i); //r.task!=cp,表示不搜索属于同一个Task的ActivityRecord if(!r.finishing && r.task != cp && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) { cp = r.task; //如果Task的affinity相同,则返回这条ActivityRecord if(r.task.affinity != null) { if(r.task.affinity.equals(info.taskAffinity)) return r; }else if (r.task.intent != null &&r.task.intent.getComponent().equals(cls)) { //如果Task Intent的ComponentName相同 return r; }else if (r.task.affinityIntent != null &&r.task.affinityIntent.getComponent().equals(cls)) { //Task affinityIntent考虑 return r; }//if (r.task.affinity != null)判断结束 }//if(!r.finishing && r.task != cp......)判断结束 }//for循环结束 returnnull; }
findTaskLocked是根据mHistory中ActivityRecord所属的Task的情况来进行相应的查找工作。
(3) 关于Launch Mode的介绍
Launch Mode用于描述Activity的启动模式,目前一共有4种模式,分别是standard、singleTop、singleTask和singleInstance。启动模式就是用于控制Activity和Task关系的。
· standard:一个Task中可以有多个相同类型的Activity。注意,此处是相同类型的Activity,而不是同一个Activity对象。例如在Task中有A、B、C、D4个Activity,如果再启动A类Activity, Task就会变成A、B、C、D、A。最后一个A和第一个A是同一类型,却并非同一对象。另外,多个Task中也可以有同类型的Activity。
· singleTop:当某Task中有A、B、C、D4个Activity时,如果D想再启动一个D类型的Activity,那么Task将是什么样子呢?在singleTop模式下,Task中仍然是A、B、C、D,只不过D的onNewIntent函数将被调用以处理这个新Intent,而在standard模式下,则Task将变成A、B、C、D、D,最后的D为新创建的D类型Activity对象。在singleTop这种模式下,只有目标Acitivity当前正好在栈顶时才有效,例如只有处于栈顶的D启动时才有用,如果D启动不处于栈顶的A、B、C等,则无效。
· singleTask:在这种启动模式下,该Activity只存在一个实例,并且将和一个Task绑定。当需要此Activity时,系统会以onNewIntent方式启动它,而不会新建Task和Activity。注意,该Activity虽只有一个实例,但是在Task中除了它之外,还可以有其他的Activity。
· singleInstance:它是singleTask的加强版,即一个Task只能有这么一个设置了singleInstance的Activity,不能再有别的Activity。而在singleTask模式中,Task还可以有其他的Activity。
Android还有其他一些标志用于控制Activity及Task之间的关系:
· FLAG_ACTIVITY_NEW_TASK:将目标Activity放到一个新的Task中。
· FLAG_ACTIVITY_CLEAR_TASK:当启动一个Activity时,先把和目标Activity有关联的Task“干掉“,然后启动一个新的Task,并把目标Activity放到新的Task中。该标志必须和FLAG_ACTIVITY_NEW_TASK标志一起使用。
· FLAG_ACTIVITY_CLEAR_TOP:当启动一个不处于栈顶的Activity时候,先把排在它前面的Activity“干掉”。例如Task有A、B、C、D4个Activity,要要启动B,直接把C、D“干掉”,而不是新建一个B。
2. ActivityStack的startActivityMayWait函数分析
startActivityMayWait函数的目标是启动com.dfp.test.TestActivity,假设系统之前没有启动过该Activity,本例最终的结果将是:
· 由于在am中设置了FLAG_ACTIVITY_NEW_TASK标志,因此除了会创建一个新的ActivityRecord外,还会新创建一个TaskRecord。
· 还需要启动一个新的应用进程以加载并运行com.dfp.test.TestActivity的一个实例。
· 如果TestActivity不是Home,还需要停止当前正在显示的Activity。
好了,将这个函数分三部分进行介绍,先来分析第一部分。
(1) startActivityMayWait分析之一
[–>ActivityStack.java::startActivityMayWait]
final int startActivityMayWait(IApplicationThread caller, int callingUid,
Intent intent, String resolvedType, Uri[] grantedUriPermissions,
int grantedMode, IBinder resultTo,
String resultWho, int requestCode, boolean onlyIfNeeded,
boolean debug, String profileFile, ParcelFileDescriptor profileFd,
boolean autoStopProfiler, WaitResult outResult, Configuration config) {
……
//在本例中,已经指明了Component,这样可省去为Intent匹配搜索之苦
booleancomponentSpecified = intent.getComponent() != null;
//创建一个新的Intent,防止客户传入的Intent被修改 intent =new Intent(intent); //查询满足条件的ActivityInfo,在resolveActivity内部和PKMS交互,读者不妨自己
//尝试分析该函数
ActivityInfoaInfo = resolveActivity(intent, resolvedType, debug,
profileFile, profileFd,autoStopProfiler);
synchronized(mService) { int callingPid; if (callingUid >= 0) { callingPid= -1; } else if (caller == null) {//本例中,caller为null callingPid= Binder.getCallingPid();//取出调用进程的Pid //取出调用进程的Uid。在本例中,调用进程是am,它由shell启动 callingUid= Binder.getCallingUid(); } else { callingPid= callingUid = -1; }// if (callingUid >= 0)判断结束 //在本例中config为null mConfigWillChange= config != null && mService.mConfiguration.diff(config) != 0; finallong origId = Binder.clearCallingIdentity(); if (mMainStack && aInfo != null&& (aInfo.applicationInfo.flags& ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0){ /* AndroidManifest.xml中的Application标签可以声明一个cantSaveState 属性,设置了该属性的Application将不享受系统提供的状态保存/恢复功能。 当一个Application退到后台时,系统会为它保存状态,当调度其到前台运行时, 将恢复它之前的状态,以保证用户体验的连续性。声明了该属性的Application被称为 “heavy weight process”。可惜系统目前不支持该属性,因为PackageParser 将不解析该属性。详情请见PackageParser.java parseApplication函数 */ }
……//待续
(2) startActivityMayWait分析之二
//调用此函数启动Activity,将返回值保存到res
int res = startActivityLocked(caller, intent,resolvedType,
grantedUriPermissions, grantedMode, aInfo,
resultTo, resultWho, requestCode, callingPid, callingUid,
onlyIfNeeded, componentSpecified, null);
//如果configuration发生变化,则调用AMS的updateConfigurationLocked
//进行处理。关于这部分内容,读者学完本章后可自行分析
if(mConfigWillChange && mMainStack) {
mService.enforceCallingPermission(
android.Manifest.permission.CHANGE_CONFIGURATION,
“updateConfiguration()”);
mConfigWillChange= false;
mService.updateConfigurationLocked(config,null, false);
}
启动Activity的核心函数是startActivityLocked,该函数异常复杂
(3) startActivityMayWait分析之三
if(outResult != null) {
outResult.result = res;//设置启动结果
if(res == IActivityManager.START_SUCCESS) {
//将该结果加到mWaitingActivityLaunched中保存
mWaitingActivityLaunched.add(outResult);
do {
try {
mService.wait();//等待启动结果
}
} while (!outResult.timeout && outResult.who == null);
}else if (res == IActivityManager.START_TASK_TO_FRONT) {
……//处理START_TASK_TO_FRONT结果,读者可自行分析
}
}//if(outResult!= null)结束
return res;
}
}
第三阶段的工作就是根据返回值做一些处理,那么res返回成功(即res== IActivityManager.START_SUCCESS的时候)后为何还需要等待呢?
这是因为目标Activity要运行在一个新的应用进程中,就必须等待那个应用进程正常启动并处理相关请求。注意,只有am设置了-W选项,才会进入wait这一状态。
3.3 startActivityLocked分析
final int startActivityLocked(IApplicationThreadcaller, Intent intent, String resolvedType, Uri[] grantedUriPermissions, int grantedMode, ActivityInfo aInfo, IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid, boolean onlyIfNeeded, boolean componentSpecified, ActivityRecord[]outActivity) { int err = START_SUCCESS; ProcessRecord callerApp = null; //如果caller不为空,则需要从AMS中找到它的ProcessRecord。本例的caller为null if(caller != null) { callerApp = mService.getRecordForAppLocked(caller); //其实就是想得到调用进程的pid和uid if(callerApp != null) { callingPid = callerApp.pid;//一定要保证调用进程的pid和uid正确 callingUid = callerApp.info.uid; }else {//如调用进程没有在AMS中注册,则认为其是非法的 err = START_PERMISSION_DENIED; } }// if (caller != null)判断结束 //下面两个变量意义很重要。sourceRecord用于描述启动目标Activity的那个Activity, //resultRecord用于描述接收启动结果的Activity,即该Activity的onActivityResult //将被调用以通知启动结果,读者可先阅读SDK中startActivityForResult函数的说明 ActivityRecordsourceRecord = null; ActivityRecord resultRecord = null; if(resultTo != null) { //本例resultTo为null, } //获取Intent设置的启动标志,它们是和Launch Mode相类似的“小把戏”, //所以,读者务必理解“关于Launch Mode的介绍”一节的知识点 intlaunchFlags = intent.getFlags(); if((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) { ...... /* 前面介绍的Launch Mode和Activity的启动有关,实际上还有一部分标志用于控制 Activity启动结果的通知。有关FLAG_ACTIVITY_FORWARD_RESULT的作用,读者可 参考SDK中的说明。使用这个标签有个前提,即A必须先存在,正如if中sourceRecord 不为null的判断所示。另外,读者自己可尝试编写例子,以测试FLAG_ACTIVITY_FORWARD_ RESULT标志的作用 */ } //检查err值及Intent的情况 if (err== START_SUCCESS && intent.getComponent() == null) err = START_INTENT_NOT_RESOLVED; ...... //如果err不为0,则调用sendActivityResultLocked返回错误 if (err!= START_SUCCESS) { if(resultRecord != null) {// resultRecord接收启动结果 sendActivityResultLocked(-1,esultRecord, resultWho, requestCode, Activity.RESULT_CANCELED, null); } ....... returnerr; } //检查权限 finalint perm = mService.checkComponentPermission(aInfo.permission, callingPid,callingUid,aInfo.applicationInfo.uid, aInfo.exported); ......//权限检查失败的处理,不必理会 if (mMainStack) { //可为AMS设置一个IActivityController类型的监听者,AMS有任何动静都会回调该 //监听者。不过谁又有如此本领去监听AMS呢?在进行Monkey测试的时候,Monkey会 //设置该回调对象。这样,Monkey就能根据AMS放映的情况进行相应处理了 if(mService.mController != null) { boolean abort = false; try { Intent watchIntent = intent.cloneFilter(); //交给回调对象处理,由它判断是否能继续后面的行程 abort = !mService.mController.activityStarting(watchIntent, aInfo.applicationInfo.packageName); }...... //回调对象决定不启动该Activity。在进行Monkey测试时,可设置黑名单,位于 //黑名单中的Activity将不能启动 if (abort) { .......//通知resultRecord return START_SUCCESS; } } }// if(mMainStack)判断结束 //创建一个ActivityRecord对象 ActivityRecordr = new ActivityRecord(mService, this, callerApp, callingUid, intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho, requestCode, componentSpecified); if(outActivity != null) outActivity[0] = r;//保存到输入参数outActivity数组中 if(mMainStack) { //mResumedActivity代表当前界面显示的Activity if(mResumedActivity == null || mResumedActivity.info.applicationInfo.uid!= callingUid) { //检查调用进程是否有权限切换Application,相关知识见下文的解释 if(!mService.checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) { PendingActivityLaunch pal = new PendingActivityLaunch(); //如果调用进程没有权限切换Activity,则只能把这次Activity启动请求保存起来, //后续有机会时再启动它 pal.r = r; pal.sourceRecord = sourceRecord; ...... //所有Pending的请求均保存到AMS mPendingActivityLaunches变量中 mService.mPendingActivityLaunches.add(pal); mDismissKeyguardOnNextActivity = false; return START_SWITCHES_CANCELED; } }//if(mResumedActivity == null...)判断结束 if (mService.mDidAppSwitch) {//用于控制app switch,见下文解释 mService.mAppSwitchesAllowedTime = 0; } else{ mService.mDidAppSwitch = true; } //启动处于Pending状态的Activity mService.doPendingActivityLaunchesLocked(false); }// if(mMainStack)判断结束 //调用startActivityUncheckedLocked函数 err =startActivityUncheckedLocked(r, sourceRecord, grantedUriPermissions, grantedMode, onlyIfNeeded, true); ...... return err; }
startActivityLocked函数的主要工作包括:
· 处理sourceRecord及resultRecord。其中,sourceRecord表示发起本次请求的Activity,resultRecord表示接收处理结果的Activity(启动一个Activity肯定需要它完成某项事情,当目标Activity将事情成后,就需要告知请求者该事情的处理结果)。在一般情况下,sourceRecord和resultRecord应指向同一个Activity。
· 处理app Switch。如果AMS当前禁止app switch,则只能把本次启动请求保存起来,以待允许app switch时再处理。从代码中可知,AMS在处理本次请求前,会先调用doPendingActivityLaunchesLocked函数,在该函数内部将启动之前因系统禁止app switch而保存的Pending请求。
· 调用startActivityUncheckedLocked处理本次Activity启动请求
1. 关于resume/stopAppSwitches的介绍
AMS提供了两个函数,用于暂时(注意,是暂时)禁止App切换。为什么会有这种需求呢?因为当某些重要(例如设置账号等)Activity处于前台(即用户当前所见的Activity)时,不希望系统因用户操作之外的原因而切换Activity(例如恰好此时收到来电信号而弹出来电界面)。[–>ActivityManagerService.java::stopAppSwitches]
public void stopAppSwitches() { ......//检查调用进程是否有STOP_APP_SWITCHES权限 synchronized(this) { //设置一个超时时间,过了该时间,AMS可以重新切换App(switch app)了 mAppSwitchesAllowedTime = SystemClock.uptimeMillis() + APP_SWITCH_DELAY_TIME; mDidAppSwitch = false;//设置mDidAppSwitch为false mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG); Message msg =//防止应用进程调用了stop却没调用resume,5秒后处理该消息 mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG); mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME); } }
· 此处控制机制名叫app switch,而不是activity switch。为什么呢?因为如果从受保护的activity中启动另一个activity,那么这个新activity的目的应该是针对同一任务,这次启动就不应该受app switch的制约,反而应该对其大开绿灯。目前,在执行Settings中设置设备策略(DevicePolicy)时就会stopAppSwitch。
· 执行stopAppSwitch后,应用程序应该调resumeAppSwitches以允许app switch,但是为了防止应用程序有意或无意忘记resume app switch,系统设置了一个超时(5秒)消息,过了此超时时间,系统将处理相应的消息,其内部会resume app switch。
[–>ActivityManagerService::resumeAppSwitches]
public voidresumeAppSwitches() { ......//检查调用进程是否有STOP_APP_SWITCHES权限 synchronized(this) { mAppSwitchesAllowedTime = 0; } //注意,系统并不在此函数内启动那些被阻止的Activity }
在resumeAppSwitches中只设置mAppSwitchesAllowedTime的值为0,它并不处理在stop和resume这段时间内积攒起的Pending请求,那么这些请求是在何时被处理的呢?
· 从前面代码可知,如果在执行resume app switch后,又有新的请求需要处理,则先处理那些pending的请求(调用doPendingActivityLaunchesLocked)。
· 在resumeAppSwitches中并未撤销stopAppSwitches函数中设置的超时消息,所以在处理那条超时消息的过程中,也会处理pending的请求。
在本例中,由于不考虑app switch的情况,那么接下来的工作就是调用startActivityUncheckedLocked函数来处理本次activity的启动请求。此时,我们已经创建了一个ActivityRecord用于保存目标Activity的相关信息。
接下来的工作就是调用startActivityUncheckedLocked函数来处理本次activity的启动请求。此时,我们已经创建了一个ActivityRecord用于保存目标Activity的相关信息。
2. startActivityUncheckedLocked函数分析
startActivityUncheckedLocked函数很长,但是目的比较简单,即为新创建的ActivityRecord找到一个合适的Task。虽然本例最终的结果是创建一个新的Task,但是该函数的处理逻辑却比较复杂。(1) startActivityUncheckedLocked分析之一
final intstartActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord, Uri[] grantedUriPermissions, intgrantedMode, boolean onlyIfNeeded, boolean doResume) { //在本例中,sourceRecord为null,onlyIfNeeded为false,doResume为true finalIntent intent = r.intent; final intcallingUid = r.launchedFromUid; intlaunchFlags = intent.getFlags(); //判断是否需要调用因本次Activity启动而被系统移到后台的当前Activity的 //onUserLeaveHint函数。可阅读SDK文档中关于Activity onUserLeaveHint函数的说明 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) ==0; //设置ActivityRecord的delayedResume为true,本例中的doResume为true if (!doResume) r.delayedResume = true; //在本例中,notTop为null ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null; if(onlyIfNeeded) {....//在本例中,该变量为false,故略去相关代码 } //根据sourceRecord的情况进行对应处理,能理解下面这段if/else的判断语句吗 if(sourceRecord == null) { //如果请求的发起者为空,则当然需要新建一个Task if((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK; }else if (sourceRecord.launchMode ==ActivityInfo.LAUNCH_SINGLE_INSTANCE){ //如果sourceRecord单独占一个Instance,则新的Activity必然处于另一个Task中 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK; } else if(r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) { //如果启动模式设置了singleTask或singleInstance,则也要创建新Task launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK; }//if(sourceRecord== null)判断结束 //如果新Activity和接收结果的Activity不在一个Task中,则不能启动新的Activity if(r.resultTo!= null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { sendActivityResultLocked(-1,r.resultTo, r.resultWho, r.requestCode, Activity.RESULT_CANCELED, null); r.resultTo = null; }
startActivityUncheckedLocked第一阶段的工作还算简单,主要确定是否需要为新的Activity创建一个Task,即是否设置FLAG_ACTIVITY_NEW_TASK标志。
(2) startActivityUncheckedLocked分析之二
booleanaddingToTask = false; TaskRecord reuseTask = null; if(((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 && (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK)== 0) || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { if(r.resultTo == null) { //搜索mHistory,得到一个ActivityRecord ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE ?findTaskLocked(intent, r.info) : findActivityLocked(intent,r.info); if (taskTop != null ){ ......//一堆复杂的逻辑处理,无非就是找到一个合适的Task,然后对应做一些 //处理。此处不讨论这段代码,读者可根据工作中的具体情况进行研究 } }//if(r.resultTo == null)判断结束 }
(3) startActivityUncheckLocked分析之三
if(r.packageName != null) { //判断目标Activity是否已经在栈顶,如果是,需要判断是创建一个新的Activity //还是调用onNewIntent(singleTop模式的处理) ActivityRecord top = topRunningNonDelayedActivityLocked(notTop); if (top != null && r.resultTo == null){ ......//不讨论此段代码 }//if(top != null...)结束 } else { ......//通知错误 returnSTART_CLASS_NOT_FOUND; } //在本例中,肯定需要创建一个Task booleannewTask = false; booleankeepCurTransition = false; if(r.resultTo == null && !addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { if(reuseTask == null) { mService.mCurTask++;//AMS中保存了当前Task的数量 if (mService.mCurTask <= 0) mService.mCurTask = 1; //为该AactivityRecord设置一个新的TaskRecord r.setTask(new TaskRecord(mService.mCurTask, r.info, intent), null,true); }else r.setTask(reuseTask, reuseTask,true); newTask = true; //下面这个函数为Android 4.0新增的,用于处理FLAG_ACTIVITY_TASK_ON_HOME的情况, //请阅读SDK文档对Intent的相关说明 moveHomeToFrontFromLaunchLocked(launchFlags); }elseif......//其他处理情况 //授权控制。在SDK中启动Activity的函数没有授权设置方面的参数。在实际工作中,笔者曾碰 //到过一个有趣的情况:在开发的一款定制系统中,用浏览器下载了受DRM保护的图片, //此时要启动Gallery3D来查看该图片,但是由于为DRM目录设置了读写权限,而Gallery3D //并未声明相关权限,结果抛出异常,导致不能浏览该图片。由于startActivity等函数不能设置 //授权,最终只能修改Gallery3D并为其添加use-permissions项了 if(grantedUriPermissions != null && callingUid > 0) { for(int i=0; i<grantedUriPermissions.length; i++) { mService.grantUriPermissionLocked(callingUid, r.packageName, grantedUriPermissions[i],grantedMode, r.getUriPermissionsLocked()); } mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName, intent, r.getUriPermissionsLocked()); //调用startActivityLocked,此时ActivityRecord和TaskRecord均创建完毕 startActivityLocked(r, newTask, doResume, keepCurTransition); return START_SUCCESS; }//startActivityUncheckLocked函数结束
(4) startActivityLocked函数分析
[–>ActivityStack.java::startActivityLocked]
private final voidstartActivityLocked(ActivityRecord r, boolean newTask, boolean doResume, boolean keepCurTransition) { final intNH = mHistory.size(); intaddPos = -1; if(!newTask){//如果不是新Task,则从mHistory中找到对应的ActivityRecord的位置 ...... } if(addPos < 0) addPos = NH; //否则加到mHistory数组的最后 mHistory.add(addPos,r); //设置ActivityRecord的inHistory变量为true,表示已经加到mHistory数组中了 r.putInHistory(); r.frontOfTask = newTask; if (NH> 0) { //判断是否显示Activity切换动画之类的事情,需要与WindowManagerService交互 } //最终调用resumeTopActivityLocked if (doResume) resumeTopActivityLocked(null);//重点分析这个函数 }
startActivityUncheckedLocked函数的功能:创建ActivityRecord和TaskRecord并将ActivityRecord添加到mHistory末尾,然后调用resumeTopActivityLocked启动它。
3. resumeTopActivityLocked函数分析
[–>ActivityStack.java::resumeTopActivityLocked]finalboolean resumeTopActivityLocked(ActivityRecord prev) { //从mHistory中找到第一个需要启动的ActivityRecord ActivityRecord next = topRunningActivityLocked(null); finalboolean userLeaving = mUserLeaving; mUserLeaving = false; if (next== null) { //如果mHistory中没有要启动的Activity,则启动Home if(mMainStack) returnmService.startHomeActivityLocked(); } //在本例中,next将是目标Activity next.delayedResume= false; ......//和WMS交互,略去 //将该ActivityRecord从下面几个队列中移除 mStoppingActivities.remove(next); mGoingToSleepActivities.remove(next); next.sleeping = false; mWaitingVisibleActivities.remove(next); //如果当前正在中断一个Activity,需先等待那个Activity pause完毕,然后系统会重新 //调用resumeTopActivityLocked函数以找到下一个要启动的Activity if(mPausingActivity != null) return false; /************************请读者注意***************************/ //①mResumedActivity指向上一次启动的Activity,也就是当前界面显示的这个Activity //在本例中,当前Activity就是Home界面 if(mResumedActivity != null) { //先中断 Home。这种情况放到最后进行分析 startPausingLocked(userLeaving,false); return true; } //②如果mResumedActivity为空,则一定是系统第一个启动的Activity,读者应能猜测到它就 //是Home ......//如果prev不为空,则需要通知WMS进行与Activity切换相关的工作 try { //通知PKMS修改该Package stop状态,详细信息参考第4章“readLPw的‘佐料’” //一节的说明 AppGlobals.getPackageManager().setPackageStoppedState( next.packageName, false); }...... if(prev!= null){ ......//还是和WMS有关,通知它停止绘画 } if(next.app != null && next.app.thread != null) { //如果该ActivityRecord已有对应的进程存在,则只需要重启Activity。就本例而言, //此进程还不存在,所以要先创建一个应用进程 } else { //第一次启动 if (!next.hasBeenLaunched) { next.hasBeenLaunched = true; } else { ......//通知WMS显示启动界面 } //调用另外一个startSpecificActivityLocked函数 startSpecificActivityLocked(next, true, true); } returntrue; }
resumeTopActivityLocked函数中有两个非常重要的关键点:
· 如果mResumedActivity不为空,则需要先暂停(pause)这个Activity。由代码中的注释可知,mResumedActivity代表上一次启动的(即当前正显示的)Activity。现在要启动一个新的Activity,须先停止当前Activity,这部分工作由startPausingLocked函数完成。
· 那么,mResumedActivity什么时候为空呢?当然是在启动全系统第一个Activity时,即启动Home界面的时候。除此之外,该值都不会为空。
先分析第二个关键点,即mResumedActivity为null的情况选择分析此种情况的原因是:如果先分析startPausingLocked,则后续分析会牵扯三个进程,即当前Activity所在进程、AMS所在进程及目标进程,分析的难度相当大。
好了,继续我们的分析。resumeTopActivityLocked最后将调用另外一个startSpecificActivityLocked,该函数将真正创建一个应用进程。
1) startSpecificActivityLocked分析
[–>ActivityStack.java::startSpecificActivityLocked]
private final void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) { //从AMS中查询是否已经存在满足要求的进程(根据processName和uid来查找) //在本例中,查询结果应该为null ProcessRecord app = mService.getProcessRecordLocked(r.processName, r.info.applicationInfo.uid); //设置启动时间等信息 if(r.launchTime == 0) { r.launchTime = SystemClock.uptimeMillis(); if(mInitialStartTime == 0) mInitialStartTime = r.launchTime; } else if(mInitialStartTime == 0) { mInitialStartTime = SystemClock.uptimeMillis(); } //如果该进程存在并已经向AMS注册(例如之前在该进程中启动了其他Activity) if (app!= null && app.thread != null) { try { app.addPackage(r.info.packageName); //通知该进程中的启动目标Activity realStartActivityLocked(r, app, andResume, checkConfig); return; }...... } //如果该进程不存在,则需要调用AMS的startProcessLocked创建一个应用进程 mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,"activity",r.intent.getComponent(), false); }
(2) startProcessLocked分析
[–>ActivityManagerService.java::startProcessLocked]
final ProcessRecord startProcessLocked(StringprocessName, ApplicationInfo info, boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName, boolean allowWhileBooting) { //根据processName和uid寻找是否已经存在ProcessRecord ProcessRecordapp = getProcessRecordLocked(processName, info.uid); if (app!= null && app.pid > 0) { ......//处理相关情况 } StringhostingNameStr = hostingName != null ? hostingName.flattenToShortString() : null; //①处理FLAG_FROM_BACKGROUND标志,见下文解释 if((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) { if(mBadProcesses.get(info.processName, info.uid) != null) return null; } else { mProcessCrashTimes.remove(info.processName,info.uid); if(mBadProcesses.get(info.processName, info.uid) != null) { mBadProcesses.remove(info.processName, info.uid); if (app != null) app.bad =false; } } if (app== null) { //创建一个ProcessRecord,并保存到mProcessNames中。注意,此时还没有创建实际进程 app= newProcessRecordLocked(null, info, processName); mProcessNames.put(processName, info.uid, app); }else app.addPackage(info.packageName); ...... //②调用另外一个startProcessLocked函数 startProcessLocked(app, hostingType, hostingNameStr); return(app.pid != 0) ? app : null; }
在以上代码中列出两个关键点,其中第一点和FLAG_FROM_BACKGROUND有关,相关知识点如下:
· FLAG_FROM_BACKGROUND标识发起这次启动的Task属于后台任务。很显然,手机中没有界面供用户操作位于后台Task中的Activity。如果没有设置该标志,那么这次启动请求就是由前台Task因某种原因而触发的(例如用户单击某个按钮)。
· 如果一个应用进程在1分钟内连续崩溃超过2次,则AMS会将其ProcessRecord加入所谓的mBadProcesses中。一个应用崩溃后,系统会弹出一个警告框以提醒用户。但是,如果一个后台Task启动了一个“BadProcess”,然后该Process崩溃,结果弹出一个警告框,那么用户就会觉得很奇怪:“为什么突然弹出一个框?”因此,此处将禁止后台Task启动“Bad Process”。如果用户主动选择启动(例如单击一个按钮),则不能禁止该操作,并且要把应用进程从mBadProcesses中移除,以给它们“重新做人”的机会。当然,要是该应用每次启动时都会崩溃,这其实是一种安全机制,防止不健全的程序不断启动可能会崩溃的组件,但是这种机制并不限制用户的行为。
[–>ActivityManagerService.java::startProcessLocked]
private final voidstartProcessLocked(ProcessRecord app, String hostingType, StringhostingNameStr) { if(app.pid > 0 && app.pid != MY_PID) { synchronized (mPidsSelfLocked) { mPidsSelfLocked.remove(app.pid); mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); } app.pid = 0; } //mProcessesOnHold用于保存那些在系统还没有准备好就提前请求启动的ProcessRecord mProcessesOnHold.remove(app); updateCpuStats(); System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1); mProcDeaths[0] = 0; try { intuid = app.info.uid; int[] gids = null; try {//从PKMS中查询该进程所属的gid gids = mContext.getPackageManager().getPackageGids( app.info.packageName); }...... ......//工厂测试 intdebugFlags = 0; if((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) { debugFlags |=Zygote.DEBUG_ENABLE_DEBUGGER; debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI; }......//设置其他一些debugFlags //发送消息给Zygote,它将派生一个子进程,该子进程执行ActivityThread的main函数 //注意,我们传递给Zygote的参数并没有包含任何与Activity相关的信息。现在仅仅启动 //一个应用进程 Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread", app.processName, uid, uid, gids, debugFlags, app.info.targetSdkVersion, null); //电量统计项 BatteryStatsImpl bs = app.batteryStats.getBatteryStats(); synchronized (bs) { if(bs.isOnBattery()) app.batteryStats.incStartsLocked(); } //如果该进程为persisitent,则需要通知Watchdog,实际上processStarted内部只 //关心刚才创建的进程是不是com.android.phone if(app.persistent) { Watchdog.getInstance().processStarted(app.processName, startResult.pid); } app.pid= startResult.pid; app.usingWrapper = startResult.usingWrapper; app.removed = false; synchronized (mPidsSelfLocked) { //以pid为key,将代表该进程的ProcessRecord对象加入到mPidsSelfLocked中保管 this.mPidsSelfLocked.put(startResult.pid, app); //发送一个超时消息,如果这个新创建的应用进程10秒内没有和AMS交互,则可断定 //该应用进程启动失败 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG); msg.obj = app; //正常的超时时间为10秒。不过如果该应用进程通过valgrind加载,则延长到300秒 //valgrind是Linux平台上一款检查内存泄露的程序,被加载的应用将在它的环境中工作, //这项工作需耗费较长时间。读者可查询valgrind的用法 mHandler.sendMessageDelayed(msg,startResult.usingWrapper ?PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT); }...... }
4. startActivity分析之半程总结
5. 应用进程的创建及初始化
应用进程的入口是ActivityThread的main函数,它是在主线程中执行的[–>ActivityThread.java::main]
public static void main(String[] args) { SamplingProfilerIntegration.start(); //和调试及strictMode有关 CloseGuard.setEnabled(false); //设置进程名为"<pre-initialized>" Process.setArgV0("<pre-initialized>"); //准备主线程消息循环 Looper.prepareMainLooper(); if(sMainThreadHandler == null) sMainThreadHandler = new Handler(); //创建一个ActivityThread对象 ActivityThread thread = new ActivityThread(); //①调用attach函数,注意其参数值为false thread.attach(false); Looper.loop(); //进入主线程消息循环 throw newRuntimeException("Main thread loop unexpectedly exited"); }
在main函数内部将创建一个消息循环Loop,接着调用ActivityThread的attach函数,最终将主线程加入消息循环。
我们在分析AMS的setSystemProcess时曾分析过ActivityThread的attach函数,那时传入的参数值为true。现在来看设置其为false的情况:
[–>ActivityThread.java::attach]
private void attach(boolean system) { sThreadLocal.set(this); mSystemThread = system; if(!system) { ViewRootImpl.addFirstDrawHandler(new Runnable() { public void run() { ensureJitEnabled(); } }); //设置在DDMS中看到的本进程的名字为"<pre-initialized>" android.ddm.DdmHandleAppName.setAppName("<pre-initialized>"); //设置RuntimeInit的mApplicationObject参数,后续会介绍RuntimeInit类 RuntimeInit.setApplicationObject(mAppThread.asBinder()); //获取和AMS交互的Binder客户端 IActivityManager mgr = ActivityManagerNative.getDefault(); try { //①调用AMS的attachApplication,mAppThread为ApplicationThread类型, //它是应用进程和AMS交互的接口 mgr.attachApplication(mAppThread); }...... } else......// system process的处理 ViewRootImpl.addConfigCallback(newComponentCallbacks2() {.......//添加回调函数}); }
我们知道,AMS创建一个应用进程后,会设置一个超时时间(一般是10秒)。如果超过这个时间,应用进程还没有和AMS交互,则断定该进程创建失败。所以,应用进程启动后,需要尽快和AMS交互,即调用AMS的attachApplication函数。在该函数内部将调用attachApplicationLocked,所以此处直接分析attachApplicationLocked,先看其第一阶段的工作。
(1) attachApplicationLocked分析之一
[–>ActivityManagerService.java::attachApplicationLocked]
private final booleanattachApplicationLocked(IApplicationThread thread, int pid) {//此pid代表调用进程的pid ProcessRecord app; if (pid != MY_PID && pid >= 0) { synchronized (mPidsSelfLocked) { app = mPidsSelfLocked.get(pid);//根据pid查找对应的ProcessRecord对象 } }else app = null; /* 如果该应用进程由AMS启动,则它一定在AMS中有对应的ProcessRecord,读者可回顾前面创建 应用进程的代码:AMS先创建了一个ProcessRecord对象,然后才发命令给Zygote。 如果此处app为null,表示AMS没有该进程的记录,故需要“杀死”它 */ if (app== null) { if(pid > 0 && pid != MY_PID) //如果pid大于零,且不是SystemServer进程,则 //Quietly(即不打印任何输出)”杀死”process Process.killProcessQuiet(pid); else{ //调用ApplicationThread的scheduleExit函数。应用进程完成处理工作后 //将退出运行 //为何不像上面一样直接杀死它呢?可查阅linux pid相关的知识并自行解答 thread.scheduleExit(); } returnfalse; } /* 判断app的thread是否为空,如果不为空,则表示该ProcessRecord对象还未和一个 应用进程绑定。注意,app是根据pid查找到的,如果旧进程没有被杀死,系统则不会重用 该pid。为什么此处会出现ProcessRecord thread不为空的情况呢?见下面代码的注释说明 */ if(app.thread != null) handleAppDiedLocked(app, true, true); StringprocessName = app.processName; try { /* 创建一个应用进程讣告接收对象。当应用进程退出时,该对象的binderDied将被调 用。这样,AMS就能做相应处理。binderDied函数将在另外一个线程中执行,其内部也会 调用handleAppDiedLocked。假如用户在binderDied被调用之前又启动一个进程, 那么就会出现以上代码中app.thread不为null的情况。这是多线程环境中常出现的 情况,不熟悉多线程编程的读者要仔细体会。 */ AppDeathRecipient adr = new AppDeathRecipient(pp, pid, thread); thread.asBinder().linkToDeath(adr, 0); app.deathRecipient = adr; }...... //设置该进程的调度优先级和oom_adj等成员 app.thread= thread; app.curAdj = app.setAdj = -100; app.curSchedGroup = Process.THREAD_GROUP_DEFAULT; app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE; app.forcingToForeground = null; app.foregroundServices = false; app.hasShownUi = false; app.debugging = false; //启动成功,从消息队列中撤销PROC_START_TIMEOUT_MSG消息 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
attachApplicationLocked第一阶段的工作比较简单:
· 设置代表该应用进程的ProcessRecrod对象的一些成员变量,例如用于和应用进程交互的thread对象、进程调度优先级及oom_adj的值等。
· 从消息队列中撤销PROC_START_TIMEOUT_MSG。
至此,该进程启动成功,但是这一阶段的工作仅针对进程本身(如设置调度优先级,oom_adj等),还没有涉及和Activity启动相关的内容,这部分工作将在第二阶段完成。
(2) attachApplicationLocked分析之二
[–>ActivityManagerService.java::attachApplicationLocked]
//SystemServer早就启动完毕,所以normalMode为true booleannormalMode = mProcessesReady || isAllowedWhileBooting(app.info); /* 我们在6.2.3的标题1中分析过generateApplicationProvidersLocked函数, 在该函数内部将查询(根据进程名,uid确定)PKMS以获取需运行在该进程中的ContentProvider */ Listproviders = normalMode ? generateApplicationProvidersLocked(app) : null; try { int testMode = IApplicationThread.DEBUG_OFF; if(mDebugApp != null && mDebugApp.equals(processName)) { ......//处理debug选项 } ......//处理Profile boolean isRestrictedBackupMode = false; ......// //dex化对应的apk包 ensurePackageDexOpt(app.instrumentationInfo!= null ? app.instrumentationInfo.packageName : app.info.packageName); //如果设置了Instrumentation类,该类所在的Package也需要dex化 if(app.instrumentationClass != null) ensurePackageDexOpt(app.instrumentationClass.getPackageName()); ApplicationInfo appInfo =app.instrumentationInfo != null ? app.instrumentationInfo :app.info; //查询该Application使用的CompatibiliyInfo app.compat =compatibilityInfoForPackageLocked(appInfo); if (profileFd != null) //用于记录性能文件 profileFd = profileFd.dup(); //①通过ApplicationThread和应用进程交互,调用其bindApplication函数 thread.bindApplication(processName,appInfo, providers, app.instrumentationClass, profileFile, profileFd, profileAutoStop,app.instrumentationArguments, app.instrumentationWatcher,testMode, isRestrictedBackupMode || !normalMode, app.persistent, mConfiguration, app.compat, getCommonServicesLocked(), mCoreSettingsObserver.getCoreSettingsLocked()); //updateLruProcessLocked函数以后再作分析 updateLruProcessLocked(app,false, true); //记录两个时间 app.lastRequestedGc= app.lastLowMemory = SystemClock.uptimeMillis(); }......//try结束 ..//从mProcessesOnHold和mPersistentStartingProcesses中删除相关信息 mPersistentStartingProcesses.remove(app); mProcessesOnHold.remove(app);
第二阶段的工作主要是为调用ApplicationThread的bindApplication做准备
此处先来看它的原型:
/* 正如我们在前面分析时提到的,刚创建的这个进程并不知道自己的历史使命是什么,甚至连自己的 进程名都不知道,只能设为"<pre-initialized>"。其实,Android应用进程的历史使命是 AMS在其启动后才赋予它的,这一点和我们理解的一般意义上的进程不太一样。根据之前的介绍, Android的组件应该运行在Android运行环境中。从OS角度来说,该运行环境需要和一个进程绑定。 所以,创建应用进程这一步只是创建了一个能运行Android运行环境的容器,而我们的工作实际上 还远未结束。 bindApplication的功能就是创建并初始化位于该进程中的Android运行环境 */ public final void bindApplication( StringprocessName,//进程名,一般是package名 ApplicationInfo appInfo,//该进程对应的ApplicationInfo List<ProviderInfo> providers,//在该APackage中声明的Provider信息 ComponentName instrumentationName,//和instrumentation有关 //下面3个参数和性能统计有关 StringprofileFile, ParcelFileDescriptor profileFd, boolean autoStopProfiler, //这两个和Instrumentation有关,在本例中,这几个参数暂时都没有作用 Bundle instrumentationArgs, IInstrumentationWatcherinstrumentationWatcher, intdebugMode,//调试模式 boolean isRestrictedBackupMode, boolean persistent,//该进程是否是persist Configuration config,//当前的配置信息,如屏幕大小和语言等 CompatibilityInfocompatInfo,//兼容信息 //AMS将常用的Service信息传递给应用进程,目前传递的Service信息只有PKMS、 //WMS及AlarmManagerService。读者可参看AMS getCommonServicesLocked函数 Map<String,IBinder> services, BundlecoreSettings)//核心配置参数,目前仅有“long_press”值
(3) attachApplicationLocked分析之三
booleanbadApp = false; booleandidSomething = false; /* 至此,应用进程已经准备好了Android运行环境,下面这句调用代码将返回ActivityStack中 第一个需要运行的ActivityRecord。由于多线程的原因,难道能保证得到的hr就是我们的目标 Activity吗? */ ActivityRecord hr = mMainStack.topRunningActivityLocked(null); if (hr !=null && normalMode) { //需要根据processName和uid等确定该Activity是否运行与目标进程有关 if(hr.app == null && app.info.uid == hr.info.applicationInfo.uid && processName.equals(hr.processName)) { try { //调用AS的realStartActivityLocked启动该Activity,最后两个参数为true if (mMainStack.realStartActivityLocked(hr, app, true, true)) { didSomething = true; } } catch (Exception e) { badApp = true; //设置badApp为true } } else{ //如果hr和目标进程无关,则调用ensureActivitiesVisibleLocked函数处理它 mMainStack.ensureActivitiesVisibleLocked(hr, null, processName, 0); } }// if (hr!= null && normalMode)判断结束 //mPendingServices存储那些因目标进程还未启动而处于等待状态的ServiceRecord if(!badApp && mPendingServices.size() > 0) { ServiceRecord sr = null; try{ for (int i=0; i<mPendingServices.size(); i++) { sr = mPendingServices.get(i); //和Activity不一样的是,如果Service不属于目标进程,则暂不处理 if (app.info.uid != sr.appInfo.uid ||!processName.equals(sr.processName)) continue;//继续循环 //该Service将运行在目标进程中,所以从mPendingService中移除它 mPendingServices.remove(i); i--; //处理此service的启动,以后再作分析 realStartServiceLocked(sr, app); didSomething = true;//设置该值为true } } }...... ......//启动等待的BroadcastReceiver ......//启动等待的BackupAgent,相关代码类似Service的启动 if(badApp) { //如果以上几个组件启动有错误,则设置badApp为true。此处将调用handleAppDiedLocked //进行处理。该函数我们以后再作分析 handleAppDiedLocked(app, false, true); returnfalse; } /* 调整进程的oom_adj值。didSomething表示在以上流程中是否启动了Acivity或其他组件。 如果启动了任一组件,则didSomething为true。读者以后会知道,这里的启动只是向 应用进程发出对应的指令,客户端进程是否成功处理还是未知数。基于这种考虑,所以此处不宜 马上调节进程的oom_adj。 读者可简单地把oom_adj看做一种优先级。如果一个应用进程没有运行任何组件,那么当内存 出现不足时,该进程是最先被系统杀死的。反之,如果一个进程运行的组件越多,那么它就越不易被 系统杀死以回收内存。updateOomAdjLocked就是根据该进程中组件的情况对应调节进程的 oom_adj值的。 */ if(!didSomething) updateOomAdjLocked(); returntrue; }
attachApplicationLocked第三阶段的工作就是通知应用进程启动Activity和Service等组件,其中用于启动Activity的函数是ActivityStack realStartActivityLocked。
此处先来分析应用进程的bindApplication,该函数将为应用进程绑定一个Application。
提示还记得AMS中System Context执行的两次init吗?第二次init的功能就是将Context和对应的Application绑定在一起。
(4) ApplicationThread的bindApplication分析
bindApplication在ApplicationThread中的实现,其代码如下:
[–>ActivityThread.java::bindApplication]
public final void bindApplication(......) { if(services != null)//保存AMS传递过来的系统Service信息 ServiceManager.initServiceCache(services); //向主线程消息队列添加SET_CORE_SETTINGS消息 setCoreSettings(coreSettings); //创建一个AppBindData对象,其实就是用来存储一些参数 AppBindData data = new AppBindData(); data.processName = processName; data.appInfo = appInfo; data.providers = providers; data.instrumentationName = instrumentationName; ......//将AMS传过来的参数保存到AppBindData中 //向主线程发送H.BIND_APPLICATION消息 queueOrSendMessage(H.BIND_APPLICATION, data); }
ApplicationThread接收到来自AMS的指令后,均会将指令中的参数封装到一个数据结构中,然后通过发送消息的方式转交给主线程去处理。BIND_APPLICATION最终将由handleBindApplication函数处理。该函数并不复杂,但是其中有些点是值得关注的,这些点主要是初始化应用进程的一些参数。handleBindApplication函数的代码如下:
[–>ActivityThread.java::handleBindApplication]
private void handleBindApplication(AppBindDatadata) { mBoundApplication = data; mConfiguration = new Configuration(data.config); mCompatConfiguration = new Configuration(data.config); //初始化性能统计对象 mProfiler = new Profiler(); mProfiler.profileFile = data.initProfileFile; mProfiler.profileFd = data.initProfileFd; mProfiler.autoStopProfiler = data.initAutoStopProfiler; //设置进程名。从此,之前那个默默无名的进程终于有了自己的名字 Process.setArgV0(data.processName); android.ddm.DdmHandleAppName.setAppName(data.processName); if(data.persistent) { //对于persistent的进程,在低内存设备上,不允许其使用硬件加速显示 Display display = WindowManagerImpl.getDefault().getDefaultDisplay(); //当内存大于512MB,或者屏幕尺寸大于1024*600,可以使用硬件加速 if(!ActivityManager.isHighEndGfx(display)) HardwareRenderer.disable(false); } //启动性能统计 if(mProfiler.profileFd != null) mProfiler.startProfiling(); //如果目标SDK版本小于12,则设置AsyncTask使用pool executor,否则使用 //serializedexecutor。这些executor涉及Java Concurrent类,对此不熟悉的读者 //请自行学习和研究。 if(data.appInfo.targetSdkVersion <= 12) AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR); //设置timezone TimeZone.setDefault(null); //设置语言 Locale.setDefault(data.config.locale); //设置资源及兼容模式 applyConfigurationToResourcesLocked(data.config, data.compatInfo); applyCompatConfiguration(); //根据传递过来的ApplicationInfo创建一个对应的LoadApk对象 data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo); //对于系统APK,如果当前系统为userdebug/eng版,则需要记录log信息到dropbox的日志记录 if((data.appInfo.flags & (ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0) { StrictMode.conditionallyEnableDebugLogging(); } /* 如目标SDK版本大于9,则不允许在主线程使用网络操作(如Socketconnect等),否则抛出 NetworkOnMainThreadException,这么做的目的是防止应用程序在主线程中因网络操作执行 时间过长而造成用户体验下降。说实话,没有必要进行这种限制,在主线程中是否网络操作 是应用的事情。再说,Socket也可作为进程间通信的手段,在这种情况下,网络操作耗时很短。 作为系统,不应该设置这种限制。另外,Goolge可以提供一些开发指南或规范来指导开发者, 而不应如此蛮横地强加限制。 */ if (data.appInfo.targetSdkVersion> 9) StrictMode.enableDeathOnNetwork(); //如果没有设置屏幕密度,则为Bitmap设置默认的屏幕密度 if((data.appInfo.flags &ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) == 0) Bitmap.setDefaultDensity(DisplayMetrics.DENSITY_DEFAULT); if(data.debugMode != IApplicationThread.DEBUG_OFF){ ......//调试模式相关处理 } IBinder b= ServiceManager.getService(Context.CONNECTIVITY_SERVICE); IConnectivityManager service = IConnectivityManager.Stub.asInterface(b); try { //设置Http代理信息 ProxyPropertiesproxyProperties = service.getProxy(); Proxy.setHttpProxySystemProperty(proxyProperties); } catch(RemoteException e) {} if(data.instrumentationName != null){ //在正常情况下,此条件不满足 } else { //创建Instrumentation对象,在正常情况都再这个条件下执行 mInstrumentation = new Instrumentation(); } //如果Package中声明了FLAG_LARGE_HEAP,则可跳过虚拟机的内存限制,放心使用内存 if((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0) dalvik.system.VMRuntime.getRuntime().clearGrowthLimit(); //创建一个Application,data.info为LoadedApk类型,在其内部会通过Java反射机制 //创建一个在该APK AndroidManifest.xml中声明的Application对象 Applicationapp = data.info.makeApplication( data.restrictedBackupMode, null); //mInitialApplication保存该进程中第一个创建的Application mInitialApplication = app; //安装本Package中携带的ContentProvider if(!data.restrictedBackupMode){ List<ProviderInfo> providers = data.providers; if(providers != null) { //installContentProviders我们已经分析过了 installContentProviders(app, providers); mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000); } } //调用Application的onCreate函数,做一些初始工作 mInstrumentation.callApplicationOnCreate(app); }
由以上代码可知,bindApplication函数将设置一些初始化参数,其中最重要的有:
· 创建一个Application对象,该对象是本进程中运行的第一个Application。
· 如果该Application有ContentProvider,则应安装它们。
提示从以上代码可知,ContentProvider的创建就在bindApplication函数中,其时机早于其他组件的创建。
(5) 应用进程的创建及初始化总结
本节从应用进程的入口函数main开始,分析了应用进程和AMS之间的两次重要交互,它们分别是:
· 在应用进程启动后,需要尽快调用AMS的attachApplication函数,该函数是这个刚呱呱坠地的应用进程第一次和AMS交互。此时的它还默默“无名”,连一个确定的进程名都没有。不过没关系,attachApplication函数将根据创建该应用进程之前所保存的ProcessRecord为其准备一切“手续”。
· attachApplication准备好一切后,将调用应用进程的bindApplication函数,在该函数内部将发消息给主线程,最终该消息由handleBindApplication处理。handleBindApplication将为该进程设置进程名,初始化一些策略和参数信息等。另外,它还创建一个Application对象。同时,如果该Application声明了ContentProvider,还需要为该进程安装ContentProvider。
6. ActivityStack realStartActivityLocked分析
如前所述,AMS调用完bindApplication后,将通过realStartActivityLocked启动Activity。在此之前,要创建完应用进程并初始化Android运行环境(除此之外,连ContentProvider都安装好了)。[–>ActivityStack.java::realStartActivityLocked]
//注意,在本例中该函数的最后两个参数的值都为true final booleanrealStartActivityLocked(ActivityRecord r, ProcessRecord app, boolean andResume, boolean checkConfig) throws RemoteException { r.startFreezingScreenLocked(app, 0); mService.mWindowManager.setAppVisibility(r,true); if(checkConfig) { ......//处理Config发生变化的情况 mService.updateConfigurationLocked(config, r, false); } r.app =app; app.waitingToKill = null; //将ActivityRecord加到ProcessRecord的activities中保存 int idx= app.activities.indexOf(r); if (idx< 0) app.activities.add(r); //更新进程的调度优先级等,以后再分析该函数 mService.updateLruProcessLocked(app, true, true); try { List<ResultInfo> results = null; List<Intent> newIntents = null; if(andResume) { results = r.results; newIntents = r.newIntents; } if(r.isHomeActivity) mService.mHomeProcess = app; //看看是否有dex对应Package的需要 mService.ensurePackageDexOpt( r.intent.getComponent().getPackageName()); r.sleeping = false; r.forceNewConfig = false; ...... //①通知应用进程启动Activity app.thread. scheduleLaunchActivity (new Intent(r.intent), r, System.identityHashCode(r), r.info, mService.mConfiguration, r.compat, r.icicle, results, newIntents, !andResume, mService.isNextTransitionForward(), profileFile, profileFd, profileAutoStop); if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) { ......//处理heavy-weight的情况 } } } ......//try结束 r.launchFailed = false; ...... if(andResume) { r.state = ActivityState.RESUMED; r.stopped = false; mResumedActivity = r;//设置mResumedActivity为目标Activity r.task.touchActiveTime(); //添加该任务到近期任务列表中 if(mMainStack) mService.addRecentTaskLocked(r.task); //②关键函数,见下文分析 completeResumeLocked(r); //如果在这些过程中,用户按了Power键,怎么办? checkReadyForSleepLocked(); r.icicle = null; r.haveState = false; }...... //启动系统设置向导Activity,当系统更新或初次使用时需要进行配置 if(mMainStack) mService.startSetupActivityLocked(); returntrue; }
scheduleLaunchActivity用于和应用进程交互,通知它启动目标Activity。而completeResumeLocked将继续AMS的处理流程。
(1) scheduleLaunchActivity函数分析
[–>ActivityThread.java::scheduleLaunchActivity]
public final void scheduleLaunchActivity(Intentintent, IBinder token, int ident, ActivityInfo info, Configuration curConfig,CompatibilityInfo compatInfo, Bundlestate, List<ResultInfo> pendingResults, List<Intent> pendingNewIntents, boolean notResumed, booleanisForward, StringprofileName, ParcelFileDescriptor profileFd, booleanautoStopProfiler) { ActivityClientRecord r = new ActivityClientRecord(); ......//保存AMS发送过来的参数信息 //向主线程发送消息,该消息的处理在handleLaunchActivity中进行 queueOrSendMessage(H.LAUNCH_ACTIVITY, r); }
[–>ActivityThread.java::scheduleLaunchActivity]
public void handleMessage(Message msg) { switch(msg.what) { case LAUNCH_ACTIVITY: { ActivityClientRecord r = (ActivityClientRecord)msg.obj; //根据ApplicationInfo得到对应的PackageInfo r.packageInfo = getPackageInfoNoCheck( r.activityInfo.applicationInfo, r.compatInfo); //调用handleLaunchActivity处理 handleLaunchActivity(r, null); }break; ...... }
[–>ActivityThread.java::handleLaunchActivity]
private voidhandleLaunchActivity(ActivityClientRecord r, Intent customIntent){ unscheduleGcIdler(); if (r.profileFd != null) {......//略去} handleConfigurationChanged(null, null); /* ①创建Activity,通过Java反射机制创建目标Activity,将在内部完成Activity生命周期 的前两步,即调用其onCreate和onStart函数。至此,我们的目标com.dfp.test.TestActivity 创建完毕 */ Activitya = performLaunchActivity(r, customIntent); if (a !=null) { r.createdConfig = new Configuration(mConfiguration); BundleoldState = r.state; //②调用handleResumeActivity,其内部有个关键点,见下文分析 handleResumeActivity(r.token, false, r.isForward); if(!r.activity.mFinished && r.startsNotResumed) { .......// . r.paused = true; }else { //如果启动错误,通知AMS ActivityManagerNative.getDefault() .finishActivity(r.token,Activity.RESULT_CANCELED, null); } }
handleLaunchActivity的工作包括:
· 首先调用performLaunchActivity,该在函数内部通过Java反射机制创建目标Activity,然后调用它的onCreate及onStart函数。
· 调用handleResumeActivity,会在其内部调用目标Activity的onResume函数。除此之外,handleResumeActivity还完成了一件很重要的事情,见下面的代码:
[–>ActivityThread.java::handleResumeActivity]
final void handleResumeActivity(IBinder token,boolean clearHide, booleanisForward) { unscheduleGcIdler(); //内部调用目标Activity的onResume函数 ActivityClientRecord r = performResumeActivity(token, clearHide); if (r !=null) { finalActivity a = r.activity; final int forwardBit = isForward ? WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0; ...... if(!r.onlyLocalRequest) { //将上面完成onResume的Activity保存到mNewActivities中 r.nextIdle = mNewActivities; mNewActivities = r; //①向消息队列中添加一个Idler对象 Looper.myQueue().addIdleHandler(new Idler()); } r.onlyLocalRequest = false; ...... }
根据第2章对MessageQueue的分析,当消息队列中没有其他要处理的消息时,将处理以上代码中通过addIdleHandler添加的Idler对象,也就是说,Idler对象的优先级最低,这是不是说它的工作不重要呢?非也。至少在handleResumeActivity函数中添加的这个Idler并不不简单,其代码如下:
[–>ActivityThread.java::Idler]
private class Idler implements MessageQueue.IdleHandler{ publicfinal boolean queueIdle() { ActivityClientRecord a = mNewActivities; booleanstopProfiling = false; ...... if (a !=null) { mNewActivities = null; IActivityManager am = ActivityManagerNative.getDefault(); ActivityClientRecord prev; do { if(a.activity != null && !a.activity.mFinished) { //调用AMS的activityIdle am.activityIdle(a.token, a.createdConfig, stopProfiling); a.createdConfig = null; } prev =a; a =a.nextIdle; prev.nextIdle = null; } while(a != null); //do循环结束 }//if(a!=null)判断结束 ...... ensureJitEnabled(); returnfalse; }// queueIdle函数结束 }
由以上代码可知,Idler将为那些已经完成onResume的Activity调用AMS的activityIdle函数。该函数是Activity成功创建并启动的流程中与AMS交互的最后一步。虽然对应用进程来说,Idler处理的优先级最低,但AMS似乎不这么认为,因为它还设置了超时等待,以处理应用进程没有及时调用activityIdle的情况。这个超时等待即由realStartActivityLocked中最后一个关键点completeResumeLocked函数设置。
(2) completeResumeLocked函数分析
[–>ActivityStack.java::completeResumeLocked]
private final voidcompleteResumeLocked(ActivityRecord next) { next.idle = false; next.results = null; next.newIntents = null; //发送一个超时处理消息,默认为10秒。IDLE_TIMEOUT_MSG就是针对acitivityIdle函数的 Messagemsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG); msg.obj= next; mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT); //通知AMS if(mMainStack) mService.reportResumedActivityLocked(next); ......//略去其他逻辑的代码 }
AMS给了应用进程10秒的时间,希望它在10秒内调用activityIdle函数。这个时间不算长,和前面AMS等待应用进程启动的超时时间一样。所以,笔者有些困惑,为什么要把这么重要的操作放到idler中去做。
下面来看activityIdle函数,在其内部将调用ActivityStack activityIdleInternal。
(3) activityIdleInternal函数分析
[–>ActivityStack.java::activityIdleInternal]
这里写代码片
final ActivityRecord activityIdleInternal(IBindertoken, boolean fromTimeout,
Configuration config) {
/*
如果应用进程在超时时间内调用了activityIdleInternal函数,则fromTimeout为false
否则,一旦超时,在IDLE_TIMEOUT_MSG的消息处理中也会调用该函数,并设置fromTimeout
为true
*/
ActivityRecord res = null;
ArrayList stops = null;
ArrayList finishes = null;
ArrayList thumbnails = null;
int NS =0;
int NF =0;
int NT =0;
IApplicationThread sendThumbnail = null;
booleanbooting = false;
booleanenableScreen = false;
synchronized (mService) {
//从消息队列中撤销IDLE_TIMEOUT_MSG
if(token != null) mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
int index= indexOfTokenLocked(token);
if(index >= 0) {
ActivityRecord r = mHistory.get(index);
res =r;
//注意,只有fromTimeout为true,才会走执行下面的条件语句
if(fromTimeout) reportActivityLaunchedLocked(fromTimeout, r, -1, -1);
if(config != null) r.configuration =config;
/*
mLaunchingActivity是一个WakeLock,它能防止在操作Activity过程中掉电,同时
这个WakeLock又不能长时间使用,否则有可能耗费过多电量。所以,系统设置了一个超时
处理消息LAUNCH_TIMEOUT_MSG,超时时间为10秒。一旦目标Activity启动成功,
就需要需要释放 WakeLock
*/
if(mResumedActivity == r && mLaunchingActivity.isHeld()) {
mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
mLaunchingActivity.release();
}
r.idle = true;
mService.scheduleAppGcsLocked();
……
ensureActivitiesVisibleLocked(null, 0);
if(mMainStack) {
if(!mService.mBooted) {
mService.mBooted = true;
enableScreen = true;
}
}//if (mMainStack)判断结束
} else if(fromTimeout) {//注意,只有fromTimeout为true,才会走下面的case
reportActivityLaunchedLocked(fromTimeout, null, -1, -1);
}
/*
①processStoppingActivitiesLocked函数返回那些因本次Activity启动而
被暂停(paused)的Activity
*/
stops =processStoppingActivitiesLocked(true);
……
for (i=0;i
7. startActivity分析之后半程总结
8. startPausingLocked函数分析
当启动一个新Activity时,系统将先行处理当前的Activity,即调用startPausingLocked函数来暂停当前Activity。(1) startPausingLocked分析
[–>ActivityStack.java::startPausingLocked]
private final void startPausingLocked(booleanuserLeaving, boolean uiSleeping) { //mResumedActivity保存当前正显示的Activity, ActivityRecord prev = mResumedActivity; mResumedActivity = null; //设置mPausingActivity为当前Activity mPausingActivity = prev; mLastPausedActivity = prev; prev.state = ActivityState.PAUSING;//设置状态为PAUSING prev.task.touchActiveTime(); ...... if(prev.app != null && prev.app.thread != null) { try { //①调用当前Activity所在进程的schedulePauseActivity函数 prev.app.thread.schedulePauseActivity(prev,prev.finishing, userLeaving,prev.configChangeFlags); if(mMainStack) mService.updateUsageStats(prev, false); } ......//catch分支 }......//else分支 if(!mService.mSleeping && !mService.mShuttingDown) { //获取WakeLock,以防止在Activity切换过程中掉电 mLaunchingActivity.acquire(); if(!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) { Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG); mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT); } } if(mPausingActivity != null) { //暂停输入事件派发 if(!uiSleeping) prev.pauseKeyDispatchingLocked(); //设置PAUSE超时,时间为500毫秒,这个时间相对较短 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG); msg.obj = prev; mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT); }......//else分支 }
startPausingLocked将调用应用进程的schedulePauseActivity函数,并设置500毫秒的超时时间,所以应用进程需尽快完成相关处理。和scheduleLaunchActivity一样,schedulePauseActivity将向ActivityThread主线程发送PAUSE_ACTIVITY消息,最终该消息由handlePauseActivity来处理。
(2) handlePauseActivity分析
[–>ActivityThread.java::handlePauseActivity]
private void handlePauseActivity(IBinder token,boolean finished, boolean userLeaving, int configChanges){ //当Activity处于finishing状态时,finished参数为true,不过在本例中该值为false ActivityClientRecord r = mActivities.get(token); if (r !=null) { //调用Activity的onUserLeaving函数, if(userLeaving) performUserLeavingActivity(r); r.activity.mConfigChangeFlags |=configChanges; //调用Activity的onPause函数 performPauseActivity(token, finished, r.isPreHoneycomb()); ...... try { //调用AMS的activityPaused函数 ActivityManagerNative.getDefault().activityPaused(token); }...... } }
[–>ActivityManagerService.java::activityPaused]
public final void activityPaused(IBinder token) { ...... mMainStack.activityPaused(token, false); }
[–>ActivityStack.java::activityPaused]
final void activityPaused(IBinder token, booleantimeout) { ActivityRecord r = null; synchronized (mService) { int index= indexOfTokenLocked(token); if (index>= 0) { r =mHistory.get(index); //从消息队列中撤销PAUSE_TIMEOUT_MSG消息 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r); if(mPausingActivity == r) { r.state = ActivityState.PAUSED;//设置ActivityRecord的状态 completePauseLocked();//完成本次Pause操作 }...... } }
(3) completePauseLocked分析
[–>ActivityStack.java::completePauseLocked]
private final void completePauseLocked() {
ActivityRecord prev = mPausingActivity;
if (prev!= null) {
if(prev.finishing) {
prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
} elseif (prev.app != null) {
if(prev.configDestroy) {
destroyActivityLocked(prev, true, false);
} else {
//①将刚才被暂停的Activity保存到mStoppingActivities中
mStoppingActivities.add(prev);
if(mStoppingActivities.size() > 3) {
//如果被暂停的Activity超过3个,则发送IDLE_NOW_MSG消息,该消息最终
//由我们前面介绍的activeIdleInternal处理
scheduleIdleLocked();
}
}
//设置mPausingActivity为null,这是图6-14②、③分支的分割点
mPausingActivity = null;
}
//②resumeTopActivityLocked将启动目标Activity
if(!mService.isSleeping()) resumeTopActivityLocked(prev);
……
}
(4) stopActivityLocked分析
根据前面的介绍,此次目标Activity将走完onCreate、onStart和onResume流程,但是被暂停的Activity才刚走完onPause流程,那么它的onStop什么时候调用呢?
答案就在activityIdelInternal中,它将为mStoppingActivities中的成员调用stopActivityLocked函数。
[–>ActivityStack.java::stopActivityLocked]
privatefinal void stopActivityLocked(ActivityRecord r) { if((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) { if(!r.finishing) { requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null, "no-history"); } } elseif (r.app != null && r.app.thread != null) { try { r.stopped = false; //设置STOPPING状态,并调用对应的scheduleStopActivity函数 r.state = ActivityState.STOPPING; r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags); }...... }
对应进程的scheduleStopActivity函数将根据visible的情况,向主线程消息循环发送H. STOP_ACTIVITY_HIDE或H. STOP_ACTIVITY_SHOW消息。不论哪种情况,最终都由handleStopActivity来处理。
[–>ActivityThread.java::handleStopActivity]
private void handleStopActivity(IBinder token,boolean show, int configChanges) { ActivityClientRecord r = mActivities.get(token); r.activity.mConfigChangeFlags |= configChanges; StopInfoinfo = new StopInfo(); //调用Activity的onStop函数 performStopActivityInner(r, info, show, true); ...... try { //调用AMS的activityStopped函数 ActivityManagerNative.getDefault().activityStopped( r.token, r.state, info.thumbnail, info.description); } }
(5) startPausingLocked总结
· 行程的起点是am。am是Android中很重要的程序,读者务必要掌握它的用法。我们利用am start命令,发起本次目标Activity的启动请求。
· 接下来进入ActivityManagerService和ActivityStack这两个核心类。对于启动Activity来说,这段行程又可分细分为两个阶段:第一阶段的主要工作就是根据启动模式和启动标志找到或创建ActivityRecord及对应的TaskRecord;第二阶段工作就是处理Activity启动或切换相关的工作。
· 首先讨论了AMS直接创建目标进程并运行Activity的流程,其中涉及目标进程的创建,在目标进程中Android运行环境的初始化,目标Activity的创建以及触发onCreate、onStart及onResume等其生命周期中重要函数调用等相关知识点。
· 接着又讨论了AMS先pause当前Activity,然后再创建目标进程并运行Activity的流程。其中牵扯到两个应用进程和AMS的交互,其难度之大可见一斑。
此处列出几个供读者深入研究的点:
· 各种启动模式、启动标志的处理流程。
· Configuration发生变化时Activity的处理,以及在Activity中对状态保存及恢复的处理流程。
· Activity生命周期各个阶段的转换及相关处理。Android 2.3以后新增的与Fragment的生命周期相关的转换及处理。
9. startActivity总结
四、Broadcast和BroadcastReceiver分析
· 在AndroidManifest.xml中声明标签。在应用程序运行时,系统会利用Java反射机制构造一个广播接收者实例。本书将这种广播接收者称为静态注册者或静态接收者。· 在应用程序运行过程中,可调用Context提供的registerReceiver函数注册一个广播接收者实例。本书将这种广播接收者称为动态注册者或动态接收者。与之相对应,当应用程序不再需要监听广播时(例如当应用程序退到后台时),则要调用unregisterReceiver函数撤销之前注册的BroadcastReceiver实例。
Android定义了三种不同类型的广播发送方式,它们分别是:
· 普通广播发送方式,由sendBroadcast及相关函数发送。以工作中的场景为例,当程序员们正埋头工作之时,如果有人大喊一声“吃午饭去”,前刻还在专心编码的人即作鸟兽散。这种方式即为普通广播发送方式,所有对“吃午饭”感兴趣的接收者都会响应。
· 串行广播发送方式,即ordered广播,由sendOrdedBroadcast及相关函数发送。在该类型方式下,按接收者的优先级将广播一个个地派发给接收者。只有等这一个接收者处理完毕,系统才将该广播派发给下一个接收者。其中,任意一个接收者都可以中止后续的派发流程。还是以工作中的场景为例:经常有项目经理(PM)深夜组织一帮人跟踪bug的状态。PM看见一个bug,问某程序员,“这个bug你能改吗?”如果得到的答案是“暂时不会”或“暂时没时间”,他会将目光转向下一个神情轻松者,直到找到一个担当者为止。这种方式即为ordered广播发送方式,很明显,它的特点是“一个一个来”。
· Sticky广播发送方式,由sendStickyBroadcast及相关函数发送。Sticky的意思是“粘”,其背后有一个很重要的考虑。我们举个例子:假设某广播发送者每5秒发送一次携带自己状态信息的广播,此时某个应用进程注册了一个动态接收者来监听该广播,那么该接收者的OnReceive函数何时被调用呢?在正常情况下需要等这一轮的5秒周期结束后才调用(因为发送者在本周期结束后会主动再发一个广播)。而在Sticky模式下,系统将马上派发该广播给刚注册的接收者。注意,这个广播是系统发送的,其中存储的是上一次广播发送者的状态信息。也就是说,在Sticky模式下,广播接收者能立即得到广播发送者的信息,而不用等到这一轮周期结束。其实就是系统会保存Sticky的广播[⑤],当有新广播接收者来注册时,系统就把Sticky广播发给它。
4.1 registerReceiver流程分析
1. ContextImpl registerReceiver分析
registerReceiver函数用于注册一个动态广播接收者,该函数在Context.java中声明。根据本章前面对Context家族的介绍(参考图6-3),其功能最终将通过ContextImpl类的registerReceiver函数来完成,可直接去看ContextImpl是如何实现此函数的。在SDK中一共定义了两个同名的registerReceiver函数,其代码如下:[–>ContextImpl.java::registerReceiver]
/* 在SDK中输出该函数,这也是最常用的函数。当广播到来时,BroadcastReceiver对象的onReceive 函数将在主线程中被调用 */ public Intent registerReceiver(BroadcastReceiverreceiver, IntentFilter filter) { returnregisterReceiver(receiver, filter, null, null); } /* 功能和前面类似,但增加了两个参数,分别是broadcastPermission和scheduler,作用有 两个: 其一:对广播者的权限增加了控制,只有拥有相应权限的广播者发出的广播才能被此接收者接收 其二:BroadcastReceiver对象的onReceiver函数可调度到scheduler所在的线程中执行 */ publicIntent registerReceiver(BroadcastReceiver receiver, IntentFilterfilter, String broadcastPermission, Handler scheduler) { /* 注意,下面所调用函数的最后一个参数为getOuterContext的返回值。前面曾说过,ContextImpl为Context家族中真正干活的对象,而它对外的代理人可以是Application和Activity等, getOuterContext就返回这个对外代理人。一般在Activity中调用registerReceiver函数,故此处getOuterContext返回的对外代理人的类型就是Activity。 */ return registerReceiverInternal(receiver, filter, broadcastPermission, scheduler, getOuterContext()); }
[–>ContextImpl.java::registerReceiverInternal]
privateIntent registerReceiverInternal(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler, Context context) { IIntentReceiver rd = null; if(receiver != null) { //①准备一个IIntentReceiver对象 if(mPackageInfo != null && context != null) { //如果没有设置scheduler,则默认使用主线程的Handler if (scheduler == null) scheduler= mMainThread.getHandler(); //通过getReceiverDispatcher函数得到一个IIntentReceiver类型的对象 rd = mPackageInfo.getReceiverDispatcher( receiver, context, scheduler, mMainThread.getInstrumentation(), true); } else { if (scheduler == null) scheduler= mMainThread.getHandler(); //直接创建LoadedApk.ReceiverDispatcher对象 rd = new LoadedApk.ReceiverDispatcher(receiver, context, scheduler, null, true).getIIntentReceiver(); }//if (mPackageInfo != null && context != null)结束 }// if(receiver != null)结束 try { //②调用AMS的registerReceiver函数 return ActivityManagerNative.getDefault().registerReceiver( mMainThread.getApplicationThread(),mBasePackageName, rd, filter,broadcastPermission); } ...... }
以上代码列出了两个关键点:其一是准备一个IIntentReceiver对象;其二是调用AMS的registerReceiver函数。
· BroadcastReceiver内部有一个PendingResult类。该类是Android 2.3以后新增的,用于异步处理广播消息。例如,当BroadcastReceiver收到一个广播时,其onReceive函数将被调用。一般都是在该函数中直接处理该广播。不过,当该广播处理比较耗时,还可采用异步的方式进行处理,即先调用BroadcastReceiver的goAsync函数得到一个PendingResult对象,然后将该对象放到工作线程中去处理,这样onReceive就可以立即返回而不至于耽误太长时间(这一点对于onReceive函数被主线程调用的情况尤为有用)。在工作线程处理完这条广播后,需调用PendingResult的finish函数来完成整个广播的处理流程。
· 广播由AMS发出,而接收及处理工作却在另外一个进程中进行,整个过程一定涉及进程间通信。在图6-17中,虽然在BroadcastReceiver中定义了一个广播接收者,但是它与Binder没有有任何关系,故其并不直接参与进程间通信。与之相反,IIntentReceiver接口则和Binder有密切关系,故可推测广播的接收是由IIntentReceiver接口来完成的。确实,在整个流程中,首先接收到来自AMS的广播的将是该接口的Bn端,即LoadedApk.ReceiverDispather的内部类InnerReceiver。
2. AMS的registerReceiver分析
(1) registerReceiver分析之一registerReceiver的返回值是一个Intent,它指向一个匹配过滤条件(由filter参数指明)的Sticky Intent。即使有多个符合条件的Intent,也只返回一个。
[–>ActivityManagerService.java::registerReceiver]
public Intent registerReceiver(IApplicationThreadcaller, String callerPackage, IIntentReceiver receiver, IntentFilter filter, String permission) { synchronized(this) { ProcessRecord callerApp = null; if(caller != null) { callerApp = getRecordForAppLocked(caller); ....... //如果callerApp为null,则抛出异常,即系统不允许未登记照册的进程注册 //动态广播接收者 //检查调用进程是否有callerPackage的信息,如果没有,也抛异常 if(callerApp.info.uid != Process.SYSTEM_UID && !callerApp.pkgList.contains(callerPackage)){ throw new SecurityException(......); } }......//if(caller != null)判断结束 List allSticky = null; //下面这段代码的功能是从系统中所有Sticky Intent中查询匹配IntentFilter的Intent, //匹配的Intent保存在allSticky中 Iterator actions = filter.actionsIterator(); if(actions != null) { while (actions.hasNext()) { String action = (String)actions.next(); allSticky = getStickiesLocked(action, filter, allSticky); } } ...... //如果存在sticky的Intent,则选取第一个Intent作为本函数的返回值 Intentsticky = allSticky != null ? (Intent)allSticky.get(0) : null; //如果没有设置接收者,则直接返回sticky 的intent if(receiver == null) return sticky; //新的数据类型ReceiverList及mRegisteredReceivers成员变量,见下文的解释 //receiver.asBinder将返回IIntentReceiver的Bp端 ReceiverList rl = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder()); //如果是首次调用,则此处rl的值将为null if (rl== null) { rl =new ReceiverList(this, callerApp, Binder.getCallingPid(), Binder.getCallingUid(),receiver); if (rl.app != null) { rl.app.receivers.add(rl); }else { try { //监听广播接收者所在进程的死亡消息 receiver.asBinder().linkToDeath(rl, 0); }...... rl.linkedToDeath = true; }// if(rl.app != null)判断结束 //将rl保存到mRegisterReceivers中 mRegisteredReceivers.put(receiver.asBinder(), rl); } //新建一个BroadcastFilter对象 BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, permission); rl.add(bf);//将其保存到rl中 // mReceiverResolver成员变量,见下文解释 mReceiverResolver.addFilter(bf);
· 在AMS中,BroadcastReceiver的过滤条件由BroadcastFilter表示,该类从IntentFilter派生。由于一个BroadcastReceiver可设置多个过滤条件(即多次为同一个BroadcastReceiver对象调用registerReceiver函数以设置不同的过滤条件),故AMS使用ReceiverList(从ArrayList派生)这种数据类型来表达这种一对多的关系。
· ReceiverList除了能存储多个BroadcastFilter外,还应该有成员指向某一个具体BroadcastReceiver,否则如何知道到底是哪个BroadcastReceiver设置的过滤条件呢?前面说过,BroadcastReceiver接收广播是通过IIntentReceiver接口进行的,故ReceiverList中有receiver成员变量指向IIntentReceiver。
· AMS提供mRegisterReceivers用于保存IIntentReceiver和对应ReceiverList的关系。此外,AMS还提供mReceiverResolver变量用于存储所有动态注册的BroadcastReceiver所设置的过滤条件。
(2) registerReceiver分析之二
[–>ActivityManagerService.java::registerReceiver]
//如果allSticky不为空,则表示有Sticky的Intent,需要立即调度广播发送
if(allSticky != null) { ArrayList receivers = new ArrayList(); receivers.add(bf); intN = allSticky.size(); for(int i=0; i<N; i++) { Intent intent = (Intent)allSticky.get(i); //为每一个需要发送的广播创建一个BroadcastRecord(暂称之为广播记录)对象 BroadcastRecord r = new BroadcastRecord(intent, null, null, -1, -1, null,receivers, null, 0, null, null, false, true, true); //如果mParallelBroadcasts当前没有成员,则需要触发AMS发送广播 if (mParallelBroadcasts.size() == 0) scheduleBroadcastsLocked();//向AMS发送BROADCAST_INTENT_MSG消息 //所有非ordered广播记录都保存在mParallelBroadcasts中 mParallelBroadcasts.add(r); }//for循环结束 }//if (allSticky != null)判断结束 returnsticky; }//synchronized结束 }
为每一个满足IntentFilter的Sticky的intent创建一个BroadcastRecord对象,并将其保存到mParllelBroadcasts数组中,最后,根据情况调度AMS发送广播。
4.2 sendBroadcast流程分析
[–>ContextImpl.java::sendBroadcast]public void sendBroadcast(Intent intent) { StringresolvedType = intent.resolveTypeIfNeeded(getContentResolver()); try { intent.setAllowFds(false); //调用AMS的brodcastIntent,在SDK中定义的广播发送函数最终都会调用它 ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, null, false, false); }...... }
1. broadcastIntentLocked分析
broadcastIntent函数的主要工作将交由AMS的broadcastIntentLocked来完成,故此处直接分析broadcastIntentLocked。(1) broadcastIntentLocked分析之一
我们分阶段来分析broadcastIntentLocked的工作,先来看第一阶段工作。
[–>ActivityManagerService.java::broadcastIntentLocked]
private final int broadcastIntentLocked(ProcessRecordcallerApp, StringcallerPackage, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundlemap, String requiredPermission, boolean ordered, boolean sticky, int callingPid, int callingUid) { intent =new Intent(intent); //为Intent增加FLAG_EXCLUDE_STOPPED_PACKAGES标志,表示该广播不会传递给被STOPPED //的Package intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES); //处理一些特殊的广播,包括UID_REMOVED,PACKAGE_REMOVED和PACKAGE_ADDED等 finalboolean uidRemoved = Intent.ACTION_UID_REMOVED.equals( intent.getAction()); ......//处理特殊的广播,主要和PACKAGE相关,例如接收到PACKAGE_REMOVED广播后,AMS //需将该Package的组件从相关成员中删除,相关代码可自行阅读 //处理TIME_ZONE变化广播 if(intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) mHandler.sendEmptyMessage(UPDATE_TIME_ZONE); //处理CLEAR_DNS_CACHE广播 if(intent.ACTION_CLEAR_DNS_CACHE.equals(intent.getAction())) mHandler.sendEmptyMessage(CLEAR_DNS_CACHE); //处理PROXY_CHANGE广播 if(Proxy.PROXY_CHANGE_ACTION.equals(intent.getAction())) { ProxyProperties proxy = intent.getParcelableExtra("proxy"); mHandler.sendMessage(mHandler.obtainMessage( UPDATE_HTTP_PROXY,proxy)); }
broadcastIntentLocked第一阶段的工作主要是处理一些特殊的广播消息
(2) broadcastIntentLocked分析之二
[–>ActivityManagerService.java::broadcastIntentLocked]
[-->ActivityManagerService.java::broadcastIntentLocked] //处理发送sticky广播的情况 if(sticky) { ......//检查发送进程是否有BROADCAST_STICKY权限 if(requiredPermission != null) { //在发送Sticky广播的时候,不能携带权限信息 returnBROADCAST_STICKY_CANT_HAVE_PERMISSION; } //在发送Stikcy广播的时候,也不能指定特定的接收对象 if(intent.getComponent() != null) ......//抛异常 //将这个Sticky的Intent保存到mStickyBroadcasts中 ArrayList<Intent> list =mStickyBroadcasts.get(intent.getAction()); if (list== null) { list= new ArrayList<Intent>(); mStickyBroadcasts.put(intent.getAction(), list); } ......//如果list中已经有该intent,则直接用新的intent替换旧的intent //否则将该intent加入到list中保存 if (i >= N) list.add(new Intent(intent)); } //定义两个变量,其中receivers用于保存匹配该Intent的所有广播接收者,包括静态或动态 //注册的广播接收者,registeredReceivers用于保存符合该Intent的所有动态注册者 Listreceivers = null; List<BroadcastFilter>registeredReceivers = null; try { if(intent.getComponent() != null) { ......//如果指定了接收者,则从PKMS中查询它的信息 }else { //FLAG_RECEIVER_REGISTERED_ONLY标签表明该广播只能发给动态注册者 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)== 0) { //如果没有设置前面的标签,则需要查询PKMS,获得那些在AndroidManifest.xml //中声明的广播接收者,即静态广播接收者的信息,并保存到receivers中 receivers = AppGlobals.getPackageManager().queryIntentReceivers( intent, resolvedType,STOCK_PM_FLAGS); } //再从AMS的mReceiverResolver中查询符合条件的动态广播接收者 registeredReceivers =mReceiverResolver.queryIntent(intent, resolvedType, false); } }...... /* 判断该广播是否设置了REPLACE_PENDING标签。如果设置了该标签,并且之前的那个Intent还 没有被处理,则可以用新的Intent替换旧的Intent。这么做的目的是为了减少不必要的广播发送, 但笔者感觉,这个标签的作用并不靠谱,因为只有旧的Intent没被处理的时候,它才能被替换。 因为旧Intent被处理的时间不能确定,所以不能保证广播发送者的一番好意能够实现。因此, 在发送广播时,千万不要以为设置了该标志就一定能节约不必要的广播发送。 */ final boolean replacePending = (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0; //先处理动态注册的接收者 int NR =registeredReceivers != null ? registeredReceivers.size() : 0; //如果此次广播为非串行化发送,并且符合条件的动态注册接收者个数不为零 if(!ordered && NR > 0) { //创建一个BroadcastRecord对象即可,注意,一个BroadcastRecord对象可包括所有的 //接收者(可参考图6-19) BroadcastRecord r = new BroadcastRecord(intent, callerApp, callerPackage, callingPid, callingUid, requiredPermission, registeredReceivers, resultTo, resultCode, resultData, map, ordered, sticky, false); boolean replaced = false; if (replacePending) { ......//从mParalledBroadcasts中查找是否有旧的Intent,如果有就替代它,并设置 //replaced为true } if(!replaced) {//如果没有被替换,则保存到mParallelBroadcasts中 mParallelBroadcasts.add(r); scheduleBroadcastsLocked();//调度一次广播发送 } //至此,动态注册的广播接收者已处理完毕,设置registeredReceivers为null registeredReceivers = null;// NR =0; }
· 查询满足条件的动态广播接收者及静态广播接收者。
· 当本次广播不为ordered时,需要尽快发送该广播。另外,非ordered的广播都被AMS保存在mParallelBroadcasts中。
(3) broadcastIntentLocked分析之三
int ir = 0;
if(receivers != null) {
StringskipPackages[] = null;
……//处理PACKAGE_ADDED的Intent,系统不希望有些应用程序一安装就启动。
//这类程序的工作原理是什么呢?即在该程序内部监听PACKAGE_ADDED广播。如果系统
//没有这一招防备,则PKMS安装完程序后所发送的PAKCAGE_ADDED消息将触发该应用的启动
......//处理ACTION_EXTERNAL_APPLICATIONS_AVAILABLE广播
……//将动态注册的接收者registeredReceivers的元素合并到receivers中去
//处理完毕后,所有的接收者(无论动态还是静态注册的)都存储到receivers变量中了
if((receivers != null && receivers.size() > 0) || resultTo != null) {
//创建一个BroadcastRecord对象,注意它的receivers中包括所有的接收者
BroadcastRecord r = new BroadcastRecord(intent, callerApp,
callerPackage, callingPid, callingUid, requiredPermission,
receivers, resultTo, resultCode, resultData, map, ordered,
sticky, false);
booleanreplaced = false;
if (replacePending) {
……//替换mOrderedBroadcasts中旧的Intent
}//
if(!replaced) {//如果没有替换,则添加该条广播记录到mOrderedBroadcasts中
mOrderedBroadcasts.add(r);
scheduleBroadcastsLocked();//调度AMS进行广播发送工作
}
}
returnBROADCAST_SUCCESS;
}
4.3 BROADCAST_INTENT_MSG消息处理函数
1. broadcastIntentLocked分析
2. processNextBroadcast分析之二
3. processNextBroadcast分析之三
4.4 应用进程处理广播分析
4.5 广播处理总结
注意任何广播对于静态注册者来说,都是ordered,而且该order是全局性的,并非只针对该广播的接收者,故从广播发出到静态注册者的onReceive函数被调用中间经历的这段时间相对较长。
五、startService
Service是Android的四大组件之一。和Activity,BroadcastReceiver相比,Service定位于业务层逻辑处理,而Activity定位于前端UI层逻辑处理,BroadcastReceiver定位于通知逻辑的处理。5.1 Service知识介绍
作为四大组件之一Service,其响应Client的请求方式有两种:· Client通过调用startService向Service端发送一个Intent,该Intent携带请求信息。而Service的onStartCommand会接受该Intent,并处理之。该方式是Android平台特有的,借助Intent来传递请求。
· Client调用bindService函数和一个指定的Service建立Binder关系,即绑定成功后,Client端将得到处理业务逻辑的Binder Bp端。此后Client直接调用Bp端提供的业务函数向Service端发出请求。注意,在这种方式中,Service的onBind函数被调用,如果该Service支持Binder,需返回一个IBinder对象给客户端。
这两种方式还影响Service对象的生命周期,简单总结如下:
· 对于以startService方式启动的Service对象,其生命周期一直延续到stopSelf或stopService被调用为止。
· 对于以bindService方式启动的Service对象,其生命周期延续到最后一个客户端调用完unbindService为止。
当系统内存不足时,系统如何处理Service。如果Service和UI某个部分绑定(例如类似通知栏中Music播放的信息),那么此Service优先级较高(可通过调用startForeground把自己变成一个前台Service),系统不会轻易杀死这些Service来回收内存。
5.2 startService流程图
六、AMS中的进程管理
AMS对进程的管理仅涉及两个方面:· 调节进程的调度优先级和调度策略。
· 调节进程的OOM值。
6.1 Linux进程管理介绍
6.2 关于Android中的进程管理的介绍
6.3 AMS进程管理函数分析
七、App的 Crash处理
7.1 应用进程的Crash处理
7.2 AMS的handleApplicationCrash分析
7.3 AppDeathRecipient binderDied分析
相关文章推荐
- 深入安卓(packageManagerService,activityManagerService_)——极客学院学习笔记
- android内核剖析学习笔记:AMS(ActivityManagerService)内部原理和工作机制
- PowerManagerService学习笔记一
- PackageManagerService学习笔记二-构造方法
- PowerManagerService学习笔记
- android ActivityManagerService 学习 (一)
- Binder学习笔记(二)——defaultServiceManager()返回了什么?
- Android开发学习笔记(十一)ListView/ActivityManager/ArrayAdapter学习
- ActivityManagerService 笔记
- Android ActivityManagerService 笔记(1)
- SystemService 学习笔记之ConnectivityManager
- Service与Activity之间通信(学习笔记)
- android 学习笔记 Activity 和service 的启动过程
- PackageManagerService学习笔记五-构造方法
- PacakgeManagerService学习笔记八-APK installation
- PacakgeManagerService学习笔记九-APK installation
- Binder学习笔记(四)—— ServiceManager如何响应checkService请求
- android ActivityManagerService 学习 (二)
- 《深入理解 Android》笔记:ActivityManagerService