Launcher的启动过程

前言

Launcher即桌面,是Android智能设备的窗口,用户使用最频繁的软件之一。Launhcer是Android所有应用的入口,也提供窗口小部件等功能。如下图:

当然,Launcher本身就是一个APP,一个提供桌面的APP,我们也可以开发一款Launcher APP作为手机的桌面。Laucher有很多和普通APP不同的地方。

  • Launcher是顶部APP,即任何应用返回后都是到Launcher,不能再继续返回;
  • Launcher是所有应用的入口,可以管理应用;
  • Launcher是Android系统启动后就要显示给用户的应用。

我们的手机一开机第一眼看见的就是Launcher,也就是说Launcher在开机的过程中就已经启动完成,下文,我们就来看看

  1. Launcher的在开机时的启动过程;
  2. 每次按Home键的启动过程(上图中底部中间圆圈的按钮);
  3. 以及Launcher发生强退等应用退出等意外情况的启动过程。

开机Launcher的启动

手机开机时,会启动ActivityManagerService,在这个系统服务启动完成后,便会启动Launcher。关于ActivityManagerService启动过程的详细过程,读者可以参阅文章《 Android系统之System Server大纲 》。

启动时序图

ActivityManagerService启动完成后,会调用systemReady()方法,如下:

public void systemReady(final Runnable goingCallback) {synchronized(this) {.....startHomeActivityLocked(currentUserId, "systemReady");......
}

这个方法定义在文件frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java中。

如上面的代码,ActivityManagerService启动完成后调用systemReady()方法,然后调用startHomeActivityLocked()方法,启动HomeActivity,即Launcher应用的桌面Activity。继续看这个方法

boolean startHomeActivityLocked(int userId, String reason) {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);}}return true;
}

这个方法定义在文件frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java中。

上面的代码首先是调用了getHomeIntent()方法取得HomeActivity的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;
}

这个方法定义在文件frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java中。

上面的代码,new一个Intent对象,mTopAction的值是Intent.ACTION_MAIN,我们重点关注intent.addCategory(Intent.CATEGORY_HOME)这条语句,给HomeActvity 的 intent 对象添加Category Intent.CATEGORY_HOME=android.intent.category.HOME,也就是说Launcher的Activity必须声明Category android.intent.category.HOME,即表明这个Actiivty是一个Home Activity。

取得Intent返回startHomeActivityLocked()方法,通过方法resolveActivityInfo()遍历手机中所有安装包含Category Intent.CATEGORY_HOME=android.intent.category.HOME的Activity,然后把Activity的信息作为Component通过intent.setComponent()方法传输给intent对象。如果是Android原生的手机,此时aInfo.applicationInfo.packageName的值是:com.android.launcher3,aInfo.name的值是:com.android.launcher3.Launcher,即com.android.launcher3.Launcher(Android 7.0)是Home Activity。

然后调用mActivityStarter.startHomeActivityLocked()继续启动Home Activity。

void startHomeActivityLocked(Intent intent, ActivityInfo aInfo, String reason) {mSupervisor.moveHomeStackTaskToTop(HOME_ACTIVITY_TYPE, reason);startActivityLocked(null /*caller*/, intent, ......);if (mSupervisor.inResumeTopActivity) {mSupervisor.scheduleResumeTopActivities();}
}

这个方法定义在文件frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java中。

首先通过mSupervisor.moveHomeStackTaskToTop()方法把Launcher的堆栈移到顶部,这也是为什么Launcher总是在所有APP的顶部的原因。然后接着调用startActivityLocked()继续启动Home Activity。startActivityLocked()是Android系统启动所有Activity的入口,本文就不再阐述Activity的启动过程了。

按Home键的Launcher启动过程

时序图

既然是按Home键,那么就涉及到输入系统,Home是一个按键,当被按下时,底层会上报事件到InputManagerService,如下

