Android系统启动之BOOT_COMPLETED广播
Posted 迷途小书童Eric
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android系统启动之BOOT_COMPLETED广播相关的知识,希望对你有一定的参考价值。
对于android系统启动的流程,大家应该很熟悉了。但系统启动是一个很复杂的过程,中间夹杂着很多细节。比如,开机动画什么退出?BOOT_COMPLETED广播什么时候发送?该广播有什么特点?等等。这篇文章就详细说一下。
大家知道,在开机启动流程最后,AMS会调用startHomeActivityLocked(),用来启动Launcher,Launcher启动后,会回调AMS的activityIdle,代码如下:
final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean
fromTimeout, Configuration config)
...
ActivityRecord r = ActivityRecord.forToken(token);
if (r != null)
...
if (isFrontStack(r.task.stack) || fromTimeout)
booting = checkFinishBootingLocked();
...
因为系统刚启动,Launcher肯定是FrontStack,所以会调用checkFinishBootingLocked(),该函数代码如下:
private boolean checkFinishBootingLocked()
final boolean booting = mService.mBooting;
boolean enableScreen = false;
mService.mBooting = false;
if (!mService.mBooted)
mService.mBooted = true;
enableScreen = true;
if (booting || enableScreen)
mService.postFinishBooting(booting, enableScreen);
return booting;
这里有两个关键变量,mService.mBooting和mService.mBooted。
mService.mBooting是AMS在AMS.systemRead()中,调用startHomeActivityLocked()之前设置为ture的。因此这里肯定=true。
mService.mBooted设置的地方比较多,这里不一一列举了,但这时候因为没有系统还未启动完毕,因此该值为false。
所以,booting=true;enableScreen=true。
进一步调用mService.postFinishBooting(true, true)。该函数代码如下:
void postFinishBooting(boolean finishBooting, boolean enableScreen)
mHandler.sendMessage(mHandler.obtainMessage(FINISH_BOOTING_MSG,
finishBooting? 1 : 0, enableScreen ? 1 : 0));
可见,是想AMS的MainHandler发送FINISH_BOOTING_MSG消息,并且该消息的两个参数arg1=1,arg2=1。
final class MainHandler extends Handler
public void handleMessage(Message msg)
...
case FINISH_BOOTING_MSG:
if (msg.arg1 != 0)
finishBooting();
if (msg.arg2 != 0)
enableScreenAfterBoot();
break;
...
FINISH_BOOTING_MSG的消息处理为:先调用finishBooting(),后调用enableScreenAfterBoot()。
下面一个一个分析,先分析finishBooting():
finishBooting()
final void finishBooting()
synchronized (this)
if (!mBootAnimationComplete)
mCallFinishBooting = true;
return;
mCallFinishBooting = false;
刚进入该函数,就会判断mBootAnimationComplete。如果该值为false,将变量mCallFinishBooting设置为true,不做处理,直接返回。看来,如果要发送BOOT_COMPLETED广播,该变量必须等于true。
变量mBootAnimationComplete在初始化时,设置为false。那么,在哪里把修改为true呢?答案是在bootAnimationComplete()中。
public void bootAnimationComplete()
final boolean callFinishBooting;
synchronized (this)
callFinishBooting = mCallFinishBooting;
mBootAnimationComplete = true;
if (callFinishBooting)
finishBooting();
结合finishBooting()的源码,可以得到以下逻辑:
- 如果AMS在调用finishBooting()时候,mBootAnimationComplete还没有被设置为true时,则不做处理,直接返回。
- 当其他地方调用bootAnimationComplete()时,发现callFinishBooting=true,会再一次调用finishBooting(),这时候该函数不会直接返回,而是继续往下执行(主要工作就是发送BOOT_COMPLETED广播)。
为什么这么做呢?看来是有件事很重要,必须处理完后,系统才能发送BOOT_COMPLETED广播。那么谁会调用bootAnimationComplete()呢?带着以上疑问,我们看一下FINISH_BOOTING_MSG消息处理的另外一个操作:enableScreenAfterBoot()。
enableScreenAfterBoot()
根据之前的描述,调用完finishBooting(),会调用enableScreenAfterBoot()。下面看一下该函数的代码:
void enableScreenAfterBoot()
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN,
SystemClock.uptimeMillis());
mWindowManager.enableScreenAfterBoot();
synchronized (this)
updateEventDispatchingLocked();
比较简单,进一步调用了WMS.enableScreenAfterBoot()。
public void enableScreenAfterBoot()
synchronized(mWindowMap)
...
if (mSystemBooted) //保证该函数只调用一次
return;
mSystemBooted = true;
...
// If the screen still doesn't come up after 30 seconds, give
// up and turn it on.
mH.sendEmptyMessageDelayed(H.BOOT_TIMEOUT, 30*1000);
...
performEnableScreen();
该函数会延时30s后发送BOOT_TIMEOUT消息,这里先不说,后面会介绍该消息的作用。进一步看一下performEnableScreen():
public void performEnableScreen()
synchronized(mWindowMap)
...
if (!mBootAnimationStopped) //确保该部分代码只执行一次
// Do this one time.
try
IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
if (surfaceFlinger != null)
//Slog.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
Parcel data = Parcel.obtain();
data.writeInterfaceToken("android.ui.ISurfaceComposer");
surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
data, null, 0);
data.recycle();
catch (RemoteException ex)
Slog.e(TAG, "Boot completed: SurfaceFlinger is dead!");
mBootAnimationStopped = true;
if (!mForceDisplayEnabled && !checkBootAnimationCompleteLocked())
...
return;
...
try
mActivityManager.bootAnimationComplete();
catch (RemoteException e)
mPolicy.enableScreenAfterBoot();
// Make sure the last requested orientation has been applied.
updateRotationUnchecked(false, false);
可见,通过binder调用了SurfaceFlinger的bootFinished(),该函数会设置属性值“service.bootanim.exit”为1。同时,bootanimation播放开机动画时候,会循环检查该属性值是否为1,如果为1且动画播放完成,则会退出bootanimation。
之后,该函数又调用了checkBootAnimationCompleteLocked:
private boolean checkBootAnimationCompleteLocked()
if (SystemService.isRunning(BOOT_ANIMATION_SERVICE))
mH.removeMessages(H.CHECK_IF_BOOT_ANIMATION_FINISHED);
mH.sendEmptyMessageDelayed(H.CHECK_IF_BOOT_ANIMATION_FINISHED,
BOOT_ANIMATION_POLL_INTERVAL);
...
return false;
...
return true;
这里的BOOT_ANIMATION_SERVICE即bootanim,也就是bootanimation开机动画进程。如果bootanimation进程退出了,则返回true,performEnableScreen()会接着往下进行;如果bootanimation进程没有退出,则会每隔0.2s检查bootanimation是否退出,直到该进程退出,然后再次调用performEnableScreen()。
接着看performEnableScreen()。经过上面的逻辑,如果bootanimation进程退出了,performEnableScreen()会继续往下执行,就会调用mActivityManager.bootAnimationComplete()。
到这里,就清楚了,在发送BOOT_COMPLETED之前,需要完成的工作就是通知bootanimation停止播放动画,且等待bootanim进程退出。
前面介绍enableScreenAfterBoot()时候,说过该函数会延时30s后发送BOOT_TIMEOUT消息。该消息的作用就是万一过了30s之后,bootanimaiton还没有退出,系统也会强制发送BOOT_COMPLETED广播,并进入桌面。
BOOT_COMPLETED广播
发送BOOT_COMPLETED广播的代码如下:
final void finishBooting()
...
Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
broadcastIntentLocked(null, null, intent, null,
new IIntentReceiver.Stub()
@Override
public void performReceive(Intent intent, int resultCode,
String data, Bundle extras, boolean ordered,
boolean sticky, int sendingUser)
synchronized (ActivityManagerService.this)
requestPssAllProcsLocked(SystemClock.uptimeMillis(),
true, false);
,
0, null, null,
android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
AppOpsManager.OP_NONE, true, false, MY_PID, Process.SYSTEM_UID, userId);
...
注意broadcastIntentLocked()中倒数第四和第五个参数。其中倒数第四个参数为false,代表该广播不是sticky广播,倒数第五个为true,表示该广播是串行广播。
串行广播意味着,BOOT_COMPLETED广播会根据优先级依次发送给接收者。当然,系统级服务或应用优先级高,会先收到并处理该广播。第三方App优先级低,接收到该广播的时间会晚一些。
以上是关于Android系统启动之BOOT_COMPLETED广播的主要内容,如果未能解决你的问题,请参考以下文章
Android 进阶——系统启动之SystemServer创建并启动Installer服务
Android 进阶——系统启动之SystemServer创建并启动Installer服务
Android 进阶——系统启动之SystemServer创建并启动Installer服务
Android 进阶——系统启动之SystemServer创建并启动Installer服务