APP启动流程解析

简单概括启动微信的流程就是:

1.Launcher通知AMS 要启动微信了,并且告诉AMS要启动的是哪个页面也就是首页是哪个页面

2.AMS收到消息告诉Launcher知道了,并且把要启动的页面记下来

3.Launcher进入Paused状态,告诉AMS,你去找微信吧

上述就是Launcher和AMS的交互过程

4.AMS检查微信是否已经启动了也就是是否在后台运行,如果是在后台运行就直接启动,如果不是,AMS会在新的进程中创建一个ActivityThread对象,并启动其中的main函数。

5.微信启动后告诉AMS,启动好了

6.AMS通过之前的记录找出微信的首页,告诉微信应该启动哪个页面

7.微信按照AMS通知的页面去启动就启动成功了。

上述阶段是微信和AMS的交互过程。那么接下来我们分析下具体过程

二  启动流程分析


1.点击Launcher上的微信图标时,会调用startActivitySafely方法,intent中携带微信的关键信息也就是我们在配置文件中配置的默认启动页信息,其实在微信安装的时候,Launcher已经将启动信息记录下来了,图标只是一个快捷方式的入口。

startActivitySafely的方法最终还是会调用Activity的startActivity方法

@Override

public void startActivity(Intent intent, @Nullable Bundle options) {

if (options != null) {

startActivityForResult(intent, -1, options);

} else {

// Note we want to go through this call for compatibility with

// applications that may have overridden the method.

startActivityForResult(intent, -1);

}

}

而startActivity方法最终又会回到startActivityForResult方法,这里startActivityForResult的方法中code为-1,表示startActivity并不关心是否启动成功。startActivityForResult部分方法如下所示:

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,

