APP启动流程解析

news2024/10/6 22:28:55

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

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.coloradmin.cn/o/1855027.html

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

相关文章

[数据概念]一分钟弄懂数据治理

“ 数据治理是数据资产化的起点。” 数据资产化的趋势正愈演愈烈。然而&#xff0c;我们必须清醒地认识到&#xff0c;资产化的前提条件是拥有实际的数据资产。那么&#xff0c;这些宝贵的数据资产究竟源自何处呢&#xff1f;答案显而易见&#xff0c;它们源自企业日常运营中积…

车载以太网权威指南阅读笔记

总体思路&#xff1a; 要基于车载以太网做出相应的机器人以太网神经中枢&#xff0c;需要按照以下步骤&#xff1a; 了解车载以太网&#xff0c;包括但不限于 车载以太网是如何基于汽车需求定义的车载以太网的工作模式车载以太网工作所需要的硬件车载以太网中的数据交互模式 …

Chrome插件: Octotree让你GitHub代码浏览速度飙升

在GitHub上浏览和管理项目代码时&#xff0c;您是否曾为复杂的目录结构感到困惑&#xff1f;如果有一种工具能够让您轻松浏览项目的文件和目录&#xff0c;会不会大大提升您的工作效率&#xff1f;这正是Octotree浏览器插件所能做到的。 不过说实话&#xff0c;GitHub自带的代码…

WordPress视频主题Qinmei 2.0

WordPress视频主题Qinmei 2.0&#xff0c;简单漂亮的WP视频站源码 主题功能 可以根据豆瓣ID直接获取到其他详细信息&#xff0c;省去慢慢填写的痛苦&#xff1b;播放器支持直链&#xff0c;解析&#xff0c;m3u8格式&#xff0c;同时解析可匹配正则自动更改&#xff1b;新增动…

【建设方案】基于gis地理信息的智慧巡检解决方案(源文件word)

传统的巡检采取人工记录的方式&#xff0c;该工作模式在生产中存在很大弊端&#xff0c;可能造成巡检不到位、操作失误、观察不仔细、历史问题难以追溯等现象&#xff0c;使得巡检数据不准确&#xff0c;设备故障隐患得不到及时发现和处理。因此建立一套完善的巡检管理系统是企…

Flutter TIM 项目配置

目录 1. 设计说明 2. 参考资料索引 Flutter SDK 服务端 Rest API 腾讯后台 其他 3. TIM 整体架构 第一部分&#xff1a;APP 端 第二部分&#xff1a;腾讯服务器 第三部分&#xff1a;三方服务 第四部分&#xff1a;你自己的服务器 4. TIM SDK 集成 TUIK 含 UI 集成…

pywebview打包本地的html

51.安装 pip install pywebview 2.新建start.py import webview import timeclass API:def say_hello(self, name):time.sleep(2) # 模拟一个耗时操作return fHello, {name}!def main():api API()webview.create_window(pywebview Example, index.html, js_apiapi)webview.…

构建家庭NAS之二:TrueNAS Scale规划、安装与配置

首先声明一下&#xff0c;我用的版本是TrueNAS SCALE 24.04.1.1&#xff08;目前的最新版本&#xff09;&#xff0c;其它版本的界面和操作方式或有不同。我安装使用过程中网上的一些教程里的操作方式和这个版本不一样&#xff0c;造成了一些困扰。 TrueNAS SCALE的最低硬件需…

DC/AC电源模块:提高太阳能发电系统的效率和稳定性

BOSHIDA DC/AC电源模块&#xff1a;提高太阳能发电系统的效率和稳定性 DC/AC电源模块是太阳能发电系统中的一个重要组成部分&#xff0c;其作用是将太阳能转化为交流电以供家庭或工业使用。它可以提高太阳能发电系统的效率和稳定性&#xff0c;使得太阳能发电系统更加可靠和持…

Pikachu靶场--CRSF

借鉴参考 CSRF跨站请求伪造&#xff08;CTF教程&#xff0c;Web安全渗透入门&#xff09;_bilibili pikachu靶场CSRF之TOKEN绕过_csrf token绕过的原理-CSDN博客 CSRF(get) 发现需要登录 查看提示&#xff0c;获取username和password 选择一个用户进行登录 选择修改个人信息 …

