本系列主要介绍Android8.0系统启动过程中涉及到的init、Zygote、SystemServer和Launcher。
在之前的三篇文章中,讲解了如下的过程:

  • 初始化化:电源上电,加载BootLoader程序; 启动init.cpp,解析init.rc配置文件;
  • 启动Zygote进程:启动虚拟机和注册JNI方法;注册Socket服务端,预加载资源;执行runSelectLoop()方法等待其他进程的注册;
  • 启动SystemServer进程:通过Zygote启动,创建Binder线程池、执行main方法;开启 三个系统服务(引导、核心和其他)。

在完成以上三个过程后,我们的系统就开始加载Launcher应用,查看源码可以发现Launcher是作为一个APP应用执行的,其一般位于系统的packages/apps目录下,可以通过该应用启动系统中其他应用程序,提供快捷访问图标。

一、Launcher的启动

1.1启动准备

在SystemServer启动时,会先启动引导服务,其中包括PMS(PackageManagerService)和AMS(ActivityManagerService),其中PMS主要作用是系统中的APK的解析和安装;AMS主要用于四大组件的启动 和管理,因此LauncherActivity通过AMS启动。
完成引导服务的启动后,开启启动其他服务。启动Launcher的入口为AMS的systemReady方法,

frameworks\base\services\java\com\android\server\SystemServer.javaprivate void startOtherServices() {...//在此之前会做大量的准备工作,包括AMS、PMS 和NetworkScoreService等各种服务,完成以上操作后,表示activity manager可以运行mActivityManagerService.systemReady(() -> {Slog.i(TAG, "Making services ready");traceBeginAndSlog("StartActivityManagerReadyPhase");mSystemServiceManager.startBootPhase(SystemService.PHASE_ACTIVITY_MANAGER_READY);...}......
}
frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.javapublic void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {traceLog.traceBegin("PhaseActivityManagerReady");synchronized(this) {
...mStackSupervisor.resumeFocusedStackTopActivityLocked();mUserController.sendUserSwitchBroadcastsLocked(-1, currentUserId);
...}
}

1.2找到Launcher 的Activity

AMS通过调用ActivityStack实现对堆栈中Activity对象的管理,我们的最终目的是查找到Launcher应用所在的Activity是如何被调用起来的?
其流程如下:
ActivityStackSuperior#resumeFocusedStackTopActivityLocked() ->ActivityStack#resumeTopActivityUncheckedLocked()->resumeTopActivityInnerLocked()
在resumeTopActivityInnerLocked中,通过调用startHomeActivityLocked方法,开启启动Launcher的Activty。

frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.javaboolean resumeFocusedStackTopActivityLocked(ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {if (targetStack != null && isFocusedStack(targetStack)) {return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);}...return false;
frameworks\base\services\core\java\com\android\server\am\ActivityStack.java
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
if (mStackSupervisor.inResumeTopActivity) {return false;}boolean result = false;try {mStackSupervisor.inResumeTopActivity = true;result = resumeTopActivityInnerLocked(prev, options);} finally {mStackSupervisor.inResumeTopActivity = false;}final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);if (next == null || !next.canTurnScreenOn()) {checkReadyForSleep();}return result;
}
frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.javaprivate boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {...
return isOnHomeDisplay() &&mStackSupervisor.resumeHomeStackTask(prev, reason);...if (r != null && !r.finishing) {moveFocusableActivityStackToFrontLocked(r, myReason);return resumeFocusedStackTopActivityLocked(mHomeStack, prev, null);}return mService.startHomeActivityLocked(mCurrentUser, myReason);
...
}

1.3 启动Launcher

frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.javaboolean startHomeActivityLocked(int userId, String reason) {//1 判断工厂模式和topAction
if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL&& mTopAction == null) {return false;}//2 创建启动Launcher的IntentIntent intent = 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);ProcessRecord app = getProcessRecordLocked(aInfo.processName,aInfo.applicationInfo.uid, true);if (app == null || app.instr == null) {intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);final int resolvedUserId = UserHandle.getUserId(aInfo.applicationInfo.uid); final String myReason = reason + ":" + userId + ":" + resolvedUserId;//3 启动LauncdrmActivityStarter.startHomeActivityLocked(intent, aInfo, myReason);}} else {Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());}return true;
}

