Android Framework学习(四)之Launcher启动流程解析

Android Framework学习(四)之Launcher启动流程解析
前言在之前我们学习了init进程、Zygote进程和SyetemServer进程的启动过程我们知道SystemServer进程主要用于启动系统的各种服务二者其中就包含了负责启动Launcher的服务LauncherAppService本篇我们将一起学习Launcher相关的知识。Launcher概述Launcher程序就是我们平时看到的桌面程序它其实也是一个Android应用程序只不过这个应用程序是系统默认第一个启动的应用程序Android系统启动的最后一步就是启动Launcher程序应用程序Launcher在启动过程中会请求PackageManagerService返回系统中已经安装的应用程序的信息并将这些信息封装成一个快捷图标列表显示在系统屏幕上这样用户可以通过点击这些快捷图标来启动相应的应用程序。Launcher启动流程SystemServer进程的启动过程中会调用其main静态方法开始执行整个SystemServer的启动流程在其中通过调用三个内部方法分别启动boot service、core service和other service。在调用startOtherService方法中就会通过调用mActivityManagerService.systemReady()方法而这个ActivityManagerService的systemReady函数就是启动Launcher的入口。frameworks/base/services/Java/com/android/server/SystemServer.javaprivatevoidstartOtherServices(){...mActivityManagerService.systemReady(newRunnable(){Overridepublicvoidrun(){Slog.i(TAG,Making services ready);mSystemServiceManager.startBootPhase(SystemService.PHASE_ACTIVITY_MANAGER_READY);...}...}可以发现这个方法传递了一个Runnable参数里面执行了各种其他服务的systemReady方法这里不是我们关注的重点我们看一下在ActivityManagerService中systemReady方法的具体实现frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.javapublicvoidsystemReady(final Runnable goingCallback){...// Start up initial activity.mBootingtrue;startHomeActivityLocked(mCurrentUserId,systemReady);...}重点是在这个方法体中调用了startHomeActivityLocked方法看其名字就是说开始执行启动homeActivity的操作booleanstartHomeActivityLocked(int userId,String reason){if(mFactoryTestFactoryTest.FACTORY_TEST_LOW_LEVELmTopActionnull){//1returnfalse;}Intent intentgetHomeIntent();//2ActivityInfo aInforesolveActivityInfo(intent,STOCK_PM_FLAGS,userId);if(aInfo!null){intent.setComponent(newComponentName(aInfo.applicationInfo.packageName,aInfo.name));aInfonewActivityInfo(aInfo);aInfo.applicationInfogetAppInfoForUser(aInfo.applicationInfo,userId);ProcessRecord appgetProcessRecordLocked(aInfo.processName,aInfo.applicationInfo.uid,true);if(appnull||app.instrumentationClassnull){//3intent.setFlags(intent.getFlags()|Intent.FLAG_ACTIVITY_NEW_TASK);mActivityStarter.startHomeActivityLocked(intent,aInfo,reason);//4}}else{Slog.wtf(TAG,No home screen found for intent,newThrowable());}returntrue;}注释1处的mFactoryTest代表系统的运行模式系统的运行模式分为三种分别是非工厂模式、低级工厂模式和高级工厂模式mTopAction则用来描述第一个被启动Activity组件的Action它的值为Intent.ACTION_MAIN。因此注释1的代码意思就是mFactoryTest为FactoryTest.FACTORY_TEST_LOW_LEVEL低级工厂模式并且mTopActionnull时直接返回false然后是调用getHomeIntent()方法IntentgetHomeIntent(){Intent intentnewIntent(mTopAction,mTopData!null?Uri.parse(mTopData):null);intent.setComponent(mTopComponent);if(mFactoryTest!FactoryTest.FACTORY_TEST_LOW_LEVEL){intent.addCategory(Intent.CATEGORY_HOME);}returnintent;}getHomeIntent函数中创建了Intent并将mTopAction和mTopData传入。mTopAction的值为Intent.ACTION_MAIN并且如果系统运行模式不是低级工厂模式则将intent的Category设置为Intent.CATEGORY_HOME。Launcher的Intent对象中添加了Intent.CATEGORY_HOME常量这个其实是一个launcher的标志一般系统的启动页面Activity都会在androidmanifest.xml中配置这个标志。我们再回到ActivityManagerService的startHomeActivityLocked函数假设系统的运行模式不是低级工厂模式在注释3处判断符合Action为Intent.ACTION_MAINCategory为Intent.CATEGORY_HOME的应用程序是否已经启动如果没启动则调用注释4的方法启动该应用程序。startHomeActivityLocked方法中经过一系列的判断逻辑之后最后调用了mStackSupervisor.startHomeActivity方法voidstartHomeActivity(Intent intent,ActivityInfo aInfo,String reason){moveHomeStackTaskToTop(HOME_ACTIVITY_TYPE,reason);startActivityLocked(null/* caller */,intent,null/* resolvedType */,aInfo,null/* voiceSession */,null/* voiceInteractor */,null/* resultTo */,null/* resultWho */,0/* requestCode */,0/* callingPid */,0/* callingUid */,null/* callingPackage */,0/* realCallingPid */,0/* realCallingUid */,0/* startFlags */,null/* options */,false/* ignoreTargetSecurity */,false/* componentSpecified */,null/* outActivity */,null/* container */,null/* inTask */);if(inResumeTopActivity){// If we are in resume section already, home activity will be initialized, but not// resumed (to avoid recursive resume) and will stay that way until something pokes it// again. We need to schedule another resume.scheduleResumeTopActivities();}}发现其调用的是scheduleResumeTopActivities()方法这个方法中就是Activity的启动流程的逻辑了此处不展开。Launcher启动的Intent是一个隐士的Intent所以我们会启动在androidmanifest.xml中配置了相同catogory的activityandroid M中配置的这个catogory就是LauncherActivity。LauncherActivity继承与ListActivity我们看一下其Layout布局文件FrameLayout xmlns:androidhttp://schemas.android.com/apk/res/androidandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentListView android:idandroid:id/listandroid:layout_widthmatch_parentandroid:layout_heightmatch_parent/TextView android:idandroid:id/emptyandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:gravitycenterandroid:textstring/activity_list_emptyandroid:visibilitygoneandroid:textAppearance?android:attr/textAppearanceMedium//FrameLayout可以看到我们现实的桌面其实就是一个ListView控件通过intent,应用程序Launcher就会被启动起来并执行它的onCreate函数。Launcher中应用图标显示流程packages/apps/Launcher3/src/com/android/launcher3/Launcher.javaOverrideprotectedvoidonCreate(Bundle savedInstanceState){...LauncherAppState appLauncherAppState.getInstance();//1mDeviceProfilegetResources().getConfiguration().orientationConfiguration.ORIENTATION_LANDSCAPE?app.getInvariantDeviceProfile().landscapeProfile:app.getInvariantDeviceProfile().portraitProfile;mSharedPrefsUtilities.getPrefs(this);mIsSafeModeEnabledgetPackageManager().isSafeMode();mModelapp.setLauncher(this);//2....if(!mRestoring){if(DISABLE_SYNCHRONOUS_BINDING_CURRENT_PAGE){mModel.startLoader(PagedView.INVALID_RESTORE_PAGE);//2}else{mModel.startLoader(mWorkspace.getRestorePage());}}...}注释1处获取LauncherAppState的实例并在注释2处调用它的setLauncher函数并将Launcher对象传入packages/apps/Launcher3/src/com/android/launcher3/LauncherAppState.javaLauncherModelsetLauncher(Launcher launcher){getLauncherProvider().setLauncherProviderChangeListener(launcher);mModel.initialize(launcher);//1mAccessibilityDelegate((launcher!null)Utilities.ATLEAST_LOLLIPOP)?newLauncherAccessibilityDelegate(launcher):null;returnmModel;}注释1处会调用LauncherModel的initialize函数publicvoidinitialize(Callbacks callbacks){synchronized(mLock){unbindItemInfosAndClearQueuedBindRunnables();mCallbacksnewWeakReferenceCallbacks(callbacks);}}在initialize函数中会将Callbacks也就是传入的Launcher 封装成一个弱引用对象。因此我们得知mCallbacks变量指的就是封装成弱引用对象的Launcher这个mCallbacks后文会用到它。 再回到Launcher的onCreate函数在注释2处调用了LauncherModel的startLoader函数packages/apps/Launcher3/src/com/android/launcher3/LauncherModel.java...Thunkstaticfinal HandlerThread sWorkerThreadnewHandlerThread(launcher-loader);//1static{sWorkerThread.start();}Thunkstaticfinal Handler sWorkernewHandler(sWorkerThread.getLooper());//2...publicvoidstartLoader(int synchronousBindPage,int loadFlags){s InstallShortcutReceiver.enableInstallQueue();synchronized(mLock){synchronized(mDeferredBindRunnables){mDeferredBindRunnables.clear();}if(mCallbacks!nullmCallbacks.get()!null){stopLoaderLocked();mLoaderTasknewLoaderTask(mApp.getContext(),loadFlags);//3if(synchronousBindPage!PagedView.INVALID_RESTORE_PAGEmAllAppsLoadedmWorkspaceLoaded!mIsLoaderTaskRunning){mLoaderTask.runBindSynchronousPage(synchronousBindPage);}else{sWorkerThread.setPriority(Thread.NORM_PRIORITY);sWorker.post(mLoaderTask);//4}}}}注释1处创建了具有消息循环的线程HandlerThread对象。注释2处创建了Handler并且传入HandlerThread的Looper。Hander的作用就是向HandlerThread发送消息。在注释3处创建LoaderTask在注释4处将LoaderTask作为消息发送给HandlerThread 。 LoaderTask类实现了Runnable接口当LoaderTask所描述的消息被处理时则会调用它的run函数privateclassLoaderTaskimplementsRunnable{...publicvoidrun(){synchronized(mLock){if(mStopped){return;}mIsLoaderTaskRunningtrue;}keep_running:{if(DEBUG_LOADERS)Log.d(TAG,step 1: loading workspace);loadAndBindWorkspace();//1if(mStopped){breakkeep_running;}waitForIdle();if(DEBUG_LOADERS)Log.d(TAG,step 2: loading all apps);loadAndBindAllApps();//2}mContextnull;synchronized(mLock){if(mLoaderTaskthis){mLoaderTasknull;}mIsLoaderTaskRunningfalse;mHasLoaderCompletedOncetrue;}}...}Launcher是用工作区的形式来显示系统安装的应用程序的快捷图标每一个工作区都是来描述一个抽象桌面的它由n个屏幕组成每个屏幕又分n个单元格每个单元格用来显示一个应用程序的快捷图标。注释1处调用loadAndBindWorkspace函数用来加载工作区信息注释2处的loadAndBindAllApps函数是用来加载系统已经安装的应用程序信息privatevoidloadAndBindAllApps(){if(DEBUG_LOADERS){Log.d(TAG,loadAndBindAllApps mAllAppsLoadedmAllAppsLoaded);}if(!mAllAppsLoaded){loadAllApps();//1synchronized(LoaderTask.this){if(mStopped){return;}}updateIconCache();synchronized(LoaderTask.this){if(mStopped){return;}mAllAppsLoadedtrue;}}else{onlyBindAllApps();}}如果系统没有加载已经安装的应用程序信息则会调用注释1处的loadAllApps函数privatevoidloadAllApps(){...mHandler.post(newRunnable(){publicvoidrun(){final long bindTimeSystemClock.uptimeMillis();final Callbacks callbackstryGetCallbacks(oldCallbacks);if(callbacks!null){callbacks.bindAllApplications(added);//1if(DEBUG_LOADERS){Log.d(TAG,bound added.size() apps in (SystemClock.uptimeMillis()-bindTime)ms);}}else{Log.i(TAG,not binding apps: no Launcher activity);}}});...}在注释1处会调用callbacks的bindAllApplications函数在前面我们得知这个callbacks实际是指向Launcher的因此我们来查看Launcher的bindAllApplications函数packages/apps/Launcher3/src/com/android/launcher3/Launcher.javapublicvoidbindAllApplications(final ArrayListAppInfoapps){if(waitUntilResume(mBindAllApplicationsRunnable,true)){mTmpAppsListapps;return;}if(mAppsView!null){mAppsView.setApps(apps);//1}if(mLauncherCallbacks!null){mLauncherCallbacks.bindAllApplications(apps);}}注释1处会调用AllAppsContainerView的setApps函数并将包含应用信息的列表apps传进去packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsContainerView.javapublicvoidsetApps(ListAppInfoapps){mApps.setApps(apps);}包含应用信息的列表apps已经设置到了AllAppsContainerView的AlphabeticalAppsList中查看AllAppsContainerView的onFinishInflate函数OverrideprotectedvoidonFinishInflate(){super.onFinishInflate();...// Load the all apps recycler viewmAppsRecyclerView(AllAppsRecyclerView)findViewById(R.id.apps_list_view);//1mAppsRecyclerView.setApps(mApps);//2mAppsRecyclerView.setLayoutManager(mLayoutManager);mAppsRecyclerView.setAdapter(mAdapter);//3mAppsRecyclerView.setHasFixedSize(true);mAppsRecyclerView.addOnScrollListener(mElevationController);mAppsRecyclerView.setElevationController(mElevationController);...}onFinishInflate函数在加载完xml文件时就会调用在注释1处得到AllAppsRecyclerView用来显示App列表并在注释2处将apps的信息列表传进去并在注释3处为AllAppsRecyclerView设置Adapter。这样应用程序快捷图标的列表就会显示在屏幕上。总结 Launcher的启动流程Zygote进程 – SystemServer进程 – startOtherService方法 – ActivityManagerService的systemReady方法 – startHomeActivityLocked方法 – ActivityStackSupervisor的startHomeActivity方法 – 执行Activity的启动逻辑执行scheduleResumeTopActivities()方法因为是隐试的启动Activity所以启动的Activity就是在AndroidManifest.xml中配置catogery的值为publicstaticfinal StringCATEGORY_HOMEandroid.intent.category.HOME;

最新新闻

日新闻

周新闻

月新闻