Android系统启动之BOOT_COMPLETED广播

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());
synchronized (this) {
updateEventDispatchingLocked();
}
浴室电视机}
⽐较简单,进⼀步调⽤了ableScreenAfterBoot()。
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 = Service("SurfaceFlinger");
if (surfaceFlinger != null) {
//Slog.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
Parcel data = Parcel.obtain();
data.writeInterfaceToken("android.ui.ISurfaceComposer");
data, null, 0);
}免清洗焊锡丝
环境风洞} catch (RemoteException ex) {
Slog.e(TAG, "Boot completed: SurfaceFlinger is dead!");
}
mBootAnimationStopped = true;
}育苗杯
包层模if (!mForceDisplayEnabled && !checkBootAnimationCompleteLocked()) {
...
return;
}
...
try {
mActivityManager.bootAnimationComplete();
} catch (RemoteException e) {
}
// Make sure the last requested orientation has been applied.
updateRotationUnchecked(false, false);
}
可见,通过binder调⽤了SurfaceFlinger的bootFinished(),该函数会设置属性值“it”为1。同
时,bootanimation播放开机动画时候,会循环检查该属性值是否为1,如果为1且动画播放完成,则会退出bootanimation。
之后,该函数⼜调⽤了checkBootAnimationCompleteLocked:
private boolean checkBootAnimationCompleteLocked() {
if (SystemService.isRunning(BOOT_ANIMATION_SERVICE)) {
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优先级低,接收到该⼴播的时间会晚⼀些。

本文发布于:2024-09-22 17:18:55,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/2/328702.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:退出   函数   系统   启动   发送   进程   消息   动画
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议