我们平时在手机桌面上点击一个app 图标, 就能启动一个app应用。从用户角度来看,这个过程看起来很简单,但是它的背后又隐藏着什么玄机 ? 在做安卓开发这么多年后,我觉得有必要认真的分析一下,启动一个app 都走了什么流程 。

1. android app 进程基础理论

1.1 每个Android App都在一个独立空间里, 意味着其运行在一个单独的进程中, 拥有自己的VM, 被系统分配一个唯一的user ID。

1.2 Android App由很多不同组件组成, 这些组件还可以启动其他App的组件. 因此, Android App并没有一个类似程序入口的main()方法。

Android进程与Linux进程一样. 默认情况下, 每个apk运行在自己的Linux进程中. 另外, 默认一个进程里面只有一个线程---主线程. 这个主线程中有一个Looper实例, 通过调用Looper.loop()从Message队列里面取出Message来做相应的处理.

那么, 这个进程何时启动的呢?
简单的说, 进程在其需要的时候被启动. 任意时候, 当用户或者其他组件调取你的apk中的任意组件时, 如果你的apk没有运行, 系统会为其创建一个新的进程并启动. 通常, 这个进程会持续运行直到被系统杀死。
关键是: 进程是在被需要的时候才创建的。

2. 启动流程

关于Android的应用进程在android guide中有这样的一段描述:

By default, every application runs in its own Linux process. Android starts the process when any of the application’s components need to be executed, then shuts down the process when it’s no longer needed or when the system must recover memory for other applications.

每一个android应用默认都是在他自己的linux进程中运行。android操作系统会在这个android应用中的组件需要被执行的时候启动这个应用进程,并且会在这个应用进程没有任何组件执行或者是系统需要为其他应用申请更多内存的时候杀死这个应用进程。所以当我们需要启动这个应用的四大组件之一的时候如果这个应用的进程还没有启动,那么就会先启动这个应用程序进程。

用户点击Home上的一个App图标, 启动一个应用时:

851999-a9c2c456c9f91596.jpg

Click事件会调用startActivity(Intent), 会通过Binder IPC机制, 最终调用到ActivityManagerService. 该Service会执行如下操作:

  • 第一步通过PackageManager的resolveIntent()收集这个intent对象的指向信息.
    指向信息被存储在一个intent对象中.
  • 下面重要的一步是通过grantUriPermissionLocked()方法来验证用户是否有足够的权限去调用该intent对象指向的Activity.
  • 如果有权限, ActivityManagerService会检查并在新的task中启动目标activity.
    现在, 是时候检查这个进程的ProcessRecord是否存在了.
    如果ProcessRecord是null, ActivityManagerService会创建新的进程来实例化目标activity.

2.1 创建进程

ActivityManagerService调用startProcessLocked()方法来创建新的进程, 该方法会通过前面讲到的socket通道传递参数给Zygote进程. Zygote孵化自身, 并调用ZygoteInit.main()方法来实例化ActivityThread对象并最终返回新进程的pid.
ActivityThread随后依次调用Looper.prepareLoop()和Looper.loop()来开启消息循环.

流程图如下:

851999-b6b5dacf9d1488f9.jpg

2.2 绑定Application

接下来要做的就是将进程和指定的Application绑定起来. 这个是通过上节的ActivityThread对象中调用bindApplication()方法完成的. 该方法发送一个BIND_APPLICATION的消息到消息队列中, 最终通过handleBindApplication()方法处理该消息. 然后调用makeApplication()方法来加载App的classes到内存中.

流程如下:

851999-32893aaf343caeac.jpg

2.3 启动Activity

经过前两个步骤之后, 系统已经拥有了该application的进程. 后面的调用顺序就是普通的从一个已经存在的进程中启动一个新进程的activity了.

实际调用方法是realStartActivity(), 它会调用application线程对象中的sheduleLaunchActivity()发送一个LAUNCH_ACTIVITY消息到消息队列中, 通过 handleLaunchActivity()来处理该消息.

假设点击的是一个视频浏览的App, 其流程如下:

851999-9f76d2f18051881c.jpg

在其他博客上看到对于启动流程的总结,感觉比较通俗易懂

大家都知道 Android是基于Linux系统的,而在Linux中,所有的进程都是由init进程直接或者是间接fork出来的,当我开机的时候init进程就会fork出一个Android的第一个新的进程Zygote,中文翻译过来要”受精卵”,一个很有意识的名字。为什么这么说呢,当我们Zygote进程跑起来后,Android为了实现实现资源共用和更快的启动速度,通过Zygote进程直接去fork出一些子进程,这就是为什么要”受精卵”的原因,也就是我们的app全部都是基于Zygote上的 ,没有Zygote就没有我们,当Zygote初始化完成之后,首先会fork它的第一个子进程SystemServer,这个类非常的重要,为什么这么说呢?因为系统里面重要的服务都是在这个进程里面开启的,比如ActivityManagerService、PackageManagerService、WindowManagerService等等,有木有觉得似曾相识当SystemServer跑起来后,这些重要的服务也会随之创建,系统初始化完成之后我们就会进到系统桌面->Launcher,其实Launcher也是一个app,它继承自Activity,当我们点击桌面上的app后,系统就会为我们的app创建一个进程,然后启动我们App的第一个类ActivityThread其实说到底我们的app就是一个main函数,也就是启动了ActivityThread.main()。我们重点来看下这个类