// Native callback.
private long interceptKeyBeforeDispatching(InputWindowHandle focus,KeyEvent event, int policyFlags) {return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
}

这个方法定义在文件frameworks/base/services/core/java/com/android/server/input/InputManagerService.java中。

参数event封装了这次按键事件,接着调用了WindowManagerCallbacks即InputMonitor的interceptKeyBeforeDispatching方法

public long interceptKeyBeforeDispatching(InputWindowHandle focus, KeyEvent event, int policyFlags) {WindowState windowState = focus != null ? (WindowState) focus.windowState : null;return mService.mPolicy.interceptKeyBeforeDispatching(windowState, event, policyFlags);
}

这个方法定义在文件frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java中。

没有做任何处理,直接调用了mService.mPolicy.interceptKeyBeforeDispatching(),mPolicy实质是PhoneWindowManager对象

public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) {......if (keyCode == KeyEvent.KEYCODE_HOME) {......handleShortPressOnHome();return -1;}
}

这个方法定义在文件frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java中。

如上面的代码,keyCode是KeyEvent.KEYCODE_HOME时,调用处理短按home键handleShortPressOnHome()的方法

private void handleShortPressOnHome() {......// Go home!launchHomeFromHotKey();
}

这个方法定义在文件frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java中。

继续往下执行launchHomeFromHotKey()

void launchHomeFromHotKey(final boolean awakenFromDreams, final boolean respectKeyguard) {......sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);startDockOrHome(true /*fromHomeKey*/, awakenFromDreams);
}

这个方法定义在文件frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java中。

首先调用sendCloseSystemWindows()关闭系统弹窗,调用startDockOrHome()启动Dock或者Home,本文要论述的是如何启动Home。

void startDockOrHome(boolean fromHomeKey, boolean awakenFromDreams) {......if (fromHomeKey) {intent = new Intent(mHomeIntent);intent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, fromHomeKey);} else {intent = mHomeIntent;}startActivityAsUser(intent, UserHandle.CURRENT);
}

这个方法定义在文件frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java中。

创建Home Activity的Intent,mHomeIntent详情如下

mHomeIntent =  new Intent(Intent.ACTION_MAIN, null);
mHomeIntent.addCategory(Intent.CATEGORY_HOME);
mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);

如上文中提到,Home Activity的必须是一个携带Category为Intent.CATEGORY_HOME的Activity。在启动Activity之前,往Intent中设置WindowManagerPolicy.EXTRA_FROM_HOME_KEY/fromHomeKey的键值对,表明从Home按键启动Launcher。然后调用startActivityAsUser()方法,把Home Activity启动起来。

意外情况启动Launcher

所谓意外情况,比如Launcher强退等异常。Launcher也是一个普通的应用,当发生异常导致强退时,也就是说Launcher死掉了,那么由Launcher显示的桌面也没有了。但是,如果桌面都没有了,用户还怎么使用Launcher呢?所以,当Launcher发生异常等导致强退时,系统需要自动重新把Launcher启动起来。

时序图

以强退为例,我们知道Android的Activity由ActivityManagerService管理和维护者,当一个应用发生强退,会调用到ActivityManagerService的forceStopPackage()方法。

当应用强退时,调用ActivityManagerService的forceStopPackage()方法

public void forceStopPackage(final String packageName, int userId) {if (isUserRunningLocked(user, false)) {forceStopPackageLocked(packageName, pkgUid, "from pid " + callingPid);}
}

这个方法定义在文件frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java中。

如上面的代码,继续调用forceStopPackageLocked()方法,最终会调用scheduleIdleLocked()方法处理强退。

final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout,Configuration config) {......if (activityRemoved) {resumeTopActivitiesLocked();}return r;
}

这个方法定义在文件frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java中。

如上面的方法,从scheduleIdleLocked()一直到activityIdleInternalLocked(),再往下处理Activity挂掉的动作。

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {return isOnHomeDisplay() &&mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, reason);
}

这个方法定义在文件frameworks/base/services/core/java/com/android/server/am/ActivityStack.java中。

如上面的方法,如果挂掉的Activity是Home Activity,那么调用resumeHomeStackTask()重新启动Launcher。最后调用ActivityManagerService的startHomeActivityLocked()方法,这里和开机启动的Launcher的过程一样了。更详细的流程请查看时序图。

Launcher的启动过程相关推荐

  1. Android系统默认Home应用程序 Launcher 的启动过程源代码分析

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 在前面一 ...

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

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

  3. Android 系统(15)---Launcher启动过程

    Launcher概述 SystemServer进程主要用于启动系统的各种服务,其中就包含了Launcher服务,LauncherAppService. Android系统默认第一个启动的应用程序是Ho ...

  4. Android系统启动(四) — Launcher 启动过程

    1 Launcher 概述 系统启动的最后一步是启动一个应用程序来显示系统中已经安装的应用程序,这个应用程序就叫做 Launcher.Launcher 在启动过程中会请求 PackageManager ...

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

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

  6. Android系统的启动过程

    Android系统的启动过程可以简单地总结为以下几个流程: 加载BootLoader -> 初始化内核 -> 启动init进程 -> init进程fork出Zygote(孵化器)进程 ...

  7. Launcher 的启动

    1.Launcher概述 Android系统启动的最后一步是启动一个Home应用程序,这个应用程序用来显示系统中已经安装的应用程序,这个Home应用程序就叫做Launcher.应用程序Launcher ...

  8. Android系统默认Home应用程序(Launcher)的启动过程源代码分析

    在前面一篇文章中,我们分析了Android系统在启动时安装应用程序的过程,这些应用程序安装好之后,还需要有一个Home应用程序来负责把它们在桌面上展示出来,在Android系统中,这个默认的Home应 ...

  9. Android系统默认Home应用程序(Launcher)的启动过程源代码分析(3)

    Step 13.  ActivityStack.startActivityLocked 这个函数定义在frameworks/base/services/java/com/android/server/ ...

最新文章

  1. 用verilog语言写的任意整数的分频器
  2. Python面试必知(四)
  3. Wcf 接收对http://*.*.*.*的的 HTTP 响应时发生错误... 的解决方法
  4. 用Maven构建Hadoop项目
  5. Crontab使用详解
  6. Ipad 日程管理APP使用心得
  7. SQLite数据操作
  8. android 血压计开发,智能血压计方案开发
  9. mysql 时间戳与java_在Java中处理MySQL日期时间和时间戳
  10. Map-Reduce
  11. 思科ccna教材_什么是CCNA或Cisco认证网络助理?
  12. LPC1788启动代码分析
  13. Windows兼容性设置图文教程,Windows兼容模式怎么设置?
  14. 自己封装的Socket组件,实现服务端多进程共享Socket对象,协同处理客户端请求...
  15. 【程序员必读】经验:编程的智慧
  16. FPGA调用OLED
  17. 计算机逻辑算法,算法逻辑
  18. java基于ssm的洗衣店管理系统
  19. 基于matlab的LFM脉冲压缩仿真
  20. 微机原理和计算机组成原理一样吗_「计算机组成原理」:一文快速了解计算机原理知识点-附思维导图...

热门文章

  1. 【JZOJ 5405】【NOIP2017提高A组模拟10.10】Permutation
  2. 西游记的四种性格和生活的人
  3. 进程和线程的主要区别及进程与程序的主要区别
  4. ADS-B及雷达显示终端8.0
  5. python三方库打包项目中_python项目生成及导入依赖的第三方库
  6. 必读论文 | 卷积神经网络百篇经典论文推荐
  7. jQuery的属性,位置,元素操作
  8. 关于联想笔记本不能连接无线网(wifi),注销后重新登录才可以连接
  9. 「Linux-基础」CentOS8 权限管理
  10. P3-2017级算法第三次上机 B SkyLee逛漫展