@Nullable Bundle options) {

if (mParent == null) {

options = transferSpringboardActivityOptions(options);

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) {

startActivityForResult方法中又会调用mInstrumentation.execStartActivity方法,我们看到其中有个参数是

mMainThread.getApplicationThread()

关于ActivityThread曾在 深入理解Android消息机制黄林晴的博客_CSDN博客-写作技巧领域博主文章中提到过,ActivityThread是在启动APP的时候创建的,ActivityThread代表应用程序,而我们开发中常用的Application其实是ActivityThread的上下文,在开发中我们经常使用,但在Android系统中其实地位很低的。

Android的main函数就在ActivityThread中

public static void main(String[] args) {

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, “ActivityThreadMain”);

SamplingProfilerIntegration.start();

// CloseGuard defaults to true and can be quite spammy. We

// disable it here, ​
but selectively enable it later (via

// StrictMode) on debug builds, but using DropBox, not logs.

CloseGuard.setEnabled(false);

Environment.initForCurrentUser();

再回到上面方法

mMainThread.getApplicationThread()

得到的是一个Binder对象,代表Launcher所在的App的进程,mToken实际也是一个Binder对象,代表Launcher所在的Activity通过Instrumentation传给AMS,这样AMS就知道是谁发起的请求。

2.mInstrumentation.execStartActivity

instrumentation在测试的时候经常用到,instrumentation的官方文档:http://developer.android.com/intl/zh-cn/reference/android/app/Instrumentation.html这里不对instrumentation进行详细介绍了,我们主要接着看mInstrumentation.execStartActivity方法

public Instrumentation.ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) {

IApplicationThread whoThread = (IApplicationThread)contextThread;

if(this.mActivityMonitors != null) {

Object e = this.mSync;

synchronized(this.mSync) {

int N = this.mActivityMonitors.size();

for(int i = 0; i < N; ++i) {

Instrumentation.ActivityMonitor am = (Instrumentation.ActivityMonitor)this.mActivityMonitors.get(i);

if(am.match(who, (Activity)null, intent)) {

++am.mHits;

if(am.isBlocking()) {

return requestCode >= 0?am.getResult():null;

}

break;

}

}

}

}

try {

intent.setAllowFds(false);

intent.migrateExtraStreamToClipData();

int var16 = ActivityManagerNative.getDefault().startActivity(whoThread, intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null?target.mEmbeddedID:null, requestCode, 0, (String)null, (ParcelFileDescriptor)null, options);

checkStartActivityResult(var16, intent);

} catch (RemoteException var14) {

;

}

return null;

}

其实这个类是一个Binder通信类,相当于IPowerManager.java就是实现了IPowerManager.aidl,我们再来看看getDefault这个函数

public static IActivityManager getDefault() {

return (IActivityManager)gDefault.get();

}

getDefault方法得到一个IActivityManager,它是一个实现了IInterface的接口,里面定义了四大组件的生命周期,

public static IActivityManager asInterface(IBinder obj) {

if(obj == null) {

return null;

} else {

IActivityManager in = (IActivityManager)obj.queryLocalInterface(“android.app.IActivityManager”);

return (IActivityManager)(in != null?in:new ActivityManagerProxy(obj));

}

}

最终返回一个ActivityManagerProxy对象也就是AMP,AMP就是AMS的代理对象,说到代理其实就是代理模式,关于什么是代理模式以及动态代理和静态代理的使用可以持续关注我,后面会单独写篇文章进行介绍。

AMP的startActivity方法

public int startActivity(IApplicationThread caller, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, String profileFile, ParcelFileDescriptor profileFd, Bundle options) throws RemoteException {

Parcel data = Parcel.obtain();

Parcel reply = Parcel.obtain();

data.writeInterfaceToken(“android.app.IActivityManager”);

data.writeStrongBinder(caller != null?caller.asBinder():null);

intent.writeToParcel(data, 0);

data.writeString(resolvedType);

data.writeStrongBinder(resultTo);

data.writeString(resultWho);

data.writeInt(requestCode);

data.writeInt(startFlags);

data.writeString(profileFile);

if(profileFd != null) {

data.writeInt(1);

profileFd.writeToParcel(data, 1);

} else {

data.writeInt(0);

}

主要就是将数据写入AMS进程,等待AMS的返回结果,这个过程是比较枯燥的,因为我们做插件化的时候只能对客户端Hook,而不能对服务端操作,所以我们只能静静的看着。(温馨提示:如果文章到这儿你已经有点头晕了,那就对了,研究源码主要就是梳理整个流程,千万不要纠结源码细节,那样会无法自拔)。

3.AMS处理Launcher的信息

AMS告诉Launcher我知道了,那么AMS如何告诉Launcher呢?

最后

小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

资料⬅专栏获取
细节,那样会无法自拔)。

3.AMS处理Launcher的信息

AMS告诉Launcher我知道了,那么AMS如何告诉Launcher呢?

最后

小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。

[外链图片转存中…(img-O1Nukeuw-1719087053301)]一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

资料⬅专栏获取

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/32423.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[FreeRTOS 基础知识] 互斥访问与回环队列 概念

文章目录 为什么需要互斥访问&#xff1f;使用队列实现互斥访问休眠和唤醒机制环形缓冲区 为什么需要互斥访问&#xff1f; 在裸机中&#xff0c;假设有两个函数&#xff08;func_A, func_B&#xff09;都要修改a的值&#xff08;a&#xff09;&#xff0c;那么将a定义为全局变…

css-vxe列表中ant进度条与百分比

1.vxe列表 ant进度条 <vxe-column field"actualProgress" title"进度" align"center" width"200"><template #default"{ row }"><a-progress:percent"Math.floor(row.actualProgress)"size"s…

Java程序之可爱的小兔兔

题目&#xff1a; 古典问题&#xff0c;有一对兔子&#xff0c;从出生后第3个月起每个月都生一对兔子&#xff0c;小兔子长到第三个月后每个月又生一对兔子&#xff0c;假如兔子都不死&#xff0c;问每个月的兔子总数为多少? 程序分析&#xff1a; 兔子的规律为数列1,1,2,3,…

C++基础知识——《缺省参数》和《函数重载》

P. S.&#xff1a;以下代码均在VS2019环境下测试&#xff0c;不代表所有编译器均可通过。 P. S.&#xff1a;测试代码均未展示头文件stdio.h的声明&#xff0c;使用时请自行添加。 博主主页&#xff1a;Yan. yan.                        …

jQuery Mobile 按钮图标

jQuery Mobile 按钮图标 引言 在移动应用和网站设计中,按钮图标是用户界面设计的重要组成部分。它们不仅增加了视觉吸引力,而且有助于提高用户体验。jQuery Mobile 是一个流行的前端框架,用于创建响应式的移动界面。它提供了一系列内置的按钮图标,这些图标可以轻松地应用…

kafka 集群原理设计(三)之启动原理介绍

kafka 集群原理设计(三)之启动原理介绍 业务背景问题描述 现在有三个机器节点192.168.0.200、192.168.0.201、192.168.0.202,分别安装部署zookeeper、 kafka集群,每个topic有3个分区,3个副本,则kafka各个节点在刚启动时,是如何选择哪个Kafka节 点为管理节点,哪个副本为…

【Android进阶学习】Android-广播接收器(Broadcast-Receivers)

android:theme“style/AppTheme” > 现在&#xff0c;无论什么时候Android设备被启动&#xff0c;都将被广播接收器MyReceiver所拦截&#xff0c;并且在onReceive()中实现的逻辑将被执行。 有许多系统产生的事件被定义为类Intent中的静态常量值。下面的表格列举了重要的系…

微积分-导数1(导数与变化率)

切线 要求与曲线 C C C相切于 P ( a , f ( a ) ) P(a, f(a)) P(a,f(a))点的切线&#xff0c;我们可以在曲线上找到与之相近的一点 Q ( x , f ( x ) ) Q(x, f(x)) Q(x,f(x))&#xff0c;然后求出割线 P Q PQ PQ的斜率&#xff1a; m P Q f ( x ) − f ( a ) x − a m_{PQ} \…

前端面试题(基础篇七)

一、谈谈你对webpack的看法 webpack是一个模块打包工具&#xff0c;我们可以使用webpack管理我们的模块依赖&#xff0c;编译输出模块所需的静态文件。它可以很好的管理、打包web开发中所需的html、css、JavaScript以及其他各种静态文件&#xff08;使用的图片、字体图标等&am…

给数据库的表添加字段

周五有一个需求是这样的&#xff1a; 原来数据库有一个表B&#xff0c;现在需要添加一个字段C&#xff0c;我把代码中增删改查部分进行了修改&#xff0c; 比如insert中也添入了字段C。 但没有考虑到一个问题&#xff0c;数据库的兼容性。因为之前的版本已经投入使用了&…

AES 高级加密加速器实验

1、AES介绍 Kendryte K210 内置 AES&#xff08;高级加密加速器&#xff09;&#xff0c;相对于软件可以极⼤的提高 AES 运算速度。 AES 加速器支持多种加密/解密模式&#xff08;ECB,CBC,GCM&#xff09;,多种⻓度的 KEY&#xff08;ECB,CBC,GCM&#xff09;的运算。 AES 加…

Linux常用环境变量

Linux常用环境变量 一、常用的默认的shell环境变量二、环境变量 PATH三、持久化修改环境变量四、常用的环境变量 一、常用的默认的shell环境变量 1、当我们在shell命令行属于一个命令&#xff0c;shell解释器去解释这个命令的时候&#xff0c;需要先找到这个命令. 找到命令有两…

C++模板类原理讲解

C模板类原理讲解 C模板是一种强大的编译期工具&#xff0c;它允许我们创建通用的、类型无关的类和函数。模板的主要目的是实现代码的重用和泛型编程。模板类的原理涉及以下几个方面&#xff1a; 模板的定义和实例化模板的类型参数模板特化模板的编译过程模板的优点和缺点 1.…

【人机交互 复习】第2章 Hadoop

一、概念 1.Hadoop 是一个能够对大量数据进行分布式处理的软件框架&#xff0c;并 且是以一种可靠、高效、可伸缩的方式进行处理的&#xff0c; 2.特点&#xff1a; 高可靠性&#xff0c;高效性&#xff0c;高可扩展性&#xff0c;高容错性 运行在Linux平台上&#xff0c;支持…

鸿蒙 HarmonyOS NEXT星河版APP应用开发—上篇

一、鸿蒙开发环境搭建 DevEco Studio安装 下载 访问官网&#xff1a;https://developer.huawei.com/consumer/cn/deveco-studio/选择操作系统版本后并注册登录华为账号既可下载安装包 安装 建议&#xff1a;软件和依赖安装目录不要使用中文字符软件安装包下载完成后&#xff0…

【Linux 基础】文件与目录管理

1. 文件和目录的基本概念 文件&#xff1a;是数据的集合&#xff0c;可以是文本、图像、视频等。 目录&#xff08;也称为文件夹&#xff09;&#xff1a;是文件和子目录的集合&#xff0c;用于组织文件。 2. 目录和路径 绝对路径&#xff1a;从根目录&#xff08;/&#x…

2021-03-29:加密与解密

前段时间导师分配的任务主要是看《加密与解密》这本书&#xff0c;“书本写的很详细&#xff0c;认真看会看懂的&#xff01;” 是的啊&#xff0c;书本写的很详细&#xff0c;可是作为一个没基础的小白看起来还是挺吃力的&#xff0c;概念一个接一个的出现&#xff0c;虽然看…

【C/C++】常量定义

常量定义 在C中&#xff0c;#define和constexpr都用于定义常量&#xff0c;但它们之间存在显著的差异。以下是它们之间的主要区别&#xff1a; 类型安全&#xff1a; #define&#xff1a;#define是预处理器指令&#xff0c;它在编译之前对源代码进行文本替换。这意味着#define…

LTE和5G基站规划原则

LTE和5G基站规划原则 以下是一些常见的规划原则&#xff1a; 基站覆盖与容量规划 1. **覆盖需求评估**&#xff1a;确定目标区域需要的覆盖范围&#xff0c;包括地理特性和用户分布情况。 2. **容量需求评估**&#xff1a;估算区域内的用户数量及其数据传输需求&#xff0c…

Android应用--简、美音乐播放器添加电话监听

3. 控制音量 4. 获取专辑图片 5. 在线下载歌词 6. 在线搜索音乐 7. 在线下载音乐 8. 实现有趣功能–甩歌 9. 界面美化–实现专辑倒影 10.实现左右界面切换 11.实现在通知栏显示播放状态 12.实现音乐播放的桌面小控件 暂时想到这些功能&#xff0c;如果朋友们有什么建…