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系统就全部启动了。