参考文档

1、[译]Android Application启动流程分析
2、Android走进源码告诉你app是如何被启动的 :这篇博客结合源码分析的很透彻,不过大篇幅的源码看着真是头疼 。
3、Activity启动过程全解析

Android启动一个app 流程相关推荐

  1. Android中一个APP启动另一个APP并传递参数

    被调用(启动)的APP: 项目名字:Demo_ybs 项目包名:com.ybs.demo_ybs 被调用APP中获取调用者的传递数据: package com.ybs.demo_ybs;import ...

  2. Android中一个app启动另一个app|从浏览器打开app

    文章目录 一.应用A中点击按钮,跳转到应用B 二.应用A中点击按钮,跳转到应用B中的指定Activity--(scheme方式) 1.应用A中,点击按钮 2.应用B中,AndroidManifest. ...

  3. android 启动其他app的activity,Android在一个app中启动其他app中的service或者Activity

    前言: 启动另一个app的activity和service其实是一样的,区别在于startActivity(intent)还是startService(intent)而已:所以下面案例以启动另一个ap ...

  4. Android 新建一个APP进程的源代码分析(ActivityManageService->Zygote->ActivityThread)

    Android应用程序框架层创建的应用程序进程具有两个特点,一是进程的入口函数是ActivityThread.main,二是进程天然支持Binder进程间通信机制:这两个特点都是在进程的初始化过程中实 ...

  5. 【Android】一个APP检测另一个APP的Service被杀死时自动重启服务

    例如:appA要检测启动appB中的service ##1.修改B中Service启动时的FLAG @Overridepublic int onStartCommand(Intent intent, ...

  6. 学习Android启动初始化 App StartUp

    StartUp是为了App的启动提供的一套简单.高效的初始化方案. ContentProvider中初始化 在项目中会需要用到很多的第三方库,而很多第三方库都提供了显示的调用初始化接口,需要在Appl ...

  7. Android添加一个按键流程及SELinux权限问题

    最近做高通平台P版本遇到一个添加按键问题,驱动在底层添加了节点,后面就不管了,刚好借此机会搞一下添加案件的整个流程下面写下流程,以做笔记 1.驱动添加节点:节点就是驱动添加的文件 ,sys/class ...

  8. android启动其他app的服务器,Android中通过外部程序启动App的三种方法

    这篇文章主要介绍了Android中通过外部程序启动App的三种方法, 本文讲解了直接通过包名. 通过自定义的Action. 通过Scheme三种方法,并分别给出操作代码,需要的朋友可以参考下 ==== ...

  9. android 启动一个应用,android 在一个应用中启动另一个应用

    android 在一个应用中启动另一个应用 在程序开发过程当中,常遇到需要启动另一个应用程序的情况,比如在点击软件的一个按钮可以打开地图软件. startDingAppButton = (Button ...

最新文章

  1. [原][osg]osgconv浅析
  2. 新网站如何推广 新建设的网站如何宣传
  3. MySQL-通过MaxScale实现读写分离初探
  4. IO多路复用之select全面总结(必看篇)
  5. from __future__ import absolute_import的作用
  6. ios找不到信任证书_iOS 11 中可用的受信任根证书列表
  7. python爬虫实战(2)——爬取知乎热榜内容
  8. linux 访问文件软件,Linux下访问文件的基本模式
  9. CodeSmith模板(生成实体类)
  10. HDU 1255 覆盖的面积(线段树+扫描线)
  11. [转载] numpy入门4:线性代数
  12. VDbench 参数信息
  13. 485通讯的校验和_MCGS 与 FX3U PLC 之间的无线通讯实例
  14. 异次元骇客、虚拟机和造物主
  15. 浙大PatC语言练习50-76
  16. opencv-python DIS光流
  17. 【nowcoder 219641】天使果冻
  18. 520礼物清单、送男友实用礼物排行榜
  19. 2011年30家最能赚钱移动互联公司排行榜
  20. 基于8051的电子密码锁程序

热门文章

  1. 六十星系之27七杀独坐寅申
  2. unraid上实现阿里云盘与nas同步
  3. docker安装Oracle数据库
  4. ssh互信 ssh私钥免密登录
  5. 软工非全研究生学习和工作总结-开题和第三辆捷安特
  6. 视频教程-SEM实战教程(三)-网络营销
  7. 如何拒绝公司耍无赖?(2)
  8. 小程序 长按识别二维码
  9. 3Dmax vary渲染器 5.0 安装
  10. Canvas之画布操作