Applied Spatial Statistics(七):Python 中的空间回归

Applied Spatial Statistics&#xff08;七&#xff09;&#xff1a;Python 中的空间回归 本笔记本演示了如何使用 pysal 的 spreg 库拟合空间滞后模型和空间误差模型。 OLS空间误差模型空间滞后模型三种模型的比较探索滞后模型中的直接和间接影响 import numpy as np impor…

Vue.js 自定义组件的三种用法

1.创建项目 创建项目,你可以参考我以前的博文,这里省略了 项目的目录结构如下: 接着,我们在 src/components 目录下创建一个自定义的组件 SplashHello.vue,示例代码如下所示: <template><div><p>{{ title }}</p><p>{{ message }}</p&…

深入探索 Nuxt3 Composables:掌握目录架构与内置API的高效应用

title: 深入探索 Nuxt3 Composables&#xff1a;掌握目录架构与内置API的高效应用 date: 2024/6/23 updated: 2024/6/23 author: cmdragon excerpt: 摘要&#xff1a;“本文深入探讨了Nuxt3 Composables&#xff0c;重点介绍了其目录架构和内置API的高效应用。通过学习本文&…

Leetcode 2713. 矩阵中严格递增的单元格数(DFS DP)

Leetcode 2713. 矩阵中严格递增的单元格数 DFS 容易想到&#xff0c;枚举每个点作为起点&#xff0c;向同行同列的可跳跃点dfs&#xff0c;维护全局变量记录可达的最远距离 超时&#xff0c;通过样例193 / 566 class Solution {int res 0;public void dfs(int[][] mat, in…

网络编程之XDP、TC和IO_URING以及DPDK

一、网络编程常见的技术 在前面已经分析过了XDP、TC和eBPF。也基本把三者间的关系理清了&#xff0c;但现在又有一个疑惑涌了上来。在前面提到过的IO_URING和DPDK与这些技术有什么关系呢&#xff1f;其实只要认真的看过分析文章可能大家心里都已经基本清楚了。 正如在前面不断…

视频格式怎么转换?9 个免费视频转换工具

前 9 款免费视频转换器有哪些&#xff1f;在此视频转换器评论中&#xff0c;我们收集了一些有用的提示并列出了顶级免费视频转换器软件&#xff0c;还找出了适合所有级别&#xff08;从初学者到专家&#xff09;的最佳免费视频转换器。 1. Geekersoft免费在线视频转换 最好的免…

【HTTPS云证书部署】SpingBoot部署证书

这里以华为云证书为例。 1. 下载证书 2. 解压 3. 选择.top_Tomcat复制到SpringBoot的Resource/source下 4. 在.properties文件中进行配置 修改key-store和key-store-password

vue3源码(五)ref、toRef、toRefs、proxyRefs

1.ref 功能 ref与reactive功能类似,都是将数据变为响应式&#xff0c;ref通常用来定义基本类型数据&#xff0c;如字符串、数字、布尔值等。而reactive用来定义对象&#xff08;或数组&#xff09;类型数据。虽然ref也可以用来定义对象或数组类型的数据&#xff0c;但内部会通…

Rxjava2最全面的解析

说到区别&#xff0c;可能有的小伙伴会问&#xff0c;我没看过rxjava1。可以直接看rxjava2么。个人觉得不必要&#xff0c;因为 rxjava2.x 是按照 Reactive-Streams specification 规范完全的重写的&#xff0c;完全独立于 rxjava1.x 而存在&#xff0c;它改变了以往 rxjava1的…

Springboot 项目启动时扫描所有枚举并存入缓存(redis)

为什么这么做? 为了springboot 注解属性转换字典方便一点(使用缓存的方式在Springboot 启动时获取字典数据) 在启动时会扫描com.vehicle.manager.core.enumerate包下的所有枚举(包括类中的内部枚举),并取出对应属性以json的方式存入redis 目录结构如下: RedisUtil可以在Red…