Bootloader 系统引导android
启动 Linux 内核app
启动 init 进程ide
启动 Zygote 进程ui
启动 SystemServer 进程this
SystemServer 会在 startBootstrapServices() 方法中会启动 ActivityManagerService 。spa
private void startBootstrapServices() {
...
// Activity manager runs the show.
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
...
}
复制代码
在 startOtherServices() 方法中会调用 ActivityManagerService 的 systemReday() 方法。线程
private void startOtherServices() {
...
mActivityManagerService.systemReady(new Runnable() {
@Override
public void run() {
Slog.i(TAG, "Making services ready");
mSystemServiceManager.startBootPhase(
SystemService.PHASE_ACTIVITY_MANAGER_READY);
...
}
...
}
复制代码
ActivityManagerService 的 systemReday() 方法中会调用 startHomeActivityLocked() 方法。rest
public void systemReady(final Runnable goingCallback) {
...
synchronized (this) {
...
startHomeActivityLocked(currentUserId, "systemReady");
...
}
...
}
复制代码
startHomeActivityLocked() 方法中会获取到 Action 为 Intent.ACTION_MAIN,Category 为 Intent.CATEGORY_HOME 的 Intent,根据该 Intent 获取到符合条件的应用,并判断该应用是否已经启动,没有启动则启动该应用。code
...
String mTopAction = Intent.ACTION_MAIN;
...
// 获取 Action 为 Intent.ACTION_MAIN,Category 为 Intent.CATEGORY_HOME 的 Intent
Intent getHomeIntent() {
Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
intent.setComponent(mTopComponent);
intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
intent.addCategory(Intent.CATEGORY_HOME);
}
return intent;
}
boolean startHomeActivityLocked(int userId, String reason) {
if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
&& mTopAction == null) {
// We are running in factory test mode, but unable to find
// the factory test app, so just sit around displaying the
// error message and don't try to start anything.
return false;
}
Intent intent = getHomeIntent();
// 获取符合条件的应用
ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
if (aInfo != null) {
intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
// Don't do this if the home app is currently being
// instrumented.
aInfo = new ActivityInfo(aInfo);
aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
ProcessRecord app = getProcessRecordLocked(aInfo.processName,
aInfo.applicationInfo.uid, true);
// 判断应用是否启动,未启动则启动该应用程序
if (app == null || app.instrumentationClass == null) {
intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
// 启动应用程序
mActivityStarter.startHomeActivityLocked(intent, aInfo, reason);
}
} else {
Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
}
return true;
}
复制代码
通常状况下,被启动的应用就是 Launcher,由于 Launcher 的 Manifest 文件中有匹配了 Action 为 Intent.ACTION_MAIN,Category 为 Intent.CATEGORY_HOME 的 Activity。component
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.launcher3">
<uses-sdk android:targetSdkVersion="23" android:minSdkVersion="21"/>
...
<application android:backupAgent="com.android.launcher3.LauncherBackupAgent" android:fullBackupOnly="true" android:fullBackupContent="@xml/backupscheme" android:hardwareAccelerated="true" android:icon="@mipmap/ic_launcher_home" android:label="@string/derived_app_name" android:largeHeap="@bool/config_largeHeap" android:restoreAnyVersion="true" android:supportsRtl="true" >
<activity android:name="com.android.launcher3.Launcher" android:launchMode="singleTask" android:clearTaskOnLaunch="true" android:stateNotNeeded="true" android:theme="@style/LauncherTheme" android:windowSoftInputMode="adjustPan" android:screenOrientation="nosensor" android:configChanges="keyboard|keyboardHidden|navigation" android:resumeWhilePausing="true" android:taskAffinity="" 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"/>
</intent-filter>
</activity>
...
</application>
</manifest>
复制代码
可是,当首次开机时,被启动的应用就是设置向导,由于设置向导的 Manifest 文件中也有匹配了 Action 为 Intent.ACTION_MAIN,Category 为 Intent.CATEGORY_HOME 的 Activity,而且优先级高于 Launcher。
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.provision">
...
<application>
<activity android:name="DefaultActivity" android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen" android:excludeFromRecents="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>
</application>
</manifest>
复制代码
Launcher 的 Manifest 中 intent-filter 没有设置优先级,默认为 0;设置向导的 Manifest 中 intent-filter 的优先级为 1;因此在 resolveActivityInfo() 方法获取符合的应用时会优先获取到设置向导。
private ActivityInfo resolveActivityInfo(Intent intent, int flags, int userId) {
ActivityInfo ai = null;
ComponentName comp = intent.getComponent();
try {
if (comp != null) {
// Factory test.
ai = AppGlobals.getPackageManager().getActivityInfo(comp, flags, userId);
} else {
ResolveInfo info = AppGlobals.getPackageManager().resolveIntent(
intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
flags, userId);
if (info != null) {
ai = info.activityInfo;
}
}
} catch (RemoteException e) {
// ignore
}
return ai;
}
复制代码
获取最优 Activity 的具体实如今 PackageManagerService 的 chooseBestActivity() 方法中。
Manifest 中 Activity 的 intent-filter 的优先级设置只有系统应用才会生效,非系统应用会被 PackageManagerService 调整为 0。
/** * Adjusts the priority of the given intent filter according to policy. * <p> * <ul> * <li>The priority for non privileged applications is capped to '0'</li> * <li>The priority for protected actions on privileged applications is capped to '0'</li> * <li>The priority for unbundled updates to privileged applications is capped to the * priority defined on the system partition</li> * </ul> * <p> * <em>NOTE:</em> There is one exception. For security reasons, the setup wizard is * allowed to obtain any priority on any action. */
private void adjustPriority( List<PackageParser.Activity> systemActivities, ActivityIntentInfo intent) {
...
final boolean privilegedApp =
((applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0);
if (!privilegedApp) {
// non-privileged applications can never define a priority >0
Slog.w(TAG, "Non-privileged app; cap priority to 0;"
+ " package: " + applicationInfo.packageName
+ " activity: " + intent.activity.className
+ " origPrio: " + intent.getPriority());
intent.setPriority(0);
return;
}
if (systemActivities == null) {
// the system package is not disabled; we're parsing the system partition
if (isProtectedAction(intent)) {
if (mDeferProtectedFilters) {
// We can't deal with these just yet. No component should ever obtain a
// >0 priority for a protected actions, with ONE exception -- the setup
// wizard. The setup wizard, however, cannot be known until we're able to
// query it for the category CATEGORY_SETUP_WIZARD. Which we can't do
// until all intent filters have been processed. Chicken, meet egg.
// Let the filter temporarily have a high priority and rectify the
// priorities after all system packages have been scanned.
mProtectedFilters.add(intent);
if (DEBUG_FILTERS) {
Slog.i(TAG, "Protected action; save for later;"
+ " package: " + applicationInfo.packageName
+ " activity: " + intent.activity.className
+ " origPrio: " + intent.getPriority());
}
return;
} else {
if (DEBUG_FILTERS && mSetupWizardPackage == null) {
Slog.i(TAG, "No setup wizard;"
+ " All protected intents capped to priority 0");
}
if (intent.activity.info.packageName.equals(mSetupWizardPackage)) {
if (DEBUG_FILTERS) {
Slog.i(TAG, "Found setup wizard;"
+ " allow priority " + intent.getPriority() + ";"
+ " package: " + intent.activity.info.packageName
+ " activity: " + intent.activity.className
+ " priority: " + intent.getPriority());
}
// setup wizard gets whatever it wants
return;
}
Slog.w(TAG, "Protected action; cap priority to 0;"
+ " package: " + intent.activity.info.packageName
+ " activity: " + intent.activity.className
+ " origPrio: " + intent.getPriority());
intent.setPriority(0);
return;
}
}
// privileged apps on the system image get whatever priority they request
return;
}
...
}
复制代码
在 adjustPriority 方法中,若是 packageName 为 mSetupWizardPackage 就不会调整其优先级,保持其 Manifest 中设置的优先级。mSetupWizardPackage 的值从 getSetupWizardPackageName() 方法中获取。
final @Nullable String mSetupWizardPackage;
...
public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) {
...
mSetupWizardPackage = getSetupWizardPackageName();
...
}
private @Nullable String getSetupWizardPackageName() {
final Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_SETUP_WIZARD);
final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, null,
MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE
| MATCH_DISABLED_COMPONENTS,
UserHandle.myUserId());
if (matches.size() == 1) {
return matches.get(0).getComponentInfo().packageName;
} else {
Slog.e(TAG, "There should probably be exactly one setup wizard; found " + matches.size()
+ ": matches=" + matches);
return null;
}
}
复制代码
因此 mSetupWizardPackage 就是有添加了 Category 为 android.intent.category.SETUP_WIZARD 的 Activity 的应用。
既然设置向导的优先级高于 Launcher,那每次开机时不是都会先启动设置向导么,为何设置向导完成后再次开机直接进入了 Launcher?
由于设置向导在最后退出时会禁用掉添加了 Category 为 Intent.CATEGORY_HOME 的 Activity,因此 ActivityManagerService 在 resolveActivityInfo() 获取匹配的应用时就不会获取到设置向导,直接获取到了 Launcher。
// remove this activity from the package manager.
PackageManager pm = getPackageManager();
ComponentName name = new ComponentName(this, DefaultActivity.class);
pm.setComponentEnabledSetting(name, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
复制代码