6.2.4 AMS的systemReady分析
作为核心服务,AMS的systemReady会做什么呢?由于该函数内容较多,我们将它的工作分为三个阶段。首先看第一阶段的工作。
1.systemReady第一阶段的工作
该阶段的具体代码如下:
[—>ActivityManagerService.java:systemReady]
public void systemReady(final Runnable goingCallback){
synchronized(this){
……
if(!mDidUpdate){//判断是否为升级操作
if(mWaitingUpdate)return;//升级未完成,直接返回
//准备PRE_BOOT_COMPLETED广播
Intent intent=new Intent(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=
new ArrayList<ComponentName>();
……//从PKMS返回的接收者中删除那些已经处理过该广播的对象
for(int i=0;i<ris.size();i++){
ActivityInfo ai=ris.get(i).activityInfo;
ComponentName comp=new ComponentName(ai.packageName, ai.name);
doneReceivers.add(comp);
intent.setComponent(comp);
IIntentReceiver finisher=null;
if(i==ris.size()-1){
//为最后一个广播接收者注册一个回调通知,当该接收者处理完广播后,将调用该
//回调
finisher=new IIntentReceiver.Stub(){
public void performReceive(Intent intent, int resultCode,
String data, Bundle extras, boolean ordered,
boolean sticky){
mHandler.post(new Runnable(){
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广播相关的事情。目前代码中还没有接收该广播的地方,不过从代码中的注释中可猜测到,该广播接收者的工作似乎和系统升级有关。
建议 如有哪位读者了解与此相关的知识,不妨和大家分享。
下面来介绍systemReady第二阶段的工作。
2.systemReady第二阶段的工作
该阶段的具体工作如下:
[—>ActivityManagerService.java: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();
systemReady第二阶段的工作包括:
杀死那些在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第三阶段的工作
该阶段的具体工作如下:
[—>ActivityManagerService.java: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结束
systemReady第三阶段的工作有3项:
调用systemReady设置的回调对象goingCallback的run函数。
启动那些声明了persistent的APK。
启动桌面。
先看回调对象goingCallback的run函数的工作。
(1)goingCallback的run函数分析
run函数的实现代码如下:
[—>SystemServer.java:ServerThread.run]
ActivityManagerService.self().systemReady(new Runnable(){
public void run(){
startSystemUi(contextF);//启动SystemUi
//调用其他服务的systemReady函数
if(batteryF!=null)batteryF.systemReady();
if(networkManagementF!=null)networkManagementF.systemReady();
……
Watchdog.getInstance().start();//启动Watchdog
……//调用其他服务的systemReady函数
}
run函数比较简单,执行的工作如下:
执行startSystemUi,在该函数内部启动SystemUIService,该Service和状态栏有关。
调用一些服务的systemReady函数。
启动Watchdog。
startSystemUi的实现代码如下:
[—>SystemServer.java:startSystemUi]
static final void startSystemUi(Context context){
Intent intent=new Intent();
intent.setComponent(new ComponentName("com.android.systemui",
"com.android.systemui.SystemUIService"));
context.startService(intent);
}
SystemUIService由SystemUi.apk提供,它实现了系统的状态栏。
注意 在精简ROM时,也不能删除SystemUi.apk。
(2)启动Home界面
如前所述,resumeTopActivityLocked将启动Home界面,此函数非常重要也比较复杂,故以后再详细分析。我们提取了resumeTopActivityLocked启动Home界面时的相关代码,如下所示:
[—>ActivityStack.java:resumeTopActivityLocked]
final boolean resumeTopActivityLocked(ActivityRecord prev){
//找到下一个要启动的Activity
ActivityRecord next=topRunningActivityLocked(null);
final boolean userLeaving=mUserLeaving;
mUserLeaving=false;
if(next==null){
//如果下一个要启动的ActivityRecord为空,则启动Home
if(mMainStack){//全系统就一个ActivityStack,所以mMainStack永远为true
//mService指向AMS
return mService.startHomeActivityLocked();//mService指向AMS
}
}
……//以后再详细分析
}
下面来看AMS的startHomeActivityLocked函数,其实现代码如下:
[—>ActivityManagerService.java:startHomeActivityLocked]
boolean startHomeActivityLocked(){
Intent intent=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));
ProcessRecord app=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;
}
至此,AMS中的Service都启动完毕,Home也靓丽登场,整个系统准备完毕,只等待用户的检验了。不过在分析逻辑上还有一点没涉及,那会是什么呢?
(3)发送ACTION_BOOT_COMPLETED广播
由前面的代码可知,AMS发送了ACTION_PRE_BOOT_COMPLETED广播,可系统中没有地方处理它。在前面的章节中,还碰到一个ACTION_BOOT_COMPLETED广播,该广播广很受欢迎,却不知道它是在哪里发送的。
当Home Activity启动后,ActivityStack的activityIdleInternal函数将被调用,其中有一句代码颇值得注意:
[—>ActivityStack.java:activityIdleInternal]
final ActivityRecord activityIdleInternal(IBinder token, boolean fromTimeout,
Configuration config){
boolean booting=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){
final int 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,
new Intent(Intent.ACTION_BOOT_COMPLETED, null),
null, null,0,null, null,
android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
false, false, MY_PID, Process.SYSTEM_UID);
}
}
}
原来,在Home启动成功后,AMS才发送ACTION_BOOT_COMPLETED广播。
4.AMS的systemReady总结
systemReady函数完成了系统就绪的必要工作,然后它将启动Home Activity。至此,Android系统就全部启动了。