android 在开机启动后的代码里 ,并不会直接启动Launcher页面,而是会判断经过开机引导和FallbackHome
简单理解 开机引导>FallbackHome>Launcher
//services/core/java/com/android/server/wm/RootWindowContainer.java
startHomeOnTaskDisplayArea() {
//省略。。。
Intent homeIntent = null;
ActivityInfo aInfo = null;
if (taskDisplayArea == getDefaultTaskDisplayArea()) {
homeIntent = mService.getHomeIntent();
aInfo = resolveHomeActivity(userId, homeIntent);
} else if (shouldPlaceSecondaryHomeOnDisplayArea(taskDisplayArea)) {
Pair<ActivityInfo, Intent> info = resolveSecondaryHomeActivity(userId, taskDisplayArea);
aInfo = info.first;
homeIntent = info.second;
}
homeIntent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
homeIntent.setFlags(homeIntent.getFlags() | FLAG_ACTIVITY_NEW_TASK);
//省略..
mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason,
taskDisplayArea);
}
开机向导
在android 12 下 是 在 packages/apps/Provision 下,新买手机后 一步步设置的界面。
public class DefaultActivity extends Activity {
private void finishSetup() {
setProvisioningState();//设置引导完成标志
disableSelfAndFinish();//关闭自己
}
private void disableSelfAndFinish() {
PackageManager pm = getPackageManager();
ComponentName name = new ComponentName(this, DefaultActivity.class);
pm.setComponentEnabledSetting(name, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
finish();
}
}
<application>
<activity android:name="DefaultActivity"
android:excludeFromRecents="true"
android:exported="true">
<intent-filter android:priority="1">
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.HOME"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.SETUP_WIZARD"/>
</intent-filter>
</activity>
FallbackHome
Android N 以后 增加的一个页面,在当设备已开机但用户尚未解锁设备时,就会显示FallbackHome。
public class FallbackHome extends Activity {
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mReceiver);
if (!mFinished) {
finishFallbackHome();
}
}
//创建的时候做了监听 监听解锁
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED));
}
//接收消息发送,再次递归调用maybeFinish
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
maybeFinish();
}
};
private void maybeFinish() {
//检查是否已经解锁
if (getSystemService(UserManager.class).isUserUnlocked()) {
//判断是否能够响应lanucher
final Intent homeIntent = new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_HOME);
final ResolveInfo homeInfo = getPackageManager().resolveActivity(homeIntent, 0);
if (Objects.equals(getPackageName(), homeInfo.activityInfo.packageName)) {
//如果是当前包名也就是 FallbackHome 那么就延迟500ms 看看lauchner起来了么
mHandler.sendEmptyMessageDelayed(0, 500);
} else {
getSystemService(PowerManager.class).userActivity(
SystemClock.uptimeMillis(), false);
finish();
}
}
}
//关闭自己 并从堆栈移除
private void finishFallbackHome() {
getSystemService(PowerManager.class).userActivity(SystemClock.uptimeMillis(), false);
finishAndRemoveTask();
mFinished = true;
}
}
<activity android:name=".FallbackHome"
android:excludeFromRecents="true"
android:label=""
android:screenOrientation="nosensor"
android:taskAffinity="com.android.settings.FallbackHome"
android:exported="true"
android:theme="@style/FallbackHome">
<intent-filter android:priority="-1000">
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
Launcher
<activity
android:name="com.android.launcher3.Launcher"
android:launchMode="singleTask"
android:clearTaskOnLaunch="true"
android:stateNotNeeded="true"
android:windowSoftInputMode="adjustPan"
android:screenOrientation="unspecified"
android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize|density"
android:resizeableActivity="true"
android:resumeWhilePausing="true"
android:taskAffinity=""
android:exported="true"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.MONKEY"/>
<category android:name="android.intent.category.LAUNCHER_APP" />
</intent-filter>
<meta-data
android:name="com.android.launcher3.grid.control"
android:value="${packageName}.grid_control" />
</activity>
下面是我个人的理解,三者都做了符合android.intent.action.MAIN 和android.intent.category.HOME匹配规则,而Provision的priority为1 ,FallbackHome为-900.Launcher 未设置。正常情况下是 Provision -> Launcher->FallbackHome。但是启动的顺序和这个关系不大。但是也确保了万一基于广播的启动顺序。
但是 在FallbackHome和Provision的xml里 设置了 android:excludeFromRecents="true"
该属性可以让页面在直启模式下运行。在解锁之前就可以启动了 FallbackHome但是在启动后,优先级就会远远低于Launcher。
Provision在完成后会设置 调用 finishSetup() ,完成设置向导,避免再次启动,调用disableSelfAndFinish() 在PackageManager 中移除自己,并关闭。
FallbackHome 构建后,监听解锁,触发解锁后,会进入maybeFinish(),进行判断Laucher3是否已经启动,符合条件后 调用关闭自己,如果不符合条件 则继续等待500ms后再次查询是否符合条件。
简单的理解,Provision负责处理设备的初始配置和系统初始化,这些操作对于设备的安全性和功能性至关重要,需要在用户界面呈现之前完成。一旦 Provision 的任务完成,系统才会继续启动流程,包括 FallbackHome 和其他用户可见的应用和服务。
FallbackHome可以在直启动模式下 启动,在该模式下匹配到的就是自己,是一个简单的展示页面,主要用来过度 启动和Launcher的过程和失败页面。FallbackHome 在 ATMS 的systemReady()里面会调用startHomeActivityLocked()。这里回去匹配符合getHomeIntent()标准的页面。在最初能匹配到的是FallbackHome,在FallbackHome不断轮训监听的过程中,查看是否已经解锁,在发现已经解锁后,关闭自己,这会才真正的拉起Launcher。
FallbackHome请求finish()自己,当然会请求执行onPasue()方法: ActivityManagerService.activityPaused() ,
-->ActivityStack.activityPausedLocked(),
-->ActivityStack.completePauseLocked(),
—-> ActivityStack.finishCurrentActivityLocked(),
-->ActivityStackSupervisor.resumeFocusedStackTopActivityLocked(),
最后调用到了ActivityManagerService.startHomeActivityLocked()。
再次查询就启动了Launcher。