在注释1处是对运行模式和Action的判断,其中运行模式包括:非工厂模式、低级工厂模式和高级工厂模式。而Action的是是指启动该Intent的Action,默认是Intent.ACTION_MAIN,表示是该应用的第一个启动的Activity,一般在创建应用时,AndroidMainfest.xm中都会包含唯一个该标签的Action。
而对于桌面应用,会增加Intent.HOME的标签,如果我们想自定义桌面应用,可在该应用的AndroidMainfest中的启动Activity的Action添加android.Intent.action.HOME,如下所示:

 <application...<activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.HOME"/><action android:name="android.intent.action.MAIN"/><category android:name="android.intent.category.LAUNCHER"/></intent-filter></activity></application>

启动Launer是在ActivityStarter的startHomeActivityLocked方法中完成,通过ActivityStackSupervisor将该Intent移动至HomeStack(用于存储Launcher的变量)的顶部,最终调用startActivityLocked方法启动该Intnet,实现对Launcer的启动。

 void startHomeActivityLocked(Intent intent, ActivityInfo aInfo, String reason) {mSupervisor.moveHomeStackTaskToTop(reason);...}

二 、Launcher桌面图标显示

完成Launcer的启动后,作为一个独立的APP,Launcher开始执行应用的加载和桌面图标的显示。

2.1 加载APP

packages\apps\Launcher3\src\com\android\launcher3\Launcher.java
protected void onCreate(Bundle savedInstanceState) {
...
//加载桌面颜色信息和监听主题变化WallpaperColorInfo wallpaperColorInfo = WallpaperColorInfo.getInstance(this);wallpaperColorInfo.setOnThemeChangeListener(this);
...
//加载桌面应用信息LauncherAppState app = LauncherAppState.getInstance(this);...mModel = app.setLauncher(this);...//加载和设置桌面viewmLauncherView = LayoutInflater.from(this).inflate(R.layout.launcher, null);setupViews();...if (!mModel.startLoader(currentScreen)) {mDragLayer.setAlpha(0);} else {mWorkspace.setCurrentPage(currentScreen);setWorkspaceLoading(true);}
}
//设置launcher的监听,初始化model
packages\apps\Launcher3\src\com\android\launcher3\LauncherAppStateLauncherModel setLauncher(Launcher launcher) {getLocalProvider(mContext).setLauncherProviderChangeListener(launcher);mModel.initialize(launcher); //传入Launcher对象return mModel;}

在设置监听时,传入的Callbacks 对象时Launcher,是为了在APP加载完成时,方便通过接口回调的形式返回值Launcher,
下面开始加载App。

packages\apps\Launcher3\src\com\android\launcher3\LauncherModelpublic void initialize(Callbacks callbacks) {synchronized (mLock) {Preconditions.assertUIThread();mCallbacks = new WeakReference<>(callbacks);}}//Callbacks 接口包含的内容如下,主要用到bindAllApplications
public interface Callbacks extends LauncherAppWidgetHost.ProviderChangedListener {...public void bindAllApplications(ArrayList<AppInfo> apps);public void bindAppsAddedOrUpdated(ArrayList<AppInfo> apps);public void bindAppsAdded(ArrayList<Long> newScreens,ArrayList<ItemInfo> addNotAnimated,ArrayList<ItemInfo> addAnimated);public void bindPromiseAppProgressUpdated(PromiseAppInfo app);public void bindShortcutsChanged(ArrayList<ShortcutInfo> updated, UserHandle user);public void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets);public void bindRestoreItemsChange(HashSet<ItemInfo> updates);public void bindWorkspaceComponentsRemoved(ItemInfoMatcher matcher);public void bindAppInfosRemoved(ArrayList<AppInfo> appInfos);public void bindAllWidgets(MultiHashMap<PackageItemInfo, WidgetItem> widgets);...}

