一篇文章搞定《APP的启动流程》

前言

前面已经铺垫了Binder、Handler、View的绘制流程
那么该来看看APP的启动流程了,是如何启动了我们这些重要的组件
本文会按照步骤和启动需要的成员并附带一点点源码进行讲解。
以了解熟悉启动的流程为主。不会大篇幅的利用源码深入。
本文结构:
1、冷启动、温启动、热启动
2、启动中的重要成员简介
3、启动的步骤详解
4、启动优化(浅谈)

冷启动、温启动、热启动

  • 冷启动:当启动应用时,后台没有该应用的进程,这时系统会重新创建一个新的进程分配给该应用,然后再根据启动的参数,启动对应的进程组件,这个启动方式就是冷启动。
  • 温启动:当启动应用时,后台已有该应用的进程,但是Activity可能因为内存不足被回收。这样系统会从已有的进程中来启动这个Activity,这个启动方式叫温启动。
  • 热启动:当启动应用时,后台已有该应用的进程(例:按back键、home键,应用虽然会退出,但是该应用的进程是依然会保留在后台,可进入任务列表查看),所以在已有进程的情况下,这种启动会从已有的进程中来启动对应的进程组件,这个方式叫热启动。

由于冷启动相对于其他启动方式多了进程的创建(Zygote进程fork创建进程)以及应用的资源加载和初始化(Application的创建及初始化),所以相对来说会比较耗时,所以我们一般说的App启动优化一般指的都是App的冷启动优化。
启动中的重要

启动中的重要成员简介

zygote进程

不说的冠冕堂皇的,就简单的给大家总结两条:

  • zygote进程是由Linux中的init进程,fock出来的进程。
  • 在Android中,所有的应用的进程都是由zygote进程fork出来的,一个新的App进程就是zygote进程的子进程。

Zygote进程首先会fork自己孵化出的SystemServer进程,它的main函数主要负责:

  • 启动binder线程池,这是SystemServer与其他进程通信的基础
  • 初始化Looper
  • 创建了SystemServiceManager对象,它会启动Android中的各种服务。包括AMS、PMS、WMS
  • 启动桌面进程,这样才能让用户见到手机的界面。
  • 开启loop循环,开启消息循环,SystemServer进程一直运行,保障其他应用程序的正常运行。

注意:init进程在开启的时候就创建了,所以在开机的时候我们的zygote进程和ServiceManager都被创建出来了。

Instrumentation

工具类,它用来监控应用程序和系统的交互,包装了 ActivityManagerService 的调用,一些插件化方案就是通过 hook 该类实现的。

SystemServer进程

SystemServer是由zygote进程fork出来的第一个进程,SystemServer和Zygote是Android Framework最重要的2个进程。 系统里面重要的服务都是在这个进程里面开启的,比如ActivityManagerService、PackageManagerService、WindowManagerService。
应用启动流程基本是围绕着ActivityManagerService和ActivityThread展开。

ActivityManagerService

  • 在Android系统中,任何一个Activity的启动都是由AMS和App进程(主要是ActivityThread)相互配合来完成的。
  • 他在SystemServer创建后被初始化
  • App进程与AMS通过Binder机制进行跨进程通信
  • AMS(SystemServer进程)与zygote通过Socket进行跨进程通信。

Binder

Binder就不细说了,Android系统中的IPC跨进程通信。
就是《一篇文章搞定〈Binder〉》中的内容

ActivityThread

ActivityThread 是 Android 系统中驱动应用程序的主线程,它的作用是管理应用程序的生命周期和交互。ActivityThread 负责启动应用程序的入口 Activity,提供与 Android 系统之间的通信桥梁,同时也处理了应用程序的消息队列和事件循环。
在 App 启动过程中,ActivityThread 主要负责以下几个重要的工作:

  • 创建一个主线程 Looper ,用于处理消息队列和事件循环。
  • 加载应用程序的主题、资源和布局文件。
  • 通过调用 Instrumentation 的 callApplicationOnCreate() 方法触发应用程序的生命周期,初始化应用程序,并创建首个 Activity。

启动的步骤详解

图中的红色线条为Binder通信
紫色线条是Socket通信

一、点击桌面图标

  • Launcher 捕获点击事件,调用 Activity#startActivity();
  • 点击图标发生在Launcher应用的进程,startActivity()函数最终是由Instrumentation通过Android的Binder跨进程通信机制 发送消息给 system_server 进程;
    在这里插入图片描述

二、创建进程

在 system_server 中,启动进程的操作会先调用ActivityManagerService#startProcessLocked() 方法,该方法内部调用 Process.start(android.app.ActivityThread);而后通过 socket 通信告知 Zygote 进程 fork 子进程,即 app 进程。
在这里插入图片描述

三、初始化APP进程

  • 开启主线程 app 进程启动后,首先是实例化 ActivityThread,并执行其main()函数
  • main()函数中创建 ApplicationThread,Looper,Handler 对象,并开启主线程消息循环Looper.loop()。
  • 调用 ActivityThread#attach(false)方法进行 Binder 通信

源码如下:ActivityThread.java

public static void main(String[] args) {
···
     Looper.prepareMainLooper();

     ActivityThread thread = new ActivityThread();
     thread.attach(false);

     if (sMainThreadHandler == null) {
         sMainThreadHandler = thread.getHandler();
     }
 ···
     Looper.loop();
 ···
 }


 private void attach(boolean system) {
 ···
     if (!system) {
     ···
         final IActivityManager mgr = ActivityManager.getService();
         try {
             mgr.attachApplication(mAppThread);
         } catch (RemoteException ex) {
             throw ex.rethrowFromSystemServer();
         }
     ···
     } else {
    ···
     }
 ···
 }

