将系统中已经安装了的应用程序显示出来的目的是为了让用户有一个统一的人口来启动它们,一个根AciLivity组件的启动过程就代表了一个应用程序的启动过程。 因此,应用程序Launcher在显示一个应用程序时,只需要获得它的根Activity组件信息即可
一个应用程序的根Activity组件的类型被定义为CATEGORY_LAUNCHER,同时它的Action名称被定义为ACTION_MAIN,这样应用程序Launcher就可以通过这两个条件来请求Package管理服务PackageManagerService返回系统中所有已经安装了的应用程序的根Activity即组件信息。获得了系统中已经安装了的应用程序的根Activity组件信息之后,应用程序Launcher就会分别将它们封装成一个快捷图标,并且显示在系统的屏幕中,这样用户就可以通过点击这些快捷图标来启动相应的应用程序了。接下来,我们就通过分析应用程序Launcher的启动过程来说明系统中已经安装了的应用程序的显 示过程。 System进程是由 Zygote进程负责启动的, 而System进程在启动过程中, 又会创建一个ServerThread线程来启动系统中的关键服务。 当系统中的关键服务都启动起来之 后, 这个ServerThread线程就会通知Activity管理服务ActivityManagerService将应用程序Launcher启动起来。
1.在SystemServer中启动AMS服务
代码路径:/frameworks/base/services/java/com/android/server/SystemServer.java
(http://androidxref.com/8.0.0_r4/xref/frameworks/base/services/java/com/android/server/SystemServer.java)
259 public static void main(String[] args) { 260 new SystemServer().run(); 261 }
在main中创建一个SystemServer的匿名对象并调用它的run函数
263 public SystemServer() { 264 // Check for factory test mode. 265 mFactoryTestMode = FactoryTest.getMode(); 266 // Remember if it's runtime restart(when sys.boot_completed is already set) or reboot 267 mRuntimeRestart = "1".equals(SystemProperties.get("sys.boot_completed")); 268 }
创建匿名对象,在构造函数中得到启动模式和sys.boot_completed的属性。用来判断是否为正常模式启动和boot启动是否完成。
在run函数中会对系统属性进行初始化设置,并启动一些关键的服务:
391 // Start services. 392 try { 393 traceBeginAndSlog("StartServices"); 394 startBootstrapServices(); 395 startCoreServices(); 396 startOtherServices(); 397 SystemServerInitThreadPool.shutdown();
例如此次要说明的AMS服务就在startBootstrapServices()函数中启动
511 // Activity manager runs the show. 512 traceBeginAndSlog("StartActivityManager"); 513 mActivityManagerService = mSystemServiceManager.startService( 514 ActivityManagerService.Lifecycle.class).getService(); 515 mActivityManagerService.setSystemServiceManager(mSystemServiceManager); 516 mActivityManagerService.setInstaller(installer); 517 traceEnd();
在startOtherServices()中调用AcitivtyManagerService的成员函数 systemReady()将应用程序Launcher启动起来。
1641 // We now tell the activity manager it is okay to run third party 1642 // code. It will call back into us once it has gotten to the state 1643 // where third party code can really run (but before it has actually 1644 // started launching the initial applications), for us to complete our 1645 // initialization. 1646 mActivityManagerService.systemReady(() -> { 1647 Slog.i(TAG, "Making services ready"); 1648 traceBeginAndSlog("StartActivityManagerReadyPhase"); 1649 mSystemServiceManager.startBootPhase( 1650 SystemService.PHASE_ACTIVITY_MANAGER_READY); 1651 traceEnd(); 1652 traceBeginAndSlog("StartObservingNativeCrashes"); 1653 try { 1654 mActivityManagerService.startObservingNativeCrashes(); 1655 } catch (Throwable e) { 1656 reportWtf("observing native crashes", e); 1657 } 1658 traceEnd();............................................
2.ActivityManagerService.systemReady
代码路径:/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java (http://androidxref.com/8.0.0_r4/xref//frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java)在校验系统底层启动完成后,通过AMS类的成员函数startHomeActivityLocked来执行启动应用程序Launcher的操作。
14031 14032 public void systemReady(final Runnable goingCallback, BootTimingsTraceLog traceLog) { 14033 traceLog.traceBegin("PhaseActivityManagerReady"); 14034 synchronized(this) { 14035 if (mSystemReady) {.....................................
14144 mBooting = true; 14145 // Enable home activity for system user, so that the system can always boot. We don't 14146 // do this when the system user is not setup since the setup wizard should be the one 14147 // to handle home activity in this case. 14148 if (UserManager.isSplitSystemUser() && 14149 Settings.Secure.getInt(mContext.getContentResolver(), 14150 Settings.Secure.USER_SETUP_COMPLETE, 0) != 0) { 14151 ComponentName cName = new ComponentName(mContext, SystemUserHomeActivity.class); 14152 try { 14153 AppGlobals.getPackageManager().setComponentEnabledSetting(cName, 14154 PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0, 14155 UserHandle.USER_SYSTEM); 14156 } catch (RemoteException e) { 14157 throw e.rethrowAsRuntimeException(); 14158 } 14159 } 14160 startHomeActivityLocked(currentUserId, "systemReady"); 14161 14162 try { 14163 if (AppGlobals.getPackageManager().hasSystemUidErrors()) { 14164 Slog.e(TAG, "UIDs on the system are inconsistent, you need to wipe your" 14165 + " data partition or your device will be unstable."); 14166 mUiHandler.obtainMessage(SHOW_UID_ERROR_UI_MSG).sendToTarget(); 14167 } 14168 } catch (RemoteException e) { 14169 }
14199 } catch (Throwable t) { 14200 Slog.wtf(TAG, "Failed sending first user broadcasts", t); 14201 } finally { 14202 Binder.restoreCallingIdentity(ident); 14203 } 14204 mStackSupervisor.resumeFocusedStackTopActivityLocked(); 14205 mUserController.sendUserSwitchBroadcastsLocked(-1, currentUserId); 14206 traceLog.traceEnd(); // ActivityManagerStartApps 14207 traceLog.traceEnd(); // PhaseActivityManagerReady 14208 } 14209 }
3.ActivityManagerService.startHomeActivityLocked
代码路径:/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java (http://androidxref.com/8.0.0_r4/xref//frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java)
在AMS的成员函数startHomeActivityLocked中,通过getHomeIntent()来获取启动Launcher的Intent,通过resolveActivityInfo(intent, STOCK_PM_FLAGS, userId)获取要启动的Launcher的主Activity的信息,最后通过调用ActivityStarter.startHomeActivityLocked(intent, aInfo, myReason)来真正启动Launcher。
4048 boolean startHomeActivityLocked(int userId, String reason) { 4049 if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL 4050 && mTopAction == null) { 4051 // We are running in factory test mode, but unable to find 4052 // the factory test app, so just sit around displaying the 4053 // error message and don't try to start anything. 4054 return false; 4055 } 4056 Intent intent = getHomeIntent();//获取启动Launcher的Intent 4057 ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);//获取要启动的Launcher的主Activity的信息 4058 if (aInfo != null) { 4059 intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name)); 4060 // Don't do this if the home app is currently being 4061 // instrumented. 4062 aInfo = new ActivityInfo(aInfo); 4063 aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId); 4064 ProcessRecord app = getProcessRecordLocked(aInfo.processName, 4065 aInfo.applicationInfo.uid, true); 4066 if (app == null || app.instr == null) { 4067 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK); 4068 final int resolvedUserId = UserHandle.getUserId(aInfo.applicationInfo.uid); 4069 // For ANR debugging to verify if the user activity is the one that actually 4070 // launched. 4071 final String myReason = reason + ":" + userId + ":" + resolvedUserId; 4072 mActivityStarter.startHomeActivityLocked(intent, aInfo, myReason); 4073 } 4074 } else { 4075 Slog.wtf(TAG, "No home screen found for " + intent, new Throwable()); 4076 } 4077 4078 return true; 4079 }
4.ActivityStarter.startHomeActivityLocked
代码路径:/frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java (http://androidxref.com/8.0.0_r4/xref//frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java)
最后通过调用来启动Launcher的主Activity,通过Launcher来将应用图标显示在桌面上
640 void startHomeActivityLocked(Intent intent, ActivityInfo aInfo, String reason) { 641 mSupervisor.moveHomeStackTaskToTop(reason); 642 mLastHomeActivityStartResult = startActivityLocked(null /*caller*/, intent, 643 null /*ephemeralIntent*/, null /*resolvedType*/, aInfo, null /*rInfo*/, 644 null /*voiceSession*/, null /*voiceInteractor*/, null /*resultTo*/, 645 null /*resultWho*/, 0 /*requestCode*/, 0 /*callingPid*/, 0 /*callingUid*/, 646 null /*callingPackage*/, 0 /*realCallingPid*/, 0 /*realCallingUid*/, 647 0 /*startFlags*/, null /*options*/, false /*ignoreTargetSecurity*/, 648 false /*componentSpecified*/, mLastHomeActivityStartRecord /*outActivity*/, 649 null /*container*/, null /*inTask*/, "startHomeActivity: " + reason); 650 if (mSupervisor.inResumeTopActivity) { 651 // If we are in resume section already, home activity will be initialized, but not 652 // resumed (to avoid recursive resume) and will stay that way until something pokes it 653 // again. We need to schedule another resume. 654 mSupervisor.scheduleResumeTopActivities(); 655 } 656 }