加载的Task分析如下

...
packages\apps\Launcher3\src\com\android\launcher3\LauncherModel
//开始加载
public boolean startLoader(int synchronousBindPage) {...synchronized (mLock) {//清除之前的回调缓存if (mCallbacks != null && mCallbacks.get() != null) {final Callbacks oldCallbacks = mCallbacks.get();// Clear any pending bind-runnables from the synchronized load process.mUiExecutor.execute(new Runnable() {public void run() {oldCallbacks.clearPendingBinds();}});// If there is already one running, tell it to stop.stopLoader();LoaderResults loaderResults = new LoaderResults(mApp, sBgDataModel,mBgAllAppsList, synchronousBindPage, mCallbacks);//包含Callbacks对象if (mModelLoaded && !mIsLoaderTaskRunning) {    //已经加载完成且没有正在加载//加载完成后,开始将结果回调至LauncherloaderResults.bindWorkspace();loaderResults.bindAllApps(); //加载的回调loaderResults.bindDeepShortcuts();loaderResults.bindWidgets();return true;} else {//开始不断的加载 工作区间、所有的APP、快捷图标和抽屉控件startLoaderForResults(loaderResults);}}}return false;}packages\apps\Launcher3\src\com\android\launcher3\LauncherModel
public void startLoaderForResults(LoaderResults results) {synchronized (mLock) {//停止加载stopLoader();//创建新的加载taskmLoaderTask = new LoaderTask(mApp, mBgAllAppsList, sBgDataModel, results);//在WorkerThread中执行该taskrunOnWorkerThread(mLoaderTask);}}//加载中涉及的线程初始化packages\apps\Launcher3\src\com\android\launcher3\LauncherModel
@Thunk static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");static {sWorkerThread.start();}
@Thunk static final Handler sWorker = new Handler(sWorkerThread.getLooper());

2.2 加载回调处理

通过LauncherModel的加载线程,获取到了系统中所有的apps的信息,同时通过其Callbacks的接口,很方便的将结果传递出去,

packages\apps\Launcher3\src\com\android\launcher3\Launcher.java
public void bindAllApplications(final ArrayList<AppInfo> apps) {Runnable r = new RunnableWithId(RUNNABLE_ID_BIND_APPS) {public void run() {bindAllApplications(apps);}};...//加载完成后AllAppsContainerView数据更新mAppsView.setApps(apps);}if (mLauncherCallbacks != null) {mLauncherCallbacks.bindAllApplications(apps);}}

数据回调值Launcher的bindAllApplications,开始对AllAppsContainerView界面进行数据设置,其设置的控制控件为AlphabeticalAppsList,通过调用AlphabeticalAppsList实现对数据的设置处理,其实现流程和Recycleview的设置比较类似。

packages\apps\Launcher3\src\com\android\launcher3\allapps\AllAppsContainerView.javapublic void setApps(List<AppInfo> apps) {mApps.setApps(apps);}//数据传递控制控件中
packages\apps\Launcher3\src\com\android\launcher3\allapps\AlphabeticalAppsList.java
public void setApps(List<AppInfo> apps) {mComponentToAppMap.clear();addOrUpdateApps(apps);}packages\apps\Launcher3\src\com\android\launcher3\allapps\AllAppsContainerView.java@Overrideprotected void onFinishInflate() {
...mAppsRecyclerView = findViewById(R.id.apps_list_view); //可以看到桌面应用部分的界面为RecyclerViewmAppsRecyclerView.setApps(mApps);mAppsRecyclerView.setLayoutManager(mLayoutManager);mAppsRecyclerView.setAdapter(mAdapter);mAppsRecyclerView.setHasFixedSize(true);
...}

AllAppsContainerView会在XML布局文件加载完成后,调用onFinishInflate方法,使加载的数据最终显示在桌面上。形成我们看到的桌面图标。

2.3 点击桌面图标的跳转至应用

在AllAppsContainerView设置adapter后,由于RecyclerView不包含setOnItemClickListener方法,因此一般是在Adapter中自定义实现,可通过回调的形式将点击事件传递出去,Launcher的执行流程如下:

//packages\apps\Launcher3\src\com\android\launcher3\allapps\AllAppsContainerView.javapublic AllAppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {...//创建新的AdaptermAdapter = new AllAppsGridAdapter(mLauncher, mApps, mLauncher, this);mSpringAnimationHandler = mAdapter.getSpringAnimationHandler();mApps.setAdapter(mAdapter);...}

设置点击的监听回调

//packages\apps\Launcher3\src\com\android\launcher3\allapps\AllAppsGridAdapter.javapublic AllAppsGridAdapter(Launcher launcher, AlphabeticalAppsList apps, View.OnClickListenericonClickListener, View.OnLongClickListener iconLongClickListener) {...mIconClickListener = iconClickListener;...}

点击事件的处理

packages\apps\Launcher3\src\com\android\launcher3\Launcher.javapublic void onClick(View v) {
...Object tag = v.getTag();if (tag instanceof ShortcutInfo) {onClickAppShortcut(v);} else if (tag instanceof FolderInfo) {if (v instanceof FolderIcon) {onClickFolderIcon(v);}} else if ((v instanceof PageIndicator) ||(v == mAllAppsButton && mAllAppsButton != null)) {onClickAllAppsButton(v);} else if (tag instanceof AppInfo) {startAppShortcutOrInfoActivity(v);} else if (tag instanceof LauncherAppWidgetInfo) {if (v instanceof PendingAppWidgetHostView) {onClickPendingWidget((PendingAppWidgetHostView) v);}}
}//点击桌面应用的快捷图标的处理
protected void onClickAppShortcut(final View v) {
...startAppShortcutOrInfoActivity(v);
...
}private void startAppShortcutOrInfoActivity(View v) {ItemInfo item = (ItemInfo) v.getTag();Intent intent;if (item instanceof PromiseAppInfo) {PromiseAppInfo promiseAppInfo = (PromiseAppInfo) item;intent = promiseAppInfo.getMarketIntent();} else {intent = item.getIntent();}...//跳转至相应的应用boolean success = startActivitySafely(v, intent, item);
...}

至此Launcher的启动过程便分析完,总结如下:

  1. 启动:SystemServer启动PMS和AMS,通过AMS的systemReady开始加载;
  2. 查找:查找流程如下ActivityStackSuperior#resumeFocusedStackTopActivityLocked() ->ActivityStack#resumeTopActivityUncheckedLocked()->resumeTopActivityInnerLocked();
  3. 显示:在resumeTopActivityInnerLocked中通过调用startHomeActivityLocked方法,启动Launcher的Activty,通过LauncherModel的加载线程处理,获取到所有的Apps信息,借助Callbacks的接口回调的形式将数据返回值Launcher,然后将数据赋值给AllAppsContainerView,使Apps的桌面图标显示至桌面中。
  4. 跳转:通过设置点击事件的回调处理,点击桌面图标后,通过startActivitySafely跳转至应用的Main界面。

Android 8.0系统启动流程_Launcher(四)相关推荐

  1. Android 7.0系统启动流程分析

    随着Android版本的升级,aosp项目中的代码也有了些变化,本文基于Android 7.0分析Android系统启动流程.当我们按下电源键后,整个Android设备大体经过了一下过程:  今天我们 ...

  2. Android 10.0 系统启动之SystemServer进程-[Android取经之路]

    摘要:上一节讲解了Zygote进程的整个启动流程.Zygote是所有应用的鼻祖.SystemServer和其他所有Dalivik虚拟机进程都是由Zygote fork而来.Zygote fork的第一 ...

  3. Android 10.0系统启动之init进程-[Android取经之路]

    摘要:init进程是linux系统中用户空间的第一个进程,进程号为1.当bootloader启动后,启动kernel,kernel启动完后,在用户空间启动init进程,再通过init进程,来读取ini ...

  4. Android8.0(34)----Android 8.0 Settings流程分析与变动

    Android 8.0 Settings流程分析与变动 一,相比Android Settings 7.0 如下图,在7.0的基础上,去掉了7.0新加的侧滑菜单(可能是觉得有点鸡肋吧).多加了一级页面, ...

  5. Android系统启动流程(四)Launcher进程启动过程解析(附带面试题)

    前面我们分析了init进程,zygote进程,SystemServer进程,本篇的Launcher是系统启动流程的最后一个进程. 1 Launcher概述 Launcher进程是一个系统的应用程序,位 ...

  6. Android系统启动流程(四)Launcher启动过程与系统启动流程

    相关文章 Android系统架构与系统源码目录 Android系统启动流程(一)解析init进程启动过程 Android系统启动流程(二)解析Zygote进程启动过程 Android系统启动流程(三) ...

  7. Android 7.0 Keyguard流程分析

    在android 6.0 上Keyguard作为了SystemUI的一个库文件被引用,所以编译的时候不会出现Keyguard.apk这个文件,Keyguard也伴随着SystemUI的启动而启动,其中 ...

  8. (连载)Android 8.0 : 系统启动流程之Linux内核

    这是一个连载的博文系列,我将持续为大家提供尽可能透彻的Android源码分析 github连载地址 前言 Android本质上就是一个基于Linux内核的操作系统,与Ubuntu Linux.Fedo ...

  9. AOSP Android 8.0 冷启动流程分析(二)

    前奏: Android系统虽然基于Linux系统的,但是由于Android属于嵌入式设备,并没有像PC那样的BISO程序,取而代之的是Bootloader----系统启动加载器. /boot : 存放 ...

最新文章

  1. python-上传文件的几种方式
  2. TCP客户端服务端编程模型
  3. mysql update 几万 非常慢_mysqL update 太慢,求解决方法
  4. Interpreter(解释器)--类行为型模式
  5. 要闻君说:华为发布2018年年度报告:全球销售收入超千亿美元;微软”立誓“不过愚人节;大众与AWS一起做工业汽车云...
  6. 厄米高斯光束 matlab,拉盖尔高斯光束_厄米高斯光束MATLAB仿真
  7. 559. N叉树的最大深度
  8. 文件编码 ANSI、GBK、GB2312、MS936、MS932、SJIS、Windows-31 、EUC-JP 、EBCDIC 等等之间的区别与联系
  9. 对高级程序设计语言的基本理解
  10. 【Android -- 开源库】BRVAH 的基本使用
  11. 安卓禁用硬件加速_详解Android开发中硬件加速支持的使用方法
  12. 华为防火墙ssl xxx配置
  13. 浅谈外存分配的几种方式
  14. 简述计算机组装的具体流程,简述计算机的组装流程??
  15. FC/NES PPU 示例汇编程序 简易画图
  16. IDEA的使用大全(快捷键、TomCat、Maven......)
  17. zabbix探究告警触发器Triggers
  18. 未来应用陈鸿:被微信封掉公众号后怎么办?给微信创业者的10点真诚建议
  19. 基于ssm框架的校园订餐系统设计与实现毕业设计源码270912
  20. 基于STM32的智能家居系统设计

热门文章

  1. 研大考研不是骗子,了解研大品质
  2. 网易面试题:卡特兰数
  3. Qtum量子链Github 开发指南
  4. 学习笔记about Markdown (项目管理第一周)
  5. AI智能音箱工作原理中应用的数字功放芯片
  6. 解放双手,不写 SQL!一个开源 mybatis 神器
  7. 八卦Google 的前端开发方式及流程
  8. 帷幕的帷是什么意思_毕业是什么意思?孩子给出了自己的答案
  9. 2021年顺德区首届镇街篮球联赛揭幕战在北滘拉开帷幕
  10. java fgc_记一次频繁FGC的简单排查