在这里插入图片描述

四、APP进程与System_server的绑定

  • 调用 ActivityThread#attach(false)方法进行 Binder 通信(在方法里进行下一步)
  • 通知system_server进程执行 ActivityManagerService#attachApplication(mAppThread)方法
  • system_server进程在收到请求后,进行一系列准备工作后(创建该App进程信息表)再通过binder IPC向App进程发送scheduleLaunchActivity请求;
  • 这相当于是APP进程发信息给system_server进程,进行一个绑定的过程。创建通信的过程。
    在这里插入图片描述

五、初始化Applacation And Activity

  • App进程的binder线程(ApplicationThread)在收到请求后,通过handler向主线程(ActivityThread)发送LAUNCH_ACTIVITY消息;
  • 主线程(ActivityThread)在收到Message后,通过HandleLaunchActivity创建目标Activity,并回调Activity.onCreate()等方法。
  • 到此,App便正式启动,开始进入Activity生命周期,执行完onCreate/onStart/onResume方法,UI渲染结束后便可以看到App的主界面
    在这里插入图片描述
    到此为止App的启动流程就结束了,上图也是完整的启动流程模型图。

启动优化(浅谈)

透明主题优化

为了解决启动窗口白屏问题,使用透明主题来解决这个问题,但是治标不治本。

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="android:windowFullscreen">true</item>
    <item name="android:windowIsTranslucent">true</item>
</style>

设置闪屏图片主题

这个挺多APP还在用的哦
为了更顺滑无缝衔接我们的闪屏页,可以在启动 Activity 的 Theme中设置闪屏页图片,这样启动窗口的图片就会是闪屏页图片,而不是白屏。

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="android:windowBackground">@mipmap/launch_image</item>   //闪屏页图片  
    <item name="android:windowFullscreen">true</item>
    <item name="android:windowContentOverlay">@null</item>
</style>

这样设置的话,就会在冷启动的时候,展示闪屏页的图片,等App进程初始化加载入口 Activity (也是闪屏页) 就可以无缝衔接。
其实这种方式并没有真正的加速应用进程的启动速度,而只是通过用户视觉效果带来的优化体验。

Application 优化

通过上面的流程,我们可以知道。会先初始化我们的Application,所以在Application中初始化减少耗时操作能有效的帮我提升。
通常,有机会优化这些工作以实现性能改进,这些常见问题包括:

  • 复杂繁琐的布局初始化
  • 阻塞主线程 UI 绘制的操作,如 I/O 读写或者是网络访问.
  • Bitmap 大图片或者 VectorDrawable加载
  • 其它占用主线程的操作

有很多第三方组件(包括App应用本身)都在 Application 中抢占先机,完成初始化操作。
比如Bugly,x5内核初始化,SP的读写,友盟等组件。那就放到子线程中去初始化。

闪屏页业务优化

例如埋点,点击流,数据库初始化等这类必须在主线程初始化的动作。那么我们可以放在闪屏页。
一般:闪屏页政展示总时间 = 组件初始化时间 + 剩余展示时间。
也就是2000ms的总时间,组件初始化了800ms,那么就再展示1200ms即可。

通过上面的流程分析,我们可以知道 Application 初始化后会调用 attachBaseContext() 方法,再调用 Application 的 onCreate(),再到入口 Activity的创建和执行 onCreate() 方法。所以我们就可以在 Application 中记录启动时间。
Application.java

@Override
protected void attachBaseContext(Context base) {
    super.attachBaseContext(base);
    SPUtil.putLong("application\_attach\_time",
        System.currentTimeMillis());//记录Application初始化时间  
}

有了启动时间,我们得知道入口的 Acitivty 显示给用户的时间(View绘制完毕)
那就是入口Activity的onWindowFocusChanged喽
入口Activity.java

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);

    long appAttachTime = SPUtil.getLong("application\_attach\_time");
    long diffTime = System.currentTimeMillis() - appAttachTime;
    //从application到入口Acitity的时间  
    
    //所以闪屏页展示的时间为 2000ms - diffTime.  
}

利用Hook

  • ActivityManagerService

在Android系统中,启动应用的过程通常是通过ActivityManagerService来进行管理的。可以通过Hook ActivityManagerService的方式,在应用启动时进行一些优化操作。例如,可以在应用启动前创建一个空的Activity,并在其onCreate方法中执行一些耗时操作,如初始化数据或预加载资源。然后,通过Hook ActivityManagerService,将启动的Activity替换为这个空的Activity形式,这样就可以减少应用启动的耗时。

  • AMS和PMS

Android系统在应用启动的过程中,会对Activity、Service等组件的启动进行权限验证和安全检查。这个过程较为耗时,可以通过Hook ActivityManagerService(AMS)和PackageManagerService(PMS)来绕过这些检查,从而提升启动速度。例如,可以通过Hook AMS和PMS,修改应用的启动流程,跳过权限验证和安全检查的过程,从而减少启动耗时。

总结

APP的启动流程学问是很大的。需要对Android的源码进行一定的理解。
但是我们在开发中需要有意识的注意会影响APP启动的操作。
毕竟APP的启动是第一扇门。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值