Links to related articles:
1. Android Framework – Learning Launcher
2. Startup process of Android system service-AMS
3. Startup process of Android system services-PMS
4. Android Framework – Start the Init process after startup
Related source files:
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
/apps/Launcher3/src/com/android/launcher3/launcher3.java
/apps/Launcher3/src/com/android/launcher3/LauncherModel.java
/apps/Launcher3/src/com/android/launcher3/LauncherAppsCompatV16.java
/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
/frameworks/base/cmds/bootanimation/bootanimation_main.cpp
Copy the code
1. Start entrance analysis
Public void systemReady(final Runnable goingCallback) {synchronized (this) {// Start Launcher startHomeActivityLocked(mCurrentUserId, "systemReady"); }} Boolean startHomeActivityLocked(int userId, String reason) {intIntent = getHomeIntent(); ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId); if (aInfo ! = null) { intent.setComponent(new ComponentName( aInfo.applicationInfo.packageName, aInfo.name)); aInfo = new ActivityInfo(aInfo); aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId); / / by process name and uid query process information ProcessRecord app = getProcessRecordLocked (aInfo. ProcessName, aInfo. ApplicationInfo. Uid, true); / / process here haven't start the app to null if (app = = null | | app. InstrumentationClass = = null) {intent. SetFlags (intent. GetFlags () | Intent.FLAG_ACTIVITY_NEW_TASK); mStackSupervisor.startHomeActivity(intent, aInfo, reason); } } return true; } Intent getHomeIntent() { Intent intent = new Intent(mTopAction, mTopData ! = null ? Uri.parse(mTopData) : null); intent.setComponent(mTopComponent); if (mFactoryTest ! FactoryTest.FACTORY_TEST_LOW_LEVEL) {// Category.addcategory (intent.category_HOME); } return intent; }Copy the code
In AMS’s systemReady method, the first parsing request is made to the PMS by intent. The PMS query returns an ActivityInfo object. Note that CATEGORY_HOME; Then use the process name and UID to check whether the process is started. The ProcessRecord of the process Launcher must be empty. Finally, call the startHomeActivity method to start and create the Launcher. The creation of the Launcher process and the startup process of the Launcher Activity will not be discussed here, but will be discussed in detail when the startup process of the four components is analyzed later.
###2. Query, parse and fill all App information
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); / / initialization Model LauncherAppState app. = LauncherAppState getInstance (); mModel = app.setLauncher(this); setContentView(R.layout.launcher); if (! mRestoring) { if (DISABLE_SYNCHRONOUS_BINDING_CURRENT_PAGE) { // If the user leaves launcher, then we should just load items asynchronously when // they return. mModel.startLoader(PagedView.INVALID_RESTORE_PAGE); } else { // We only load the page synchronously if the user rotates (or triggers a // configuration change) while launcher is in the foreground mModel.startLoader(mWorkspace.getRestorePage()); } } } public void startLoader(int synchronousBindPage, int loadFlags) { synchronized (mLock) { if (mCallbacks ! = null && mCallbacks.get() ! = null) { mLoaderTask = new LoaderTask(mApp.getContext(), loadFlags); if (synchronousBindPage ! = PagedView.INVALID_RESTORE_PAGE && mAllAppsLoaded && mWorkspaceLoaded && ! mIsLoaderTaskRunning) { mLoaderTask.runBindSynchronousPage(synchronousBindPage); } else { sWorkerThread.setPriority(Thread.NORM_PRIORITY); sWorker.post(mLoaderTask); } } } } public void run() { loadAndBindAllApps(); } private void loadAllApps() { final List<LauncherActivityInfoCompat> apps = mLauncherApps.getActivityList(null, user); for (int i = 0; i < apps.size(); i++) { LauncherActivityInfoCompat app = apps.get(i); mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache)); } mHandler.post(new Runnable() { public void run() { final Callbacks callbacks = tryGetCallbacks(oldCallbacks); if (callbacks ! = null) { callbacks.bindAllApplications(added); } else { ... }}}); } public List<LauncherActivityInfoCompat> getActivityList(String packageName, UserHandleCompat user) { final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); mainIntent.setPackage(packageName); / / like the PMS launched all ResolveInfo information query a List < ResolveInfo > infos. = mPm queryIntentActivities (mainIntent, 0); List<LauncherActivityInfoCompat> list = new ArrayList<LauncherActivityInfoCompat>(infos.size()); for (ResolveInfo info : infos) { list.add(new LauncherActivityInfoCompatV16(mContext, info)); } return list; }Copy the code
The onCreate method of the Launcher application will call the startLoader method of mModel to query all App application information. The queryIntentActivities method of PKMS is actually called inside this method. And all the Apk information will be queried, through the way of callback notification Launcher to fill our desktop RecyclerView interface. Note that the Action and Category queries are ACTION_MAIN and CATEGORY_LAUNCHER, respectively, because we typically have the following configuration in AndroidMnifest. XML.
<activity android:name=".MainActivity" android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Copy the code
###3. Start and close the boot screen
After starting the Launcher, the system will help us close the startup screen, so here we incidentally talk about the startup and shutdown of the startup screen. Let’s first examine the startup of the startup animation, which is actually a service parsed in the init process, except that the init.rc script is configured as Disable. This means that the init process will only parse when it starts, but will not start the boot animation process, because the boot animation process needs to handle rendering, so it must rely on the SurfaceFlinger process to initialize.
service bootanim /system/bin/bootanimation
class core
user graphics
group graphics audio
disabled
oneshot
void SurfaceFlinger::init() {
// start boot animation
startBootAnim();
}
void SurfaceFlinger::startBootAnim() {
// start boot animation
property_set("service.bootanim.exit", "0");
property_set("ctl.start", "bootanim");
}
Copy the code
After SurfaceFlinger is initialized, property_set is used to notify init process to start bootanim process. Therefore, we only need to find the bootanim process source code.
int main() { setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY); char value[PROPERTY_VALUE_MAX]; property_get("debug.sf.nobootanimation", value, "0"); int noBootAnimation = atoi(value); ALOGI_IF(noBootAnimation, "boot animation disabled"); if (! NoBootAnimation) {// Open binder driver sp<ProcessState> proc(ProcessState::self()); ProcessState::self()->startThreadPool(); // create the boot animation object sp<BootAnimation> boot = new BootAnimation(); IPCThreadState::self()->joinThreadPool(); } return 0; } void BootAnimation::onFirstRef() { status_t err = mSession->linkToComposerDeath(this); ALOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err)); if (err == NO_ERROR) { run("BootAnimation", PRIORITY_DISPLAY); } } status_t BootAnimation::readyToRun() { mAssets.addDefaultAssets(); // Get initialization layer... // initialize opengl and egl... // Initialize open boot zip package... return NO_ERROR; } bool BootAnimation::threadLoop() { bool r; // We have no bootanimation file, so we use the stock android logo // animation. if (mZip == NULL) { ... } else { r = movie(); } // Destroy opengl and egl eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroyContext(mDisplay, mContext); eglDestroySurface(mDisplay, mSurface); mFlingerSurface.clear(); mFlingerSurfaceControl.clear(); eglTerminate(mDisplay); IPCThreadState::self()->stopProcess(); return r; } bool BootAnimation::movie() { String8 desString; // read desc.txt configuration file if (! readFile("desc.txt", desString)) { return false; } char const* s = desString.string(); // Parse description file for (;;) {... } for (size_t i=0 ; i<pcount ; i++) { for (int r=0 ; ! part.count || r<part.count ; R++) {// opengl render operation glClearColor(part.backgroundcolor [0], part.backgroundcolor [1], part.backgroundcolor [2], 1.0f); for (size_t j=0 ; j<fcount && (! exitPending() || part.playUntilComplete) ; j++) { const Animation::Frame& frame(part.frames[j]); nsecs_t lastFrame = systemTime(); . if (r > 0) { glBindTexture(GL_TEXTURE_2D, frame.tid); } else { ... initTexture(frame); } // specify the y center as ceiling((mHeight - animation.height) / 2) // which is equivalent to mHeight - (yc + animation.height) glDrawTexiOES(xc, mHeight - (yc + animation.height), 0, animation.width, animation.height); eglSwapBuffers(mDisplay, mSurface); // Check to see if checkExit() is needed when constantly drawing; } // If exitPending() &&! part.count) break; } // free the textures for this part if (part.count ! = 1) { for (size_t j=0 ; j<fcount ; j++) { const Animation::Frame& frame(part.frames[j]); glDeleteTextures(1, &frame.tid); } } } return false; #define EXIT_PROP_NAME "service.bootanim.exit" void BootAnimation::checkExit() {// Allow surface flinger to gracefully request shutdown char value[PROPERTY_VALUE_MAX]; property_get(EXIT_PROP_NAME, value, "0"); int exitnow = atoi(value); if (exitnow) { requestExit(); if (mAudioPlayer ! = NULL) { mAudioPlayer->requestExit(); }}}Copy the code
The bottom layer of startup animation is rendered by Opengles. The content to be drawn is a local startup animation resource package. During the drawing process, it will constantly judge whether to exit. A value of 1 means that break is required to exit the loop drawing. So we just need to find where service.bootanim.exit is set to 1 to find the entry to exit the startup animation. Closing the entry to the animation is still done in SurfaceFlinger, but the call process is more complicated:
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume) { ActivityClientRecord r = performResumeActivity(token, clearHide); if (r ! = null) { if (! r.onlyLocalRequest) { r.nextIdle = mNewActivities; mNewActivities = r; // Add an IdleHandler message looper.myQueue ().addidleHandler (new Idler()); } } else { ... } } private class Idler implements MessageQueue.IdleHandler { @Override public final boolean queueIdle() { ActivityClientRecord a = mNewActivities; if (a ! = null) { mNewActivities = null; IActivityManager am = ActivityManagerNative.getDefault(); ActivityClientRecord prev; do { if (a.activity ! = null && ! A. activity. MFinished) {try {// Call AMS activityIdle am. ActivityIdle (A.token, A.createdConfig, stopProfiling); } catch (RemoteException ex) { // Ignore } } } while (a ! = null); } return false; } } @Override public final void activityIdle(IBinder token, Configuration config, boolean stopProfiling) { synchronized (this) { ActivityStack stack = ActivityRecord.getStackLocked(token); if (stack ! = null) { ActivityRecord r = mStackSupervisor.activityIdleInternalLocked(token, false, config); } } Binder.restoreCallingIdentity(origId); } // Checked. final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout, Configuration config) { ActivityRecord r = ActivityRecord.forTokenLocked(token); if (r ! = null) { ... if (isFrontStack(r.task.stack) || fromTimeout) { booting = checkFinishBootingLocked(); }}... return r; } 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; } void enableScreenAfterBoot() { mWindowManager.enableScreenAfterBoot(); synchronized (this) { updateEventDispatchingLocked(); } } public void performEnableScreen() { synchronized(mWindowMap) { if (! MBootAnimationStopped) {try {IBinder SurfaceFlinger = ServiceManager.getService("SurfaceFlinger"); if (surfaceFlinger ! = null) { 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) { ... } mBootAnimationStopped = true; }... } } } void SurfaceFlinger::bootFinished() { ... // Set the service.bootanim.exit property to 1, bootanim process will exit when it reads 1 and start animation property_set("service. }Copy the code
The process of closing the startup animation is complicated. Let’s start the whole logic. Our Launcher process starts our Launcher Activity interface, and the Activity life cycle calls are executed by ActivityThread. This executes to the handleResumeActivity method, which adds an IdleHandler message that calls AMS’s activityIdle method, AMS calls WMS’s enableScreenAfterBoot method, and WMS informs SurfaceFlinger across processes to turn off our boot animation.
Video address: pan.baidu.com/s/1LZ-kHXQy…
Video password: O71F