精华内容
下载资源
问答
  • 主要介绍了Activiti如何启动流程并使流程前进,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • 主要介绍了Android APP启动方式、启动流程启动优化分析的相关资料,需要的朋友可以参考下
  • 本文介绍了浅谈android性能优化之启动过程(冷启动和热启动) ,分享给大家,具体如下: 一、应用的启动方式 通常来说,启动方式分为两种:冷启动和热启动。 1、冷启动:当启动应用时,后台没有该应用的进程,这时系统...
  • 主要介绍了Spring IOC 容器启动流程分析,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
  • 1. 启动过程中dts解析过程 2. 启动过程中dts与platform、int的关联 3. 针对100ask linux kernel
  • 一台linux系统的电脑,从按下开关到登录到系统上整个过程,经历了什么,这是我们这次要讨论的问题。 其实一共有四个阶段 BIOS启动引导阶段 GRUB启动引导阶段; 内核阶段; init初始化阶段。 1. BIOS启动引导阶段 在...
  • Linux启动过程

    2018-12-03 11:00:13
    基于i386体系结构的Linux启动代码分析,概述Linux系统的启动顺序
  • 启动过程流程图2. 对启动过程的解读2.1 从BIOS--->内核解压并自检2.2 从找到intramfs-->挂载真正的根目录2.2.1 查看initramfs文件2.3 从/sbin/init到/etc/init/rcS.conf2.4 从/etc/inittab到进入系统3. 总结 ...

    前言

    • Linux的启动过程还是非常复杂的。学习启动过程可以加深对Linux有整体认识,从而对Linux的体系更加了解。字不如图,图不如视频。所以通过图的方式,来学习Linux启动过程。

    1. 启动过程流程图

     
    在这里插入图片描述

     

    2. 对启动过程的解读

    2.1 从BIOS—>内核解压并自检

    • 当我们开机之后,主板上的BIOS芯片就会进行自检,自检完成之后,会加载MBR(主引导记录),主引导记录当中保存是启动引导程序, 在Linux当中,Linux的启动引导程序叫grub,grub保存在MBR里,是系统启动的主要引导程序,在MBR当中,通过这个引导程序来进行下一步的启动过程,这个时候会进行选择,有一个分支,如果服务器只有一个Linux,那么启动引导程序grub就会直接加载Linux内核,然后进行下一步的启动。如果计算机里不仅有Linux还有Windows,或者有两个不同版本的Linux,这个时候会进入多系统启动的状态,有一个列表,在里面去选。 这时会出现类似Windows的界面会让你选,虚拟机在启动的时候会有倒数五秒,在倒数五秒的时候按一下任意键盘,会出现选择界面,默认只有一个Linux系统,要是有多个可以在这里去选,到底启动哪一个,那么选定哪个操作系统就会加载这个操作系统所对应的内核,选的是Linux,就会加载Linux内核,选的是Windows,就加载Windows内核。如果有多个系统就会多一个选择界面。最终都会加载需要启动操作系统的内核。然后启动就会到下一步。内核是压缩的内核,内核本身就不大,如果不压缩会占用比较大的启动空间,所以把它做了一个压缩。所以会先在内存当中进行压缩进行解压缩,解压缩之后,内核会在做一次自检,bios会进行一次自检,内核在进行一次自检,如果是Linux,一般Linux信任的是内核自检,会把内核的自检过程记录在dmesg命令(输入可以看到启动自检过程的信息)当中,启动这个过程之后,内核加载之后,就需要内核去加载驱动。

    2.2 从找到intramfs–>挂载真正的根目录

    • 前言: 装虚拟机的时候是这样的,安装完Linux,所有的硬件内核直接就驱动了,然后就直接可以使用了。Windows:装完计算机,需要给每一个硬件安装驱动,然后才能使用,说明Windows装的单纯的操作系统。不附带任何驱动程序,如果想使用驱动,需要手工安装,当然Windows当中会集成一些简单的驱动,到那时绝大多数的驱动还是需要手动安装的,但是Linux不是,Linux的真实机安装和虚拟机安装是完全一样的。
    • 内核只要安装完,所有的驱动都装在内核当中,内核通过服务器的硬件,来判断到底需要哪个驱动,会自动加载(练习用的虚拟机和真实机完全一样,都不需要手工安装驱动,只需要把内核装那,会自动帮你检测驱动。)这样有一个问题,如果把所有硬件的驱动都放在内核里,那么内核就会变得无比庞大。 解决方案是: 把常见得驱动放在内核里。把不常见的驱动,作为函数模块。把驱动写成一个程序,保存在硬盘里,一般放在硬盘的/lib/这个目录当中,是函数库的保存位置。 把他放进去,然后当我需要的时候内核直接去这里去读,把他拿出来就可以了。这样保证了我的内核不会太大。绝大多数的硬件驱动都不需要手工安装,Linux会自动进行识别。只有一种情况下,需要手工安装驱动,比如Linux内核当中没有包含这个硬件的驱动,比如说硬件太新了。当这个硬件发行的时候,内核早都出现了。所以有可能进行手工安装。但是大多数的程序,尤其是服务器上的硬件,都不需要手工安装驱动。也就是说内核解压自检完成之后,应该去/lib/下去读取这个驱动。读出来就可以加载了。
    • 硬盘接口的驱动在硬盘里,内核需要去硬盘读取驱动,可是内核没有硬盘接口的驱动,进不去,这个问题该如何解决??? 我们的硬盘如果是IDE接口,IDE接口的驱动是直接在内存当中,就可以认识IDE硬盘,然后去找到/lib/目录然后拿出。但是我们现在绝大多数的计算机,我们的硬盘都是SATA接口的,或者SCSI接口(淘汰了)。SATA接口的硬盘,内核认为驱动不是必须的,所以他是作为模块放在/lib这个目录当中。这就是产生的问题: 我的内核必须要去/lib/当中读取出来SATA的这个驱动,才能识别硬盘,但是我既然没有识别硬盘,怎么去加载他的驱动那???SATA接口的这个驱动,是放在硬盘的/lib/目录下的,但是如果我没有这个驱动,是无法读取这个硬盘的,我也当然就无法打开/lib这个目录。
    • 举个形象的栗子来说明这个问题: 如果进自己家的门,通过钥匙才能打开,但是那钥匙(相当于驱动,驱动就放在/lib/目录下),但是钥匙没有在身上(相当于内核没有驱动),而是把锁在了房间里面。请问如何进这个屋里???解决方法: 如果真要开房间就要找开锁公司,但是对Linux内核,也是用类似的办法。他在我们的启动分区当中,有一个initamfs文件系统,这个文件系统模拟了一个跟硬盘基本相似的这个结构,然后那内核先加载他,通过它把基本的常见驱动,加载到内核里,也就是说SATA的这个驱动,没有直接再从/lib/下去调,而是从这个假的文件系统里面去调,内核加载了它之后,才建立仿真目录,然后才能去加载真正的硬盘分区,才能读取剩余的其他驱动。 也就是说有一个假的根目录,这个根目录当中保存了硬盘上必须的这些驱动。把这个加载到内核里,内核就可以去调用真正的硬盘。相当于找开锁公司,配了把假钥匙,拿这个假钥匙就能打开门,能取出真钥匙,才能读取后续的命令。
    • 这时还会有疑问: Initramfs文件是放在/boot目录下,那/boot/不也在硬盘上吗?内核居然没法加载/lib/,当然也无法加载/boot??? /boot这个分区不是由内核直接加载的,而是由启动引导程序事先就已经读取出来的。 /boot目录整个就是启动分区,所以启动引导程序默认是可以识别boot分区的,所以不存在驱动这样的一个过程。

    2.2.1 查看initramfs文件

    开始实验:

    • (1)打开这个initramfs内存文件系统,看一下里面有什么
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述

    小提示:

    • cpio命令在rpm包安装的时候使用过,cpio –ivcdu < 文件 就可以读取里面的内容,会把这个文件解压缩。bin、dev、etc、lib目录,绝大多数的驱动都在这,跟真正的根目录有些相似,也就是说是利用这个文件,模拟一个跟根差不多的目录,主要的目的是为了加载这个文件当中,lib下的这些驱动。
    • 上面的查看initramfs文件的过程是手工进行解压的过程,在真正启动的时候,这个解压过程应该在内存当中直接进行的,建立仿真目录,里面有硬件的驱动。然后就可以读取真正的硬盘上的驱动了,就可以读取真正的系统的硬盘了。然后就可以读取里面真正的根目录了。 到这个时候,这个仿真根目录的作用使命就结束了。

    2.3 从/sbin/init到/etc/init/rcS.conf

    读出来真正的系统硬盘空间。系统启动的第一个进程,通过它才可以进行后续的启动进程。然后调用了/etc/init/rcS.conf文件。

    /etc/init/rcS.conf文件主要有两个功能:

    • 第一个功能: 先调用/etc/rc.d/rc.sysinit这个文件,主要作用是进行Linux系统的初始化。 (没有这个文件的存在,系统是无法正常启动的,其实它只要正常加载,正常初始化,这时系统的基本功能就已经全部具备了。完成系统的基本启动。)
    • 第二个功能是:然后再调用/etc/inittab,确定系统默认级别。 就是定义进入字符界面还是进入图形界面。(定义了运行级别之后那,需要把运行级别传到/etc/init/rc.conf这个配置文件,通过这个配置文件调用/etc/rc.d/rc,其实归根结底是调用/etc/rc[0-6].d这个目录。如果是字符界面,那就调用/etc/rc3.d这个目录下所有的程序,如果是图形界面,那就调用/etc/rc5.d当中的所有程序。)

    小总结:

    • (1)读出来之后继续调用/sbin/init这个文件,这个命令。init是系统启动的第一个进程,是所有其余进程的父进程,在centos 5.x当中,他的作用会远比现在还要大,现在作用稍微消弱了。但还是系统启动的第一个进程。
    • (2)也就是说/etc/init/rcS.conf有两个功能,第一进行系统的初始化,系统初始化完成之后,操作系统的基本功能就具备了。但是这只是它的最基本功能,要想正常使用,需要确定系统是进入的字符界面还是图形界面,如果进入的是不同的界面,还需要启动对应的附加程序才可以完成整个系统的启动。

    2.4 从/etc/inittab到进入系统

    从/etc/inittab经过调用,运行级别参数传入/etc/rc.d/rc这个脚本之后,由这个脚本我呢见按照不同的级别启动/etc/rc[0-6].d/目录中的相应的程序。如果级别为3,进入cd /etc/rc3.d/ 字符界面的级别下,目录下都是执行文件。而且这些执行文件很特殊,很有规律,要么以K开头,要么以S开头的,K开头的对字符界面没有太大的作用,所以默认把他关了。S开头的一次启动,如果把这些程序都启动了,我的系统就进入了对应的字符界面级别。这些都是程序,全部都是命令,他们都是软连接(快捷方式);

    /etc/rc3.d/K??开头的文件 (??是数字),会按照数字顺寻依次关闭
    /etc/rc3.d/S??开头的文件 (??是数字),会按照数字顺序依次启动

    • (1)查看/etc/rc3.d文件
       
      在这里插入图片描述
      在这里插入图片描述
       
    • 在登录界面之前还会调用,/etc/rc.d/rc.local(服务管理涉及过)文件,只要把这个命令写到这个文件里,在开机的时候都会执行一遍。为什么再开机是都会执行一遍那???按照启动顺序,在登录之前,会把这个文件当中所有的命令都会执行一遍,所以可以把服务的启动命令写在这里。然后登录进入系统。注意: 如果是图形界面,/etc/rc.d/rc.local这一步执行完之后,还要进行一系列操作,这里主要指的是启动了图形界面的Xserver和图形界面的Xclient程序,依次启动之后才可以起。

    3. 总结

    (1) 从BIOS自检,到加载内核,到加载驱动,到加载运行级别,一系列的启动过程,完成的启动过程。
    (2) 重点理解加载驱动的过程,initramfs文件的功能(内核通过它获取常见的驱动,同时包括SATA硬盘接口的驱动,然后才能进入硬盘,读取真正的根目录)
    (3) 如果启动级别是5,进入的图形界面,那么/etc/rc.d/rc.local这一步执行完之后,还要进行一系列操作,这里主要指的是启动了图形界面的Xserver和图形界面的Xclient程序,依次启动之后才可以启动图形界面。
    (4) 图形界面对服务器来讲用处不大,不建议去使用图形界面。

    4. 补充 /etc/rc.d/rc.sysinit初始化

    /etc/rc.d/rc.sysinit初始化了哪些东西那???

    1. 获得网络环境
    2. 挂载设备
    3. 开机启动画面Plymouth
    4. 判断是否启用SELinux
    5. 显示开机过程中的欢迎画面
    6. 初始化硬件
    7. 用户自定义模块的加载
    8. 配置内核的参数
    9. 设置主机名
    10. 同步存储器
    11. 设备映射器及相关的初始化
    12. 初始化软件磁盘阵列(RAID)
    13. 初始化LVM的文件系统功能
    14. 检验磁盘文件系统(fsck)
    15. 设置磁盘配额(quota)
    16. 重新以可读写模式挂载系统磁盘
    17. 更新quota(非必要)
    18. 启动系统虚拟随机数生成器
    19. 配置机器(非必要)
    20. 清除开机过程当中的临时文件
    21. 创建ICE目录
    22. 启动交换分区(swap)
    23. 将开机信息写入/var/log/dmesg文件中
    展开全文
  • APP启动流程详解

    2018-02-03 18:24:49
    详细的解说了APP的启动过程及其核心代码,为学习Android framework框架提供了很好的学习资料
  • 第一次接触蓝牙,先从蓝牙的开启流程入手吧,借此顺便熟悉一下蓝牙的代码架构。 1、UI /packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothSwitchPreferenceController.java public void onClick...
  • 此前的文章我们学习了init进程、Zygote进程和SyetemServer进程的启动过程,这一篇文章我们就来学习Android系统启动流程的最后一步:Launcher的启动流程,并结合本系列的前三篇文章的内容来讲解Android系统启动流程。...

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

    前言

    此前的文章我们学习了init进程、Zygote进程和SyetemServer进程的启动过程,这一篇文章我们就来学习Android系统启动流程的最后一步:Launcher的启动流程,并结合本系列的前三篇文章的内容来讲解Android系统启动流程。建议读这篇文章前要通读本系列的前三篇文章,否则你可能不会理解我在讲什么。

    1.Launcher概述

    Android系统启动的最后一步是启动一个Home应用程序,这个应用程序用来显示系统中已经安装的应用程序,这个Home应用程序就叫做Launcher。应用程序Launcher在启动过程中会请求PackageManagerService返回系统中已经安装的应用程序的信息,并将这些信息封装成一个快捷图标列表显示在系统屏幕上,这样用户可以通过点击这些快捷图标来启动相应的应用程序。

    2.Launcher启动流程

    SyetemServer进程在启动的过程中会启动PackageManagerService,PackageManagerService启动后会将系统中的应用程序安装完成。在此前已经启动的ActivityManagerService会将Launcher启动起来。
    启动Launcher的入口为ActivityManagerService的systemReady函数,如下所示。
    frameworks/base/services/java/com/android/server/SystemServer.java

     private void startOtherServices() {
     ...
      mActivityManagerService.systemReady(new Runnable() {
                @Override
                public void run() {
                    Slog.i(TAG, "Making services ready");
                    mSystemServiceManager.startBootPhase(
                            SystemService.PHASE_ACTIVITY_MANAGER_READY);
    
    ...
    }
    ...
    }

    在startOtherServices函数中,会调用ActivityManagerService的systemReady函数:
    frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

    public void systemReady(final Runnable goingCallback) {
    ...
    synchronized (this) {
               ...
                mStackSupervisor.resumeFocusedStackTopActivityLocked();
                mUserController.sendUserSwitchBroadcastsLocked(-1, currentUserId);
            }
        }

    systemReady函数中调用了ActivityStackSupervisor的resumeFocusedStackTopActivityLocked函数:
    frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

    boolean resumeFocusedStackTopActivityLocked(
                ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
            if (targetStack != null && isFocusedStack(targetStack)) {
                return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);//1
            }
            final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
            if (r == null || r.state != RESUMED) {
                mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
            }
            return false;
        }

    在注释1处会调用ActivityStack的resumeTopActivityUncheckedLocked函数,ActivityStack对象是用来描述Activity堆栈的,resumeTopActivityUncheckedLocked函数如下所示。
    frameworks/base/services/core/java/com/android/server/am/ActivityStack.java

     boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
            if (mStackSupervisor.inResumeTopActivity) {
                // Don't even start recursing.
                return false;
            }
            boolean result = false;
            try {
                // Protect against recursion.
                mStackSupervisor.inResumeTopActivity = true;
                if (mService.mLockScreenShown == ActivityManagerService.LOCK_SCREEN_LEAVING) {
                    mService.mLockScreenShown = ActivityManagerService.LOCK_SCREEN_HIDDEN;
                    mService.updateSleepIfNeededLocked();
                }
                result = resumeTopActivityInnerLocked(prev, options);//1
            } finally {
                mStackSupervisor.inResumeTopActivity = false;
            }
           return result;
        }

    注释1调用了resumeTopActivityInnerLocked函数:

     private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
       ...
       return isOnHomeDisplay() &&
                            mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, "prevFinished");
       ...                 
    }

    resumeTopActivityInnerLocked函数的代码很长,我们截取我们要分析的关键的一句:调用ActivityStackSupervisor的resumeHomeStackTask函数,代码如下所示。
    frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

    boolean resumeHomeStackTask(int homeStackTaskType, ActivityRecord prev, String reason) {
        ...
        if (r != null && !r.finishing) {
            mService.setFocusedActivityLocked(r, myReason);
            return resumeFocusedStackTopActivityLocked(mHomeStack, prev, null);
        }
        return mService.startHomeActivityLocked(mCurrentUser, myReason);//1
    }

    在注释1处调用了ActivityManagerService的startHomeActivityLocked函数,如下所示。
    frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

       boolean startHomeActivityLocked(int userId, String reason) {
            if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
                    && mTopAction == null) {//1
                return false;
            }
            Intent intent = getHomeIntent();//2
            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.instrumentationClass == null) {//3
                    intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
                    mActivityStarter.startHomeActivityLocked(intent, aInfo, reason);//4
                }
            } else {
                Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
            }
    
            return true;
        }

    注释1处的mFactoryTest代表系统的运行模式,系统的运行模式分为三种,分别是非工厂模式、低级工厂模式和高级工厂模式,mTopAction则用来描述第一个被启动Activity组件的Action,它的值为Intent.ACTION_MAIN。因此注释1的代码意思就是mFactoryTest为FactoryTest.FACTORY_TEST_LOW_LEVEL(低级工厂模式)并且mTopAction=null时,直接返回false。注释2处的getHomeIntent函数如下所示。

    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;
    }

    getHomeIntent函数中创建了Intent,并将mTopAction和mTopData传入。mTopAction的值为Intent.ACTION_MAIN,并且如果系统运行模式不是低级工厂模式则将intent的Category设置为Intent.CATEGORY_HOME。我们再回到ActivityManagerService的startHomeActivityLocked函数,假设系统的运行模式不是低级工厂模式,在注释3处判断符合Action为Intent.ACTION_MAIN,Category为Intent.CATEGORY_HOME的应用程序是否已经启动,如果没启动则调用注释4的方法启动该应用程序。
    这个被启动的应用程序就是Launcher,因为Launcher的Manifest文件中的intent-filter标签匹配了Action为Intent.ACTION_MAIN,Category为Intent.CATEGORY_HOME。Launcher的Manifest文件如下所示。
    packages/apps/Launcher3/AndroidManifest.xml

    <manifest
        xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.android.launcher3">
        <uses-sdk android:targetSdkVersion="23" android:minSdkVersion="16"/>
     ...
     <application
            ...
            <activity
                android:name="com.android.launcher3.Launcher"
                android:launchMode="singleTask"
                android:clearTaskOnLaunch="true"
                android:stateNotNeeded="true"
                android:theme="@style/Theme"
                android:windowSoftInputMode="adjustPan"
                android:screenOrientation="nosensor"
                android:configChanges="keyboard|keyboardHidden|navigation"
                android:resumeWhilePausing="true"
                android:taskAffinity=""
                android:enabled="true">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.HOME" />
                    <category android:name="android.intent.category.DEFAULT" />
                    <category android:name="android.intent.category.MONKEY"/>
                </intent-filter>
            </activity>
    ...
      </application> 
    </manifest>         

    这样,应用程序Launcher就会被启动起来,并执行它的onCreate函数。

    3.Launcher中应用图标显示流程

    Launcher的onCreate函数如下所示。
    packages/apps/Launcher3/src/com/android/launcher3/Launcher.java

          @Override
        protected void onCreate(Bundle savedInstanceState) {
           ...
            LauncherAppState app = LauncherAppState.getInstance();//1
            mDeviceProfile = getResources().getConfiguration().orientation
                    == Configuration.ORIENTATION_LANDSCAPE ?
                    app.getInvariantDeviceProfile().landscapeProfile
                    : app.getInvariantDeviceProfile().portraitProfile;
    
            mSharedPrefs = Utilities.getPrefs(this);
            mIsSafeModeEnabled = getPackageManager().isSafeMode();
            mModel = app.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对象传入,LauncherAppState的setLauncher函数如下所示。
    packages/apps/Launcher3/src/com/android/launcher3/LauncherAppState.java

       LauncherModel setLauncher(Launcher launcher) {
            getLauncherProvider().setLauncherProviderChangeListener(launcher);
            mModel.initialize(launcher);//1
            mAccessibilityDelegate = ((launcher != null) && Utilities.ATLEAST_LOLLIPOP) ?
                new LauncherAccessibilityDelegate(launcher) : null;
            return mModel;
        }

    注释1处会调用LauncherModel的initialize函数:

    public void initialize(Callbacks callbacks) {
        synchronized (mLock) {
            unbindItemInfosAndClearQueuedBindRunnables();
            mCallbacks = new WeakReference<Callbacks>(callbacks);
        }
    }

    在initialize函数中会将Callbacks,也就是传入的Launcher 封装成一个弱引用对象。因此我们得知mCallbacks变量指的就是封装成弱引用对象的Launcher,这个mCallbacks后文会用到它。
    再回到Launcher的onCreate函数,在注释2处调用了LauncherModel的startLoader函数:
    packages/apps/Launcher3/src/com/android/launcher3/LauncherModel.java

    ...
     @Thunk static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");//1
        static {
            sWorkerThread.start();
        }
        @Thunk static final Handler sWorker = new Handler(sWorkerThread.getLooper());//2
    ...
       public void startLoader(int synchronousBindPage, int loadFlags) {s
            InstallShortcutReceiver.enableInstallQueue();
            synchronized (mLock) {
                synchronized (mDeferredBindRunnables) {
                    mDeferredBindRunnables.clear();
                }
                if (mCallbacks != null && mCallbacks.get() != null) {
                    stopLoaderLocked();
                    mLoaderTask = new LoaderTask(mApp.getContext(), loadFlags);//3
                    if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE
                            && mAllAppsLoaded && mWorkspaceLoaded && !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函数,代码如下所示

     private class LoaderTask implements Runnable {
     ...
            public void run() {
                synchronized (mLock) {
                    if (mStopped) {
                        return;
                    }
                    mIsLoaderTaskRunning = true;
                }
                keep_running: {
                    if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");
                    loadAndBindWorkspace();//1
                    if (mStopped) {
                        break keep_running;
                    }
                    waitForIdle();
                    if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");
                    loadAndBindAllApps();//2
                }
                mContext = null;
                synchronized (mLock) {
                    if (mLoaderTask == this) {
                        mLoaderTask = null;
                    }
                    mIsLoaderTaskRunning = false;
                    mHasLoaderCompletedOnce = true;
                }
            }
       ...     
      }      

    Launcher是用工作区的形式来显示系统安装的应用程序的快捷图标,每一个工作区都是来描述一个抽象桌面的,它由n个屏幕组成,每个屏幕又分n个单元格,每个单元格用来显示一个应用程序的快捷图标。注释1处调用loadAndBindWorkspace函数用来加载工作区信息,注释2处的loadAndBindAllApps函数是用来加载系统已经安装的应用程序信息,loadAndBindAllApps函数代码如下所示。

    private void loadAndBindAllApps() {
        if (DEBUG_LOADERS) {
            Log.d(TAG, "loadAndBindAllApps mAllAppsLoaded=" + mAllAppsLoaded);
        }
        if (!mAllAppsLoaded) {
            loadAllApps();//1
            synchronized (LoaderTask.this) {
                if (mStopped) {
                    return;
                }
            }
            updateIconCache();
            synchronized (LoaderTask.this) {
                if (mStopped) {
                    return;
                }
                mAllAppsLoaded = true;
            }
        } else {
            onlyBindAllApps();
        }
    }

    如果系统没有加载已经安装的应用程序信息,则会调用注释1处的loadAllApps函数:

      private void loadAllApps() {
    ...
            mHandler.post(new Runnable() {
                public void run() {
                    final long bindTime = SystemClock.uptimeMillis();
                    final Callbacks callbacks = tryGetCallbacks(oldCallbacks);
                    if (callbacks != null) {
                        callbacks.bindAllApplications(added);//1
                        if (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.java

    public void bindAllApplications(final ArrayList<AppInfo> apps) {
        if (waitUntilResume(mBindAllApplicationsRunnable, true)) {
            mTmpAppsList = apps;
            return;
        }
        if (mAppsView != null) {
            mAppsView.setApps(apps);//1
        }
        if (mLauncherCallbacks != null) {
            mLauncherCallbacks.bindAllApplications(apps);
        }
    }

    在注释1处会调用AllAppsContainerView的setApps函数,并将包含应用信息的列表apps传进去,AllAppsContainerView的setApps函数如下所示。
    packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsContainerView.java

      public void setApps(List<AppInfo> apps) {
            mApps.setApps(apps);
        }

    包含应用信息的列表apps已经传给了AllAppsContainerView,查看AllAppsContainerView的onFinishInflate函数:

     @Override
        protected void onFinishInflate() {
            super.onFinishInflate();
    ...
            // Load the all apps recycler view
            mAppsRecyclerView = (AllAppsRecyclerView) findViewById(R.id.apps_list_view);//1
            mAppsRecyclerView.setApps(mApps);//2
            mAppsRecyclerView.setLayoutManager(mLayoutManager);
            mAppsRecyclerView.setAdapter(mAdapter);//3
            mAppsRecyclerView.setHasFixedSize(true);
            mAppsRecyclerView.addOnScrollListener(mElevationController);
            mAppsRecyclerView.setElevationController(mElevationController);
    ...
        }

    onFinishInflate函数在加载完xml文件时就会调用,在注释1处得到AllAppsRecyclerView用来显示App列表,并在注释2处将apps的信息列表传进去,并在注释3处为AllAppsRecyclerView设置Adapter。这样应用程序快捷图标的列表就会显示在屏幕上。
    到这里Launcher启动流程就讲到这,接下来讲Android系统启动流程。

    4.Android系统启动流程

    那么结合本篇以及本系列的前三篇文章,我们就可以得出Android系统启动流程,如下所示。
    1.启动电源以及系统启动
    当电源按下时引导芯片代码开始从预定义的地方(固化在ROM)开始执行。加载引导程序Bootloader到RAM,然后执行。
    2.引导程序BootLoader
    引导程序BootLoader是在Android操作系统开始运行前的一个小程序,它的主要作用是把系统OS拉起来并运行。
    3.Linux内核启动
    内核启动时,设置缓存、被保护存储器、计划列表、加载驱动。当内核完成系统设置,它首先在系统文件中寻找init.rc文件,并启动init进程。
    4.init进程启动
    初始化和启动属性服务,并且启动Zygote进程。
    5.Zygote进程启动
    创建JavaVM并为JavaVM注册JNI,创建服务端Socket,启动SystemServer进程。
    6.SystemServer进程启动
    启动Binder线程池和SystemServiceManager,并且启动各种系统服务。
    7.Launcher启动
    被SystemServer进程启动的ActivityManagerService会启动Launcher,Launcher启动后会将已安装应用的快捷图标显示到界面上。

    结合上面的流程,给出Android系统启动流程图:
    这里写图片描述


    欢迎关注我的微信公众号,第一时间获得博客更新提醒,以及更多成体系的Android相关原创技术干货。
    扫一扫下方二维码或者长按识别二维码,即可关注。

    展开全文
  • Android系统启动流程(1) ——解析init进程启动过程 Android系统启动流程(2) ——解析Zygote进程启动过程 Android系统启动流程(3) ——解析SystemServer进程启动过程 Launcher启动过程 此前已经学习了 Android ...
     
    
           此前已经学习了 Android 系统启动流程的 i n it 进程、 Zygote 进程和 SystemServer 进程, 最后我们来学习 La unch er 的启动过程。这篇文章主要分析Android8.1系统的Launcher的启动流程。

        1 Launcher 概述

           系统启动的最后一步是启动一个应用程序用来显示系统中已经安装的应用程序,也就是我们手机看到的桌面,这个应用程序就叫作 Launcher。Launcher 在启动过程中会请求 PackageManagerService 返回系统中已经安装的应用程序的信息,并将这些信息封装成一个快捷图标列表显示在系统屏幕上, 这样用户可以通过点击这些快捷图标来启动相应的应用程序。

           通俗来讲 Launcher 就是 Android 系统的桌面,它的作用主要有以下两点:

           (1 )作为 Android 系统的启动器,用于启动应用程序
           (2 )作为 Android 系统的桌面,用于显示和管理应用程序的快捷图标或者其他桌面组件。
     

        2 Launcher 启动过程介绍

           SystemServer 进程在启动的过程中会启动ActivityManagerServer、PackageManagerService服务, PackageManagerService启动之后会将系统中的应用程序安装完成。AMS(ActivityManagerServer) 会将 Launcher 启动起来。

           启动Launcher的入口为AMS的sytemReady方法,它在SystemServer的startOtherServices方法中被调用,代码如下所示:

    frameworks/base/services/java/com/android/server/SystemServer.java

     private void startOtherServices() {
    
      mActivityManagerService.systemReady(() -> {
                Slog.i(TAG, "Making services ready");
                traceBeginAndSlog("StartActivityManagerReadyPhase");
                mSystemServiceManager.startBootPhase(
                        SystemService.PHASE_ACTIVITY_MANAGER_READY);
    
                ...           
    
            }, BOOT_TIMINGS_TRACE_LOG);
     }

             在Android8.0开始在源码中引入了Java Lambda表达式,接下来分析AMS的systemReady方法做了什么,代码如下:

    frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
      public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
            ...
    
            synchronized (this) {  
    
                ...
    
                startHomeActivityLocked(currentUserId, "systemReady"); // ... 1
               
                ...
    
                mStackSupervisor.resumeFocusedStackTopActivityLocked();// ... 2
                mUserController.sendUserSwitchBroadcastsLocked(-1, currentUserId);
            }
        }

        特别注意!!!

     
            在网络上有很多博客中基于Android7.0以及更高系统版本分析Launcher启动过程时,说是在ActivityManagerService的systemReady方法中使用的是注释1处的代码调用startHomeActivityLocked方法启动Launcher的,这种说法是错误的。其实是注释2处的代码通过一系列的调用最后还是调用到AMS的startHomeActivityLocked方法启动Launcher的。
     
            为了验证这个结果,我们来修改Android8.1的AMS代码,然后编译系统,查看Log日志,对AMS修改如下:
     
        frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java 
        boolean startHomeActivityLocked(int userId, String reason) {
            
            Slog.wtf("ActivityManagerService", "reason = " + reason +
                    " ;  mFactoryTest =" + mFactoryTest
                    + " ; mTopAction = " + mTopAction
                    + " ; userId = " + userId); // ...  1
    
            if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
                    && mTopAction == null) {
                // We are running in factory test mode, but unable to find
                // the factory test app, so just sit around displaying the
                // error message and don't try to start anything.
                return false;
            }
            Intent intent = getHomeIntent();
            ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
            Slog.wtf("ActivityManagerService", "reason = " + reason
                    + " ; aInfo = " + aInfo); // ... 2
            if (aInfo != null) {
                intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
                Slog.wtf("ActivityManagerService", "reason = " + reason
                        + " ; aInfo.applicationInfo.packageName = " + aInfo.applicationInfo.packageName); // ... 3
                // 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);
                }
            } else {
                Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
            }
    
            return true;
        }
           我们在AMS的 startHomeActivityLocked方法中增加了注释1 、2 、3 处的打印log日志的代码,然后再编译系统(不会编译系统的请自行百度研究,这里就不做讲解),启动模拟器查看日志输出,我们通过日志分析工具查看到如下log日志信息:

            在AMS的systemReady方法中,注释1处调用startHomeActivityLocked方法是传入的reason参数的值是“systemReady”,在Log日志中我们发现reason为“systemReady”时,所启动的并不是我们的Launcher程序,而是Settings程序的FallbackHome这Activity。注释2处代码通过一系列调用之后最终调用到startHomeActivityLocked方法是传入的reason参数的值是 “noMoreActivities resumeHomeStackTask” (这个值我们后面具体分析是怎么传入的)时,在Log日志中我们发现reason为“noMoreActivities resumeHomeStackTask”时,所启动的才是我们的Launcher程序。
     
           由此可以证明我们所说的结果是正确的。
     
           那么为什么AMS的systemReady方法中在注释1处要调用 startHomeActivityLocked方法启动Setting程序的FallbackHome呢?
     
           其实是Android 7.0引入了Direct Boot模式,当手机已经通电开机但是用户并有解锁锁屏的时候,Android 7.0以后系统会运行于一个安全的模式,也就是Dierect Boot模式。
     

           Direct Boot模式下,仅限于运行一些关键的、紧急的APP,比如:

    • Apps that have scheduled noti cations, such as alarm clock apps.
    • Apps that provide important user noti cations, like SMS apps.
    • Apps that provide accessibility services, like Talkback.

           在Android 7.0以后,在启动Launcher之前会先启动一个FallbackHome;  FallbackHome是Settings里的一个activity,Settings的android:directBootAware为true,而且FallbackHome在category中配置了Home属性;而Launcher的android:directBootAware为false,所以在DirectBoot模式下,只有FallbackHome可以启动。即先启动com.android.tv.settings/.FallbackHome(或者是com.android.settings/.FallbackHome ) ,待用户解锁后再启动com.android.launcher3/.Launcher。想更深入了解Direct Boot模式和FallbackHome所做的工作的同学可以去阅读源码研究,这里就不做深入说明,下面我们继续分享Lancher的启动过程。

     
           再回到 ActivityManagerService的 systernReady方法,在注释2处调用了 ActivityStackSupervisor的 resumeFocusedStackTopActivityLocked 方法,代码如下:
     
    frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
        boolean resumeFocusedStackTopActivityLocked() {
            return resumeFocusedStackTopActivityLocked(null, null, null);
        }
    
        boolean resumeFocusedStackTopActivityLocked(
                ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
    
            if (!readyToResume()) {
                return false;
            }
    
            if (targetStack != null && isFocusedStack(targetStack)) {
                return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions); // ... 1
            }
    
            final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
            if (r == null || r.state != RESUMED) {
                mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
            } else if (r.state == RESUMED) {
                // Kick off any lingering app transitions form the MoveTaskToFront operation.
                mFocusedStack.executeAppTransition(targetOptions);
            }
    
            return false;
        }
           在注释1 处调用 ActivityStack的 resumeTopActivityUncheckedLocked方法 ActivityStack 对象是用来描述 Activity 堆栈 的, resumeTopActivityUncheckedLocked 方法如下所示:
     
    frameworks/base/services/core/java/com/android/server/am/ActivityStack.java.java
        boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
            if (mStackSupervisor.inResumeTopActivity) {
                // Don't even start recursing.
                return false;
            }
    
            boolean result = false;
            try {
                // Protect against recursion.
                mStackSupervisor.inResumeTopActivity = true;
                result = resumeTopActivityInnerLocked(prev, options); // ... 1
            } finally {
                mStackSupervisor.inResumeTopActivity = false;
            }
    
            // When resuming the top activity, it may be necessary to pause the top activity (for
            // example, returning to the lock screen. We suppress the normal pause logic in
            // {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the end.
            // We call the {@link ActivityStackSupervisor#checkReadyForSleepLocked} again here to ensure
            // any necessary pause logic occurs. In the case where the Activity will be shown regardless
            // of the lock screen, the call to {@link ActivityStackSupervisor#checkReadyForSleepLocked}
            // is skipped.
            final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
            if (next == null || !next.canTurnScreenOn()) {
                checkReadyForSleep();
            }
    
            return result;
        }
    
           在注释1调 用了 resume TopActivitylnnerLocked 方法,代码如下所示:
     
    frameworks/base/services/core/java/com/android/server/am/ActivityStack.java
    
        private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
           
            ...
            if (!hasRunningActivity) {
                // There are no activities left in the stack, let's look somewhere else.
                return resumeTopActivityInNextFocusableStack(prev, options, "noMoreActivities");  // ... 1
            }
    
                
            ...
        }
    
           resumeTopActivitylnnerLocked 方法的 代码很长,这里 截取我 们要分析的关键的部分,注释1处调用resumeTopActivityInNextFocusableStack方法并且传入的reason参数为"noMoreActivities",代码如下:
     
    frameworks/base/services/core/java/com/android/server/am/ActivityStack.java
        private boolean resumeTopActivityInNextFocusableStack(ActivityRecord prev,
                ActivityOptions options, String reason) {
            
            ...
            return isOnHomeDisplay() &&
                    mStackSupervisor.resumeHomeStackTask(prev, reason); // ... 1
        }

           在注释1处调用 ActivityStackSupervisor 的resumeHomeStackTask 方法并且传入的reason参数就是"noMoreActivities",代码如下所示:

    frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
    
        boolean resumeHomeStackTask(ActivityRecord prev, String reason) {
             
            ...
    
            // reason 的值为noMoreActivities
            final String myReason = reason + " resumeHomeStackTask"; // ... 1
    
            // Only resume home activity if isn't finishing.
            if (r != null && !r.finishing) {
                moveFocusableActivityStackToFrontLocked(r, myReason);
                return resumeFocusedStackTopActivityLocked(mHomeStack, prev, null);
            }
            return mService.startHomeActivityLocked(mCurrentUser, myReason); // ... 2
        }
    
           在注释1处myReason的值被赋值为" noMoreActivities resumeHomeStackTask ",在注释2处mService就是ActivityManagerService,因此 调用了 AMS的 startHomeAc tivityLocke方法并将传入reason参数的值为myReason的值(验证上面Log日志输出的reason值) ,如下所示:
     
    frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
        boolean startHomeActivityLocked(int userId, String reason) {
            // 判断工厂模式和mTopAction的值
            if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
                    && mTopAction == null) { // ... 1
                // We are running in factory test mode, but unable to find
                // the factory test app, so just sit around displaying the
                // error message and don't try to start anything.
                return false;
            }
    
            // 创建Launcher启动所需的Intent
            Intent intent = getHomeIntent(); // ... 2
            ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId); // ... 3
            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.instr == null) { // ... 4
                    intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
                    final int resolvedUserId = UserHandle.getUserId(aInfo.applicationInfo.uid);
                    // For ANR debugging to verify if the user activity is the one that actually
                    // launched.
                    final String myReason = reason + ":" + userId + ":" + resolvedUserId;
                    mActivityStarter.startHomeActivityLocked(intent, aInfo, myReason); // ... 5
                }
            } else {
                Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
            }
    
            return true;
        }
           注释1处的 mFactoryTest 代表系统的运行模式,系统的运行模式分为三 种,分别是非工厂模式、低级工厂模式和高级工厂模式, mTopAction 则用来描述第一 个被启动 Activity 组件的 Action ,它的默认值为 Intent.ACTION_ MAIN , 因此注释1 处的代码的意思就是 mFactoryTest为FactoryTest.FACTORY _TEST LOW_LEVEL (低级工厂模式)并且 mTopAction 等于 null 时,直接返回 false 。 注释2 处的 getHomelntent 方法如下所示:
     
    frameworks/base/services/core/java/com/android/server/am/ActivityManageService.java
        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;
        }
            在getHomelntent 方法 中创建了 Intent ,并将 mTopAction和 mTopData 传入。 mTopAction 的值为 Intent.ACTION_ MAIN ,并且如果系统运行模式不是低级工厂模式,则将 intent的 Category 设置为 Intent.CATEGORY HOME 后返回 Intent 。
     
           再回到 AMS的startHomeActivityLocked 方法,在注释3处通过resolveActivityInfo方法解析处ActivityInfo信息,代码如下:
    frameworks/base/services/core/java/com/android/server/am/ActivityManageService.jav
        private ActivityInfo resolveActivityInfo(Intent intent, int flags, int userId) {
            ActivityInfo ai = null;
            ComponentName comp = intent.getComponent();
            try {
                if (comp != null) {
                    // Factory test.             
                    ai = AppGlobals.getPackageManager().getActivityInfo(comp, flags, userId);
                } else {
                    ResolveInfo info = AppGlobals.getPackageManager().resolveIntent(
                            intent,
                            intent.resolveTypeIfNeeded(mContext.getContentResolver()),
                            flags, userId);
    
                    if (info != null) {
                        ai = info.activityInfo;
                    }
                }
            } catch (RemoteException e) {
                // ignore
            }
    
            return ai;
        }

     

            再回到 AMS的startHomeActivityLocked 方法,假设系统的运行模式不是低级工厂模式,在注释4 处判断符合 Action Intent.ACTION MAIN 、 Category Intent.CATEGORY_ HOME 的应用程序是否已经启动,如 果没 启动则调 用注释4 处的方法启 动该应用程序。  这个被启 动的应用程 序就 Launcher ,因为 Launcher的 AndroidManifest 文 件中的 intent- filter 表情 匹配了 Action 为Intent.ACTION_MAIN, Category为 Intent.CATEGORY _HOME。
     
    Launcher AndroidManifest 文件如下所示:
     
    packages/apps/Launche3/AndroidManifest.xml
    <manifest
        xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.android.launcher3">
        <uses-sdk android:targetSdkVersion="23" android:minSdkVersion="21"/>
        ...
    
        <application
            android:backupAgent="com.android.launcher3.LauncherBackupAgent"
            android:fullBackupOnly="true"
            android:fullBackupContent="@xml/backupscheme"
            android:hardwareAccelerated="true"
            android:icon="@drawable/ic_launcher_home"
            android:label="@string/derived_app_name"
            android:theme="@style/LauncherTheme"
            android:largeHeap="@bool/config_largeHeap"
            android:restoreAnyVersion="true"
            android:supportsRtl="true" >
    
            <!--
            Main launcher activity. When extending only change the name, and keep all the
            attributes and intent filters the same
            -->
            <activity
                android:name="com.android.launcher3.Launcher"
                android:launchMode="singleTask"
                android:clearTaskOnLaunch="true"
                android:stateNotNeeded="true"
                android:windowSoftInputMode="adjustPan"
                android:screenOrientation="nosensor"
                android:configChanges="keyboard|keyboardHidden|navigation"
                android:resizeableActivity="true"
                android:resumeWhilePausing="true"
                android:taskAffinity=""
                android:enabled="true">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.HOME" />
                    <category android:name="android.intent.category.DEFAULT" />
                    <category android:name="android.intent.category.MONKEY"/>
                    <category android:name="android.intent.category.LAUNCHER_APP" />
                </intent-filter>
            </activity>      
           ...
    
        </application>
    </manifest>
    

           可以看到intent-filter设置了<category android:name="android.intent.category.HOME" /> 属性,这样名称为com.android.launcher3.Launcher的Activity 就成为了主 Activity。 从前面 AMS的startHomeActivityLocked方法的注释5处,我们知如 Launcher 没有启动就会调用ActivityStarter的startHomeActivityLocked 方法来启动Launcher ,如下所示:

    frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java

        void startHomeActivityLocked(Intent intent, ActivityInfo aInfo, String reason) {
            // 将Launcher放入HomeStack中
            mSupervisor.moveHomeStackTaskToTop(reason); // ... 1
            mLastHomeActivityStartResult = startActivityLocked(null /*caller*/, intent,
                    null /*ephemeralIntent*/, null /*resolvedType*/, aInfo, null /*rInfo*/,
                    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*/, mLastHomeActivityStartRecord /*outActivity*/,
                    null /*inTask*/, "startHomeActivity: " + reason); // ... 2
            if (mSupervisor.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.
                mSupervisor.scheduleResumeTopActivities();
            }
        }

           在注释1处将 Launcher放入HomeStack 中,HomeStack 是在 ActivityStackSupervisor 中定义的用于存储Launcher的变量 。接着调用注释2处的startActivityLocked方法来启动Launcher, 剩余的过程会和普通Activity 启动过程类似,后面会出Activity启动过程相关文章,这里就先不做讲解。最终进Launcher的onCreate 方注中,到这里 Launcher就启动完成了。

        3 Launcher 中应用图标显示过程

           Launcher 完成启动后会做很多的工作,作为桌面它会显示应用程序图标, 这与应用程序开发有所关联,应用程序图标是用户进入应用程的入口,因此我们有必要了解 Launcher 是如何显示应用程序图标的。

           我们先从 Launcher的 on Create 方法入手,代码如下所:
     
    packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
      @Override
        protected void onCreate(Bundle savedInstanceState) {
           
            ...
           
            LauncherAppState app = LauncherAppState.getInstance(this); // ... 1
    
            // Load configuration-specific DeviceProfile
            mDeviceProfile = app.getInvariantDeviceProfile().getDeviceProfile(this);
            if (isInMultiWindowModeCompat()) {
                Display display = getWindowManager().getDefaultDisplay();
                Point mwSize = new Point();
                display.getSize(mwSize);
                mDeviceProfile = mDeviceProfile.getMultiWindowProfile(this, mwSize);
            }
    
            mOrientation = getResources().getConfiguration().orientation;
            mSharedPrefs = Utilities.getPrefs(this);
            mIsSafeModeEnabled = getPackageManager().isSafeMode();
    
            mModel = app.setLauncher(this); // ...2
    
            ...
    
            if (!mModel.startLoader(currentScreen)) { // ... 3 
                // If we are not binding synchronously, show a fade in animation when
                // the first page bind completes.
                mDragLayer.setAlpha(0);
            } else {
                // Pages bound synchronously.
                mWorkspace.setCurrentPage(currentScreen);
    
                setWorkspaceLoading(true);
            }
    
            ...
    
        }
    
     
          在注释1处获取 La uncherAppState 的实 例, 在注释2 处调用它 setLauncher方法并将 Launcher对象传入 LauncherAppState 的 setLauncher 方法如下所示:
     
    packages/apps/Launcher3/src/com/android/launcher3/LauncherAppState.java
        LauncherModel setLauncher(Launcher launcher) {
            getLocalProvider(mContext).setLauncherProviderChangeListener(launcher);
            mModel.initialize(launcher); // ... 1
            return mModel;
        }
    
           在注释1 处会调用 Launch erModel的 initialize 方法,代码如下
     
    packages/apps/Launcher3/src/com/android/launche3/LauncherModel.java
        public void initialize(Callbacks callbacks) {
            synchronized (mLock) {
                Preconditions.assertUIThread();
                mCallbacks = new WeakReference<>(callbacks);
            }
        }
           在initialize方 法中会将 Ca llbacks 也就是传人的 Launch er ,封装成一个弱 引用对 象。 因此  mCallbacks 变量指的就是封装成弱引用对象的 Launc her ,这个 mCallbacks 后面会用到它。
     
           再回到 Launcher的 on Create 方法 ,在注释3处调 用了 Launcher Model的 startLoader方 法,代码如下所示:
     
    packages/apps/Launcher3/src/com/android/launche3/LauncherModel.java
        ...   
    
        // 创建了具有消息循环的线程HandlerThread对象
        @Thunk static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader"); // ... 1
        static {
            sWorkerThread.start();
        }
        @Thunk static final Handler sWorker = new Handler(sWorkerThread.getLooper()); // ... 2
    
         ...
    
         public boolean startLoader(int synchronousBindPage) {
            // Enable queue before starting loader. It will get disabled in Launcher#finishBindingItems
            InstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_LOADER_RUNNING);
            synchronized (mLock) {
                // Don't bother to start the thread if we know it's not going to do anything
                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);  // ... 3
                    if (mModelLoaded && !mIsLoaderTaskRunning) {
                        // Divide the set of loaded items into those that we are binding synchronously,
                        // and everything else that is to be bound normally (asynchronously).
                        loaderResults.bindWorkspace();
                        // For now, continue posting the binding of AllApps as there are other
                        // issues that arise from that.
                        loaderResults.bindAllApps();
                        loaderResults.bindDeepShortcuts();
                        loaderResults.bindWidgets();
                        return true;
                    } else {
                        startLoaderForResults(loaderResults); // ... 4
                    }
                }
            }
            return false;
        }
           在注释1 处创建了具有消息循环的线程 HandlerThread 象。在注释2 处创建了 Handler 并且传入 Hand lerThr ead Looper ,这里 Hander 的作用就是向 HandlerThread 发送消息。 在注释3处创建LoaderResults类的对象loaderResults,并传入mCallbacks,
    在注释4处调用startLoaderForResults方法并传入刚才创建的loaderResults的对象,代码如下所示:
     
    packages/apps/Launcher3/src/com/android/launche3/LauncherModel.java
        public void startLoaderForResults(LoaderResults results) {
            synchronized (mLock) {
                stopLoader();
                mLoaderTask = new LoaderTask(mApp, mBgAllAppsList, sBgDataModel, results); // ... 1
                runOnWorkerThread(mLoaderTask); // ... 2
            }
        }

           在注释1处创建LoaderTask的对象mLoaderTask并将LoaderResult对象传入构造器,后面会用到这个LoaderResult的对象,在注释2处调用runOnWorkerThread方法,代码如下:

    packages/apps/Launcher3/src/com/android/launche3/LauncherModel.java

        private static void runOnWorkerThread(Runnable r) {
            if (sWorkerThread.getThreadId() == Process.myTid()) {
                r.run(); // 如果当前线程是工作线程,直接执行run方法
            } else {
                // If we are not on the worker thread, then post to the worker handler
                // 如果当前线程不是工作现在,那么post到工作线程处理。
                sWorker.post(r); 
            }
        }

           LoaderTask类实现了Runnable接口,当LoaderTask所描述的消息被处理时,则会调用它的run方法,LoaderTask的run方法代码如下所示:

    packages/apps/Launcher3/src/com/android/launche3/model/LoaderTask.java

        public void run() {
            synchronized (this) {
                // Skip fast if we are already stopped.
                if (mStopped) {
                    return;
                }
            }
    
            try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
                long now = 0;
                if (DEBUG_LOADERS) Log.d(TAG, "step 1.1: loading workspace");
                // 加载工作区信息
                loadWorkspace(); // ... 1
    
                verifyNotStopped();
                if (DEBUG_LOADERS) Log.d(TAG, "step 1.2: bind workspace workspace");
    
                // 绑定工作区信息
                mResults.bindWorkspace(); // ... 2
    
                // Take a break
                if (DEBUG_LOADERS) {
                    Log.d(TAG, "step 1 completed, wait for idle");
                    now = SystemClock.uptimeMillis();
                }
                waitForIdle();
                if (DEBUG_LOADERS) Log.d(TAG, "Waited " + (SystemClock.uptimeMillis() - now) + "ms");
                verifyNotStopped();
    
                // second step
                if (DEBUG_LOADERS) Log.d(TAG, "step 2.1: loading all apps");
    
                // 加载系统已经安装的应用程序信息
                loadAllApps(); // ... 3
    
                if (DEBUG_LOADERS) Log.d(TAG, "step 2.2: Binding all apps");
                verifyNotStopped();
    
                // 绑定Appinfo
                mResults.bindAllApps(); // ... 4
                
                ...
    
            } catch (CancellationException e) {
                // Loader stopped, ignore
                if (DEBUG_LOADERS) {
                    Log.d(TAG, "Loader cancelled", e);
                }
            }
        }
           Launcher是用 工作区的形式来显示系统安装的应用程序的快捷图标的,每一 个工作区都是用来描述一个抽 象桌 面的,它由n个 屏幕 组成, 每个 屏幕又分n 个单元格,每个单元格用来显示一 个应用程序 的快捷图 标。 在注释1处和注释2 处分别调用 load Workspa ce
    方法和 bindWorksp ace方法 来加 载和绑定工作区信息 。注释3 处的 l oadA llApp方法 用来加载系统已经安装的应用程序信息,代码如下:
     
    packages/apps/Launcher3/src/com/android/launche3/model/LoaderTask.java
        private void loadAllApps() {
           
            ...
    
            // Clear the list of apps
            mBgAllAppsList.clear();
            for (UserHandle user : profiles) {
                
                ...
    
                final List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null, user);
                ...
      
                for (int i = 0; i < apps.size(); i++) {
                    LauncherActivityInfo app = apps.get(i);
                    // This builds the icon bitmaps.
                    mBgAllAppsList.add(new AppInfo(app, user, quietMode), app); // ... 1
                }
    
                ManagedProfileHeuristic.onAllAppsLoaded(mApp.getContext(), apps, user);
            }
    
            ... 
        }

           在注释1处创建AppInfo信息并添加到mBgAllAppsList列表中。

           在回到LoaderTask的run方法,在注释4处的mResult就是构造LoaderTask时传入的LoaderResult对象,调用LoaderResult的bindAllApps方法绑定App信息,代码如下:

    packages/apps/Launcher3/src/com/android/launche3/model/LoaderResult.java

     public void bindAllApps() {
            // shallow copy
            // 将mBgAllAppList中的data属性克隆一份
            @SuppressWarnings("unchecked")
            final ArrayList<AppInfo> list = (ArrayList<AppInfo>) mBgAllAppsList.data.clone();
    
            Runnable r = new Runnable() {
                public void run() {
                    Callbacks callbacks = mCallbacks.get();
                    if (callbacks != null) {
                        // 这里的callbacks就是Launcher的对象
                        callbacks.bindAllApplications(list); // ... 1
                    }
                }
            };
            mUiExecutor.execute(r);
        }

           在注释1处调用callbacks的bindAllApplications方法实质上就是调用Launcher的bindAllApplications方法,接下里分析Launcher中的bindAllApplications方法,代码如下:

     packages/apps/Launcher3/src/com/android/launcher3/Launcher.java

     public void bindAllApplications(final ArrayList<AppInfo> apps) {
    
            ...
    
            if (mAppsView != null) {
                Executor pendingExecutor = getPendingExecutor();
                if (pendingExecutor != null && mState != State.APPS) {
                    // Wait until the fade in animation has finished before setting all apps list.
                    pendingExecutor.execute(r);
                    return;
                }
    
                mAppsView.setApps(apps); // ... 1
            }
           
            ...
        }
          在注释1处调 AllA pps Conta ine rView 类型的 mApps View的 setApp方法 ,并将包含应用信息的 列表 a pps传 进去, AllA pps Conta ine rView 的setApps方法如 下所示:
     
    packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsContainerView.java
        public void setApps(List<AppInfo> apps) {
            mApps.setApps(apps);
        }
           se tApps方法会将包 含应用 信息 的列表a pps设置给 mApps ,这个 mApps是 AlphabeticalAppsList  类型 。接 着查 AllAppsContainerView的onFinishInflate 方法,代码如下 所示:
        @Override
        protected void onFinishInflate() {
            super.onFinishInflate();
           
            ...
    
            mAppsRecyclerView = findViewById(R.id.apps_list_view); // ... 1
            mAppsRecyclerView.setApps(mApps); // ... 2
            mAppsRecyclerView.setLayoutManager(mLayoutManager);
            mAppsRecyclerView.setAdapter(mAdapter); //  ... 3
           
            ...
        }
    
           onFinishInflate方法会在AllAppsContainerView加 载完 X ML 时调用, 在 注释1处得到AllApps RecyclerV iew (RecycleView的子类)用 来显示 a pp 列 表,并在注释2 处将此前的 mApps设置进去, 在注释3处为 All AppsRecycler View 设置 Adapter 。这样应用程序快捷图标就会显示在屏幕上。
     
           到这里 Launcher 中应用图标显示过程以及 Launcher 启动流程就讲解完了,接下来介绍Android 系统启动流程。

     

     Android 系统启动流程

         1.启动电源以及系统启动

           当电源按下时引导芯片代码从预定义的地方(固化在 ROM )开始执行。加载引导程序 BootLoader到RAM ,然后执行。

         2. 引导程序 Bootloader

           引导程序 BootLoader 是在 Android 操作系统开始运行前的一 个小程序,它的主要作用是把操作系统 拉起来并运行。

         3. Linux 内核启动

           当内核启动时  ,设置缓存、被保护存储器、计划列表、加载驱动。当内核完成系统设置时,它首先在系统文件中寻找 init.rc 文件,并启动 init 进程。

         4. init 进程启动

           初始化和启动属性服务,并且启动 Zygote 进程。

         5. Zygote 进程启动

           创建Java 虚拟机并为 Java 虚拟机注册 JNI 方法 ,创建服务器端 Socket ,启动SystemServer 进程。

         6. System Server 进程启动

           启动 Binder 线 程池和 SystemServiceManager ,并且启动各种系统服务。

         7. Launcher 启动

           SystemServer 进程启动的 AMS 会启动 Launcher, Launcher 启动 后会将己安装应用的快捷图标显示到界面上。

     

    展开全文
  • Activity启动过程

    2017-06-20 23:42:42
    Activity启动过程
  • 二、Android 应用进程启动过程 三、 Android Activity的启动流程 一、Android APK的构建过程 通过IDE可以生成可以在android设备中安装的apk文件,Google官方提供的构建APK的过程流程图如下: 打包APK流程总结...

    目录

    一、Android APK的构建过程

    二、Android 应用进程启动过程

    三、 Android Activity的启动流程


    一、Android APK的构建过程

    通过IDE可以生成可以在android设备中安装的apk文件,Google官方提供的构建APK的过程流程图如下:

    • 打包APK流程总结如下:
    1. AAPT(Android Asset Packaging Tool)工具会打包应用中的资源文件,如AndroidManifest.xml、layout布局中的xml等,并将xml文件编译为二进制形式,当然assets文件夹中的文件不会被编译,图片及raw文件夹中的资源也会保持原来的形态,需要注意的是raw文件夹中的资源也会生成资源id。AAPT编译完成之后会生成R.java文件。
    2. AIDL工具会将所有的aidl接口转化为java接口。
    3. 所有的java代码,包括R.java与aidl文件都会被Java编译器编译成.class文件。
    4. Dex工具会将上述产生的.class文件及第三库及其他.class文件编译成.dex文件(dex文件是Dalvik虚拟机可以执行的格式),dex文件最终会被打包进APK文件。
    5. ApkBuilder工具会将编译过的资源及未编译过的资源(如图片等)以及.dex文件打包成APK文件。
    6. 生成APK文件后,需要对其签名才可安装到设备,平时测试时会使用debug keystore,当正式发布应用时必须使用release版的keystore对应用进行签名。
    7. 如果对APK正式签名,还需要使用zipalign工具对APK进行对齐操作,这样做的好处是当应用运行时会提高速度,但是相应的会增加内存的开销。

     

    我们知道,通过Intent就可以执行APK安装的,执行如下代码后,我们就会打开安装apk文件的程序并执行安装逻辑了,大家应该都知道这段代码执行的结果是打开一个隐式的Activity,即PackageInstallerActivity。

    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    intent.setDataAndType(Uri.parse("file://" + path),"application/vnd.android.package-archive");
    context.startActivity(intent);
    • 安装APK流程总结如下:
    1. 代码中执行intent.setDataAndType(Uri.parse(“file://” + path),”application/vnd.android.package-archive”);可以打开隐士的PackageInstallerActivity。
    2. PackageInstallerActivity主要用于执行解析apk文件;解析manifest.xml、解析签名等操作。
    3. 点击安装按钮,调起InstallAppProcess,这个Activity主要用于执行安装apk逻辑,用于初始化安装界面,用于初始化用户UI;并调用PackageInstaller执行安装逻辑。
    4. InstallAppProcess内注册有广播,当安装完成之后接收广播,更新UI。显示apk安装完成界面。

     

    二、Android 应用进程启动过程

        首先,Android在系统架构分为四个层面。从高层到低层分别是应用程序层、应用程序框架层、系统运行库层和linux核心层。另外,进程是系统的执行单位。Linux系统是核心底层,那么Android的其他进程都是基于Linux进程的根进程init进程,因此它可以算作是整个android操作系统的第一个进程。最后,我们知道android系统的Zygote进程是所有的android进程的父进程,包括SystemServer和各种应用进程都是通过Zygote进程fork出来的。而Zygote进程则是通过linux系统的init进程启动的,也就是说,android系统中各种进程的启动方式及顺序是:

    init进程 –> Zygote进程 –> SystemServer进程 –>各种应用进程

    各种应用进程:启动自己编写的客户端应用时,一般都是重新启动一个应用进程,有自己的虚拟机与运行环境;

    init进程在启动Zygote进程时一般都会调用ZygoteInit类的main方法,Zygote进程mian方法主要执行逻辑:

    • 初始化DDMS;

    • 注册Zygote进程的socket通讯;

    • 初始化Zygote中的各种类,资源文件,OpenGL,类库,Text资源等等;

    • 初始化完成之后fork出SystemServer进程;

    • fork出SystemServer进程之后,关闭socket连接;

    其实,SystemServer进程主要的作用是启动各种系统服务,比如ActivityManagerService,PackageManagerService,WindowManagerService等服务。我们平时熟知的各种系统性的服务其实都是在SystemServer进程中启动的,而当我们的应用需要使用各种系统服务的时候,其实也是通过与SystemServer进程通讯获取各种服务对象的句柄来执行相应的操作。

    • SystemServer进程启动服务的启动函数为main函数;

    • SystemServer在执行过程中首先会初始化一些系统变量,加载类库,创建Context对象,创建SystemServiceManager对象等之后才开始启动系统服务;

    • SystemServer进程将系统服务分为三类:boot服务,core服务和other服务,并逐步启动;

    • SystemServer进程在尝试启动服务之前会首先尝试与Zygote建立socket通讯,只有通讯成功之后才会开始尝试启动服务;

    • 创建的系统服务过程中主要通过SystemServiceManager对象来管理,通过调用服务对象的构造方法和onStart方法初始化服务的相关变量;

    • 服务对象都有自己的异步消息对象,并运行在单独的线程中;

    其实,我们知道SystemServer进程主要用于启动系统的各种服务,而且其中就包含负责启动Launcher程序的服务-LauncherAppService。Launcher 程序就是我们平时看到的桌面程序,它其实也是一个android应用程序,只不过这个应用程序是系统默认第一个启动的应用程序,这里我们就简单的分析一下Launcher应用的启动流程。

    前面说SystemServer调用三个内部方法分别启动boot service、core service和other service。在调用startOtherService方法中就会通过调用mActivityManagerService.systemReady()方法。

    public void systemReady(final Runnable goingCallback) {
            ...
            // Start up initial activity.
            mBooting = true;
            startHomeActivityLocked(mCurrentUserId, "systemReady");
            ...
        }

    这个方法体中调用了startHomeActivityLocked方法,看名字就知道开始执行启动homeActivity的操作。好了,既然如此,我们再看一下startHomeActivityLocked的具体实现:

    boolean startHomeActivityLocked(int userId, String reason) {
            if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
                    && mTopAction == null) {
                return false;
            }
            Intent 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.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) {
                intent.addCategory(Intent.CATEGORY_HOME);
            }
            return intent;
        }

    可以发现,Intent是一个隐士对象,并且添加了Intent.CATEGORY_HOME常量,这个其实是一个launcher的标志,一般系统的启动页面Activity都会在androidmanifest.xml中配置这个标志。

    void startHomeActivity(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) {
    
                scheduleResumeTopActivities();
    
            }
        }

    发现其调用的是scheduleResumeTopActivities()方法,这个方法其实是关于Activity的启动流程的逻辑的,这逻辑后面会讲。因为我们的Launcher启动的Intent是一个隐士的Intent,所以我们会启动在androidmanifest.xml中配置了相同catogory的activity,androidManifest中配置的这个catogory其实就是LauncherActivity。

    LauncherActivity继承与ListActivity,我们先看一下其Layout布局文件和onCreate方法:

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >
    
        <ListView
            android:id="@android:id/list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            />
    
        <TextView
            android:id="@android:id/empty"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:text="@string/activity_list_empty"
            android:visibility="gone"
            android:textAppearance="?android:attr/textAppearanceMedium"
            />
    
    </FrameLayout>
    @Override
    protected void onCreate(Bundle icicle) {
            super.onCreate(icicle);
    
            mPackageManager = getPackageManager();
            if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
                requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
                setProgressBarIndeterminateVisibility(true);
            }
            onSetContentView();
            mIconResizer = new IconResizer();
    
            mIntent = new Intent(getTargetIntent());
            mIntent.setComponent(null);
            mAdapter = new ActivityAdapter(mIconResizer);
    
            setListAdapter(mAdapter);
            getListView().setTextFilterEnabled(true);
    
            updateAlertTitle();
            updateButtonText();
    
            if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
                setProgressBarIndeterminateVisibility(false);
            }
        }

    可见,手机桌面其实就是一个ListView控件,在onCreate方法中初始化了一个PackageManager,从中查询出系统所有已经安装的应用列表,包括应用包名、图标等信息,然后将这些信息以Adapter方式注入到Listview中将系统应用图标和名称显示出来。 另外,在系统的回调方法onListItemClick中说明了,为什么我们点击某一个应用图标之后就可以启动某一项应用的原因了。

    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
            Intent intent = intentForPosition(position);
            startActivity(intent);
    }
    protected Intent intentForPosition(int position) {
            ActivityAdapter adapter = (ActivityAdapter) mAdapter;
            return adapter.intentForPosition(position);
    }
    public Intent intentForPosition(int position) {
                if (mActivitiesList == null) {
                    return null;
                }
    
                Intent intent = new Intent(mIntent);
                ListItem item = mActivitiesList.get(position);
                intent.setClassName(item.packageName, item.className);
                if (item.extras != null) {
                    intent.putExtras(item.extras);
                }
                return intent;
    }

        所以,LauncherActivity中是以ListView来显示我们的应用图标列表的,并且为每个Item保存了应用的包名和启动Activity类名,这样点击某一项应用图标的时候就可以根据应用包名和启动Activity名称启动我们的App了。

        其实Android中应用进程可以通过许多方式启动,比如启动一个Activity、Service、ContentProvider或BroadcastReceiver,也就是说通过启动四大组件的方式启动,这时候系统会判断当前这些组件所需要的应用进程是否已经启动,若没有的话,则会启动应用进程。通过上面Launcher启动流程,我们知道每一个launcher中的图标对应着一个应用报名和启动activity类名,查看LauncherActivity中的图标点击事件:

    protected void onListItemClick(ListView l, View v, int position, long id) {
            Intent intent = intentForPosition(position);
            startActivity(intent);
    }

    这里调用了startActivity方法传入Intentd对象来启动这个activity。很明显,当前该应用属于冷启动,也就是说我们调用的startActivity方法不单单为我们启动了这个activity,也同时在启动activity之前启动了这个应用进程。好了,那我们这里就以这个方法为入口分析一下应用进程的启动流程。

    @Override
    public void startActivity(Intent intent) {
            this.startActivity(intent, null);
    }

    发现其调用的startActivity的重载方法,传入Intent对象和可为空Bundle对象。 并且发现继续调用startActivityForResult方法。

    @Override
        public void startActivity(Intent intent, @Nullable Bundle options) {
            if (options != null) {
                startActivityForResult(intent, -1, options);
            } else {
                startActivityForResult(intent, -1);
            }
        }

    很明显的此时传递的options为空,继续跟进:

    public void startActivityForResult(Intent intent, int requestCode) {
            startActivityForResult(intent, requestCode, null);
    }

    好吧,最后调用的还是startActivityForResult(intent, requestCode, null)这个重载方法:

    public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
            if (mParent == null) {
                Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(
                        this, mMainThread.getApplicationThread(), mToken, this,intent, requestCode, options);
                if (ar != null) {
                    mMainThread.sendActivityResult(
                        mToken, mEmbeddedID, requestCode, ar.getResultCode(),ar.getResultData());
                }
                if (requestCode >= 0) {
                    mStartedActivity = true;
                }
    
                cancelInputsAndStartExitTransition(options);
           
            } else {
                if (options != null) {
                    mParent.startActivityFromChild(this, intent, requestCode, options);
                } else {
                    mParent.startActivityFromChild(this, intent, requestCode);
                }
            }
        }

    首先注意mInstrumentation.execStartActivity方法。Instrumentation对象,他是Android系统中应用程序端操作Activity的具体操作类,这里的操作是相对于ActivityManagerService服务端来说的。也就是说当我们在执行对Activity的具体操作时,比如回调生命周期的各个方法都是借助于Instrumentation类来实现的。看一下源码:

    public ActivityResult execStartActivity(
                Context who, IBinder contextThread, IBinder token, Activity target,
                Intent intent, int requestCode, Bundle options) {
            ...
            try {
                intent.migrateExtraStreamToClipData();
                intent.prepareToLeaveProcess();
    //关键代码
                int result = ActivityManagerNative.getDefault()
                    .startActivity(whoThread, who.getBasePackageName(), intent,
                            intent.resolveTypeIfNeeded(who.getContentResolver()),
                            token, target != null ? target.mEmbeddedID : null,
                            requestCode, 0, null, options);
                checkStartActivityResult(result, intent);
            } catch (RemoteException e) {
                throw new RuntimeException("Failure from system", e);
            }
            return null;
        }

    关键代码段实际上是进程间通讯。ActivityManagerNative继承于Binder接口,本身就是一个Binder对象,然后上面我们介绍SystemServer进程的时候对ActivityManagerService有过了解,发现其继承于ActivityManagerNative,好吧,了解过Binder机制的知道,ActivityManagerService就是这个Binder机制的服务器端而ActivityManagerNative就是这个Binder机制的客户端。所以我们这里调用的startActivity实际上是将参数传递给ActivityManagerService,并执行ActivityManagerService的startActivity方法。

    既然这样,我们看一下ActivityManagerService的startActivity方法:

    @Override
        public final int startActivity(IApplicationThread caller, String callingPackage,
                Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
                int startFlags, ProfilerInfo profilerInfo, Bundle options) {
            return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
                resultWho, requestCode, startFlags, profilerInfo, options,
                UserHandle.getCallingUserId());
        }

    然后我们继续看一下startActivityAsUser方法:

    @Override
        public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
                Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
                int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
            enforceNotIsolatedCaller("startActivity");
            userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                    false, ALLOW_FULL_ONLY, "startActivity", null);
    
            return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
                    resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                    profilerInfo, null, null, options, false, userId, null, null);
        }

    继续查看startActivityMayWait方法:

    final int startActivityMayWait(IApplicationThread caller, int callingUid,
                String callingPackage, Intent intent, String resolvedType,
                IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
                IBinder resultTo, String resultWho, int requestCode, int startFlags,
                ProfilerInfo profilerInfo, WaitResult outResult, Configuration config,
                Bundle options, boolean ignoreTargetSecurity, int userId,
                IActivityContainer iContainer, TaskRecord inTask) {
            ...
    
                int res = startActivityLocked(caller, intent, resolvedType, aInfo,
                        voiceSession, voiceInteractor, resultTo, resultWho,
                        requestCode, callingPid, callingUid, callingPackage,
                        realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity,
                        componentSpecified, null, container, inTask);
    
                ...
    
                return res;
            }
        }

    这里调用了startActivityLocked方法,也就是说在初始化其他逻辑之后,这个方法会调用startActivityLocked方法,然后我们查看startActivityLocked方法发现其调用了resumeTopActivitiesLocked方法:

    if (doResume) {
                mStackSupervisor.resumeTopActivitiesLocked(this, r, options);
    }

    继续跟进:

    final boolean resumeTopActivityLocked(ActivityRecord prev) {
            return resumeTopActivityLocked(prev, null);
        }

    resumeTopActivityLocked方法中又调用了resumeTopActivityInnerLocked方法,resumeTopActivityInnerLocked方法中又调用了startSpecificActivityLocked方法:

    final ProcessRecord startProcessLocked(String processName,
                ApplicationInfo info, boolean knownToBeDead, int intentFlags,
                String hostingType, ComponentName hostingName, boolean allowWhileBooting,
                boolean isolated, boolean keepIfLarge) {
            return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,
                    hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
                    null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
                    null /* crashHandler */);
        }

    查看startProcessLocked方法的具体实现:

    checkTime(startTime, "startProcess: asking zygote to start proc");
                Process.ProcessStartResult startResult = Process.start(entryPoint,
                        app.processName, uid, uid, gids, debugFlags, mountExternal,
                        app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
                        app.info.dataDir, entryPointArgs);
                checkTime(startTime, "startProcess: returned from zygote!");

    查看关键代码,这里调用了Process.start方法:

    public static final ProcessStartResult start(final String processClass,
                                      final String niceName,
                                      int uid, int gid, int[] gids,
                                      int debugFlags, int mountExternal,
                                      int targetSdkVersion,
                                      String seInfo,
                                      String abi,
                                      String instructionSet,
                                      String appDataDir,
                                      String[] zygoteArgs) {
            try {
                return startViaZygote(processClass, niceName, uid, gid, gids,
                        debugFlags, mountExternal, targetSdkVersion, seInfo,
                        abi, instructionSet, appDataDir, zygoteArgs);
            } catch (ZygoteStartFailedEx ex) {
                Log.e(LOG_TAG,
                        "Starting VM process through Zygote failed");
                throw new RuntimeException(
                        "Starting VM process through Zygote failed", ex);
            }
        }

    最后,这里的processClass就是要启动的进程的名称,这里传递的就是ActivityThread:"android.app.ActivityThread"。具体的Process启动进程的Native层代码这里不做过多的分析,这个方法就是启动了AcitivtyThread进程并执行了ActivityThread的main方法,所以我们经常说的进程的启动方法就是ActivityThread的main方法,就在这里实现的。

     

    三、 Android Activity的启动流程

    • Activity的启动流程一般是通过调用startActivity或者是startActivityForResult来开始的

    • startActivity内部也是通过调用startActivityForResult来启动Activity,只不过传递的requestCode小于0

    • Activity的启动流程涉及到多个进程之间的通讯这里主要是ActivityThread与ActivityManagerService之间的通讯

    • ActivityThread向ActivityManagerService传递进程间消息通过ActivityManagerNative,ActivityManagerService向ActivityThread进程间传递消息通过IApplicationThread。

    • ActivityManagerService接收到应用进程创建Activity的请求之后会执行初始化操作,解析启动模式,保存请求信息等一系列操作。

    • ActivityManagerService保存完请求信息之后会将当前系统栈顶的Activity执行onPause操作,并且IApplication进程间通讯告诉应用程序继承执行当前栈顶的Activity的onPause方法;

    • ActivityThread接收到SystemServer的消息之后会统一交个自身定义的Handler对象处理分发;

    • ActivityThread执行完栈顶的Activity的onPause方法之后会通过ActivityManagerNative执行进程间通讯告诉ActivityManagerService,栈顶Actiity已经执行完成onPause方法,继续执行后续操作;

    • ActivityManagerService会继续执行启动Activity的逻辑,这时候会判断需要启动的Activity所属的应用进程是否已经启动,若没有启动则首先会启动这个Activity的应用程序进程;

    • ActivityManagerService会通过socket与Zygote继承通讯,并告知Zygote进程fork出一个新的应用程序进程,然后执行ActivityThread的mani方法;

    • 在ActivityThead.main方法中执行初始化操作,初始化主线程异步消息,然后通知ActivityManagerService执行进程初始化操作;

    • ActivityManagerService会在执行初始化操作的同时检测当前进程是否有需要创建的Activity对象,若有的话,则执行创建操作;

    • ActivityManagerService将执行创建Activity的通知告知ActivityThread,然后通过反射机制创建出Activity对象,并执行Activity的onCreate方法,onStart方法,onResume方法;

    • ActivityThread执行完成onResume方法之后告知ActivityManagerService onResume执行完成,开始执行栈顶Activity的onStop方法;

    • ActivityManagerService开始执行栈顶的onStop方法并告知ActivityThread;

    • ActivityThread执行真正的onStop方法;

     

     

     

    展开全文
  •  以s3c2410为例Uboot的启动过程大体可分为两个部分,第一部分是初始化系统为第二部分做准备,多用汇编实现,第二部分实现外围设备的初始化和内核的下载及参数的传递,开始用C实现。  下面是uboot启动流程  ...
  • Android应用安装有如下四种方式 1.系统应用安装――开机时完成,没有安装界面 ...4.第三方应用安装――通过SD卡里的APK文件安装,有安装界面,由packageinstaller.apk应用处理安装及卸载过程的界面。
  • 首先,对于一个web应用,其部署在web容器(tomcat)中,web容器提供其一个全局的上下文环境,这个上下文就是ServletContext,其为后面的...spring容器启动流程 定位 在spring中,使用统一的资源表现方式Res...
  • SpringBoot springboot是依赖于spring的,bi'qi
  • Activity启动流程详解(基于api28)

    千次阅读 多人点赞 2020-08-02 16:49:06
    这里涉及到了系统服务进程,启动过程细节很多,这里我只展示主体流程。activity的启动流程随着版本的更替,代码细节一直在进行更改,每次都会有很大的修改,如android5.0 android8.0。我这里的版本是基于android api...
  • 老罗Activity启动过程文章中,时序图比较模糊看不清,自己重新做了一个
  • 新唐NUC977开发板uboot代码解析1-启动流程 新唐NUC977开发板uboot代码解析1-启动流程
  • 主要介绍了springboot中的swagger快速启动流程,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
  • 主要介绍了iOS应用程序的启动过程,讲述了从其执行main函数开始到展示UIWindow的流程中的一些关键点,需要的朋友可以参考下
  • ¶ Tomcat - 启动过程:初始化和启动流程 在有了Tomcat架构设计和源码入口以后,我们便可以开始真正读源码了。@pdai¶ 总体流程 很多人在看框架代码的时候会很难抓住重点的,而一开始了解整体流程会很大程度提升理解...
  • 对NXP iMX8 Boot ROM固化程序开始加载运行SPL程序,到u-boot程序正常运行过程中调用的函数的位置说明。
  • 分析嵌入式系统的启动过程 嵌入式系统的启动过程 上电>u-boot>加载Linux内核>挂载rootfs >执行应用程序 分析u-boot 什么是u-boot是一个通用的bootloader U-Boot全称 Universal Boot Loader是遵循GPL条款的 开放源码...
  • APP启动流程解析

    万次阅读 多人点赞 2019-04-22 10:07:15
    启动流程简介 首先要知道的是,手机屏幕其实就是一个Activity,我们专业点将其称为Launcher,相信做过车载设备开发的朋友肯定不会陌生,Launcher是手机厂商提供的,不同的手机厂商比拼的就是Launcher的设计。当然...
  • Linux系统开机启动过程

    千次阅读 2021-12-17 13:34:53
    Linux系统开机之后从载入内核到进入登入界面。启动一系列的进程。
  • zygote启动流程源码分析, 文件包含zygote systemService activityManager启动homeLauncher. 因为本地文字较长 不方便写blog发布 所以上传一下文档

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,740,399
精华内容 1,096,159
关键字:

启动流程