【Android】页面启动耗时统计流程梳理

文章基于Android 11

写在前面:
最近的文章都会放流程图,时序图之类的图片,解释下为什么这么做:
图片的好处:

  • 流程清晰,一目了然
  • 很多代码,如同老太太的裹脚布,又臭又长。影响理解,特别当想和别人解释清除一件事时,大量的代码,会搞得大家没耐心。

所以,如果只是浅尝辄止,只要看图即可得到你想要的结论。如果想深入了解,则跟着图片,对照源码梳理一遍流程。因此这篇文章,如果你有自己阅读源码的方式,理解完第一张图,后续的也就不用看了。后面的文章是给想学源码,却不知道怎么学的人,也是我看源码的个人习惯。

正文开始

本文重点

  • 弄清楚Android是如何统计页面启动耗时的
  • 这个时间是如何算出来的

查看Android的日志可以发现这样一条日志

2024-09-25 10:50:20.944 1292-1350 ActivityTaskManager system_process I Displayed xxx包名/.MainActivity: +966ms

那么我们要统计计时,其实只要弄清楚这个日志的时间怎么计算出来的。跟踪源码,全局搜索Displayed发现

ActivityMetricsLogger#logAppDisplayed

    private void logAppDisplayed(TransitionInfoSnapshot info) {if (info.type != TYPE_TRANSITION_WARM_LAUNCH && info.type != TYPE_TRANSITION_COLD_LAUNCH) {return;}EventLog.writeEvent(WM_ACTIVITY_LAUNCH_TIME,info.userId, info.activityRecordIdHashCode, info.launchedActivityShortComponentName,info.windowsDrawnDelayMs);StringBuilder sb = mStringBuilder;sb.setLength(0);sb.append("Displayed ");sb.append(info.launchedActivityShortComponentName);sb.append(": ");TimeUtils.formatDuration(info.windowsDrawnDelayMs, sb);Log.i(TAG, sb.toString());}

可以看到重点就是这个时间info.windowsDrawnDelayMs,那么这个数据是怎么来的呢?直接上图(如果看不清楚,下载下来看):

在这里插入图片描述

下面是代码分析:整个过程属实无聊。是我自己看源码的一个方法,如果你有自己看源码的方式,后续不看也罢。
as右键find Usages(后续所有的只有一个来源都是这么得到的结论)
TransitionInfoSnapshot#windowsDrawnDelayMs数据的来源只有一个

		private TransitionInfoSnapshot(TransitionInfo info, ActivityRecord launchedActivity,int windowsFullyDrawnDelayMs) {//......windowsDrawnDelayMs = info.mWindowsDrawnDelayMs;//......}

ActivityMetricsLogger#mWindowsDrawnDelayMs

		/** Elapsed time from when we launch an activity to when its windows are drawn. *///直译:从启动 Activity 到绘制其窗口所经过的时间。int mWindowsDrawnDelayMs;

查看这个值的写入只有一个地方

ActivityMetricsLogger#notifyWindowsDrawn

    /*** Notifies the tracker that all windows of the app have been drawn.** @return Non-null info if the activity was pending to draw, otherwise it might have been set*         to invisible (removed from active transition) or it was already drawn.*/TransitionInfoSnapshot notifyWindowsDrawn(@NonNull ActivityRecord r, long timestampNs) {if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn " + r);final TransitionInfo info = getActiveTransitionInfo(r);if (info == null || info.allDrawn()) {if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn no activity to be drawn");return null;}//这里进行赋值// Always calculate the delay because the caller may need to know the individual drawn time.info.mWindowsDrawnDelayMs = info.calculateDelay(timestampNs);info.removePendingDrawActivity(r);final TransitionInfoSnapshot infoSnapshot = new TransitionInfoSnapshot(info);if (info.mLoggedTransitionStarting && info.allDrawn()) {done(false /* abort */, info, "notifyWindowsDrawn - all windows drawn", timestampNs);}return infoSnapshot;}

TransitionInfo#calculateDelay

int calculateDelay(long timestampNs) {// Shouldn't take more than 25 days to launch an app, so int is fine here.//传入的时间 - 开始过渡的时间return (int) TimeUnit.NANOSECONDS.toMillis(timestampNs - mTransitionStartTimeNs);
}

接下来分两部分

  • 开始过渡的时间什么时候赋值
  • 传入的时间是什么时间

开始过渡的时间写入只有一个来源

        private TransitionInfo(ActivityRecord r, LaunchingState launchingState, int transitionType,boolean processRunning, boolean processSwitch) {mLaunchingState = launchingState;//此处就是赋值的地方mTransitionStartTimeNs = launchingState.mCurrentTransitionStartTimeNs;//......}

查看launchingState.mCurrentTransitionStartTimeNs的赋值

TransitionInfoSnapshot#notifyActivityLaunching

    private LaunchingState notifyActivityLaunching(Intent intent, @Nullable ActivityRecord caller,int callingUid) {final long transitionStartTimeNs = SystemClock.elapsedRealtimeNanos();//......if (existingInfo == null) {// Only notify the observer for a new launching event.launchObserverNotifyIntentStarted(intent, transitionStartTimeNs);final LaunchingState launchingState = new LaunchingState();launchingState.mCurrentTransitionStartTimeNs = transitionStartTimeNs;return launchingState;}existingInfo.mLaunchingState.mCurrentTransitionStartTimeNs = transitionStartTimeNs;return existingInfo.mLaunchingState;}

可以看到是在notifyActivityLaunching方法被调用时的SystemClock.elapsedRealtimeNanos()。继续跟踪这个方法被调用的时机

ActivityStarter#startResolvedActivity

ActivityStartController#doPendingActivityLaunches

ActivityStart#executeRequest

到这里熟悉Activity启动流程的基本也就知道开始过渡时间的来源了。不熟悉的我放一张图,大家看下Activity的启动流程,应该也能明白这个时间大概是什么时候。(为了方便看清楚,只截图了一部分,完整图很大,截图放不下。可私聊我获取)

在这里插入图片描述

接下来查看结束时间,即TransitionInfo#calculateDelay传入的时间

再贴一次代码

    TransitionInfoSnapshot notifyWindowsDrawn(@NonNull ActivityRecord r, long timestampNs) {//......// Always calculate the delay because the caller may need to know the individual drawn time.info.mWindowsDrawnDelayMs = info.calculateDelay(timestampNs);//......}

ActivityRecord#onWindowsDrawn

    /** Called when the windows associated app window container are drawn. */void onWindowsDrawn(boolean drawn, long timestampNs) {//......final TransitionInfoSnapshot info = mStackSupervisor.getActivityMetricsLogger().notifyWindowsDrawn(this, timestampNs);//......}

ActivityRecord#updateReportedVisibilityLocked

    void updateReportedVisibilityLocked() {if (nowDrawn != reportedDrawn) {onWindowsDrawn(nowDrawn, SystemClock.elapsedRealtimeNanos());reportedDrawn = nowDrawn;}}

至此,结束时间赋值来源分析结束

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

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

相关文章

《开题报告》基于SpringBoot框架的高校专业实习管理系统开题报告的设计与实现源码++学习文档+答辩讲解视频

开题报告 研究背景 在当今高等教育日益普及与深化的背景下,高校专业实习作为学生将理论知识转化为实践能力、提前适应社会工作环境的重要环节,其重要性不言而喻。然而,传统的高校专业实习管理模式往往存在信息不对称、流程繁琐、效率低下、…

AWS Network Firewall - IGW方式配置只应许白名单域名出入站

参考链接 https://repost.aws/zh-Hans/knowledge-center/network-firewall-configure-domain-ruleshttps://aws.amazon.com/cn/blogs/networking-and-content-delivery/deployment-models-for-aws-network-firewall/ 1. 创建防火墙 选择防火墙的归属子网(选择公有…

【软件工程】成本效益分析

一、成本分析目的 二、成本估算方法 三、成本效益分析方法 课堂小结 例题 选择题

生信初学者教程(十二):数据汇总

文章目录 介绍加载R包导入数据汇总表格输出结果总结介绍 在本教程中,汇总了三个肝细胞癌(HCC)的转录组数据集,分别是LIRI-JP,LIHC-US/TCGA-LIHC和GSE14520,以及一个HCC的单细胞数据集GSE149614的临床表型信息。这些数据集为科研人员提供了丰富的基因表达数据和相关的临床…

设计模式 策略模式(Strategy Pattern)

策略模式简绍 策略模式(Strategy Pattern)是一种行为设计模式,它使你能在运行时改变对象的行为。该模式定义了一系列的算法,并将每一个算法封装起来,使它们可以相互替换。策略模式让算法独立于使用它的客户而变化。 …

当前用户添加到 [uucp ]组

archlinux使用tabby 查看当前用户:将当前用户添加到 uucp 组验证组成员身份重新登录 /dev/ttyUSB0 设备的所有者是 root,而所属组是 uucp,如果您想以当前用户身份访问此设备,您可以将当前用户添加到 uucp 组中。 以下是将当前用户添加到 uucp…

初识C语言(三)

感兴趣的朋友们可以留个关注,我们共同交流,相互促进学习。 文章目录 前言 八、函数 九、数组 (1)数组的定义 (2)数组的下标和使用 十、操作符 (1)算数操作符 (2&#xff…

C# C++ 笔记

第一阶段知识总结 lunix系统操作 1、基础命令 (1)cd cd /[目录名] 打开指定文件目录 cd .. 返回上一级目录 cd - 返回并显示上一次目录 cd ~ 切换到当前用户的家目录 (2)pwd pwd 查看当前所在目录路径 pwd -L 打印当前物理…

Windows安装openssl开发库

1 下载openssl安装包并安装 下载网址: https://slproweb.com/products/Win32OpenSSL.html 下载对应的安装版本。 双击安装包,一路下一步完成安装。注意:1.安装路径不要有空格; 2. 建议不要把DLL拷贝到系统路径。 2 编辑代码 …

遇到慢SQL、SQL报错,应如何快速定位问题 | OceanBase优化实践

在数据库的使用中,大家时常会遇到慢SQL,或执行出错的SQL。对于某些SQL问题,其错误原因显而易见,但也有不少情况难以直观判断。面对这类问题,我们应当如何应对?如何准确识别SQL错误的根源?是否需…

针对考研的C语言学习(定制化快速掌握重点4)

typedef的使用 简化变量类型 逻辑结构 集合结构:无关系 线性结构:一对一 树形结构:一对多 图形结构:多对多 存储结构 顺序存储和链式存储(考代码) 顺序存储优点:1.可以实现随机存取。2.…

山大电力研发费用率远弱同行,先分红上亿再补流9000万?

《港湾商业观察》施子夫 8月9日,证监会网站披露深交所已向山东山大电力技术股份有限公司(以下简称,山大电力)发出第三轮审核问询函。据悉,2023年6月,山大电力递表深交所,保荐机构为兴业证券。 …

Redis入门第一步:认识Redis与快速安装配置

认识Redis与快速安装配置🍃 Redis是什么🐲 1.Redis的背景🎍 Redis(Remote Dictionary Server)译为"远程字典服务",它是一款基于内存实现的键值型 NoSQL 数据库, 通常也被称为数据结…

iOS 项目中的多主题颜色设计与实现

引言 在现代iOS应用中,用户对个性化体验的需求越来越高,除了功能上的满足,多样的视觉风格也是提升用户体验的重要手段之一。提供多主题颜色的切换功能不仅能满足用户的审美偏好,还可以让应用更具活力,适应不同场景下的…

周成虎院士团队和朴世龙院士合作发表Nature Communications:中国植树造林的固碳潜力评估

本文首发于“生态学者”微信公众号! 编者荐语:以下论文是中国科学院地理科学与资源研究所周成虎院士研究团队和朴世龙院士近期合作发表的研究,研究发现在中国强烈的人地矛盾和耕林博弈背景下,相较于新增林地,加密现有…

PCIe6.0 AIC金手指和板端CEM连接器信号完整性设计规范

先附上我之前写的关于PCIe5.0金手指的设计解读: PCIe5.0的Add-in-Card(AIC)金手指layout建议(一)_pcie cem-CSDN博客 PCIe5.0的Add-in-Card(AIC)金手指layout建议(二)_gnd bar-CSDN博客 首先,相较于PCI…

AIGAME平台的由来与未来展望 —— 蒙特加密基金推动区块链与AI融合创新

摘要: AIGAME平台凭借蒙特加密产业基金的战略投资,成为区块链与AI融合创新的先驱。该平台集成了链游、DeFi、加密聊天和跨境支付等多项功能,打造出一个多元化的Web3生态系统。未来,AIGAME将在技术创新和全球布局中持续引领潮流。 …

Ktor快速上手1 - 第一个服务端项目

Ktor 快速上手 第一个APP 工程创建 首先你需要创建一个Ktor工程,这里有两种办法创建: 网页创建后下载包到本地,作为工程打开:Ktor: Project Generator直接在IDEA里面创建Ktor工程 为了方便操作,这里直接在IDEA里面…

WebSocket 2024/9/30

WebSocket是基于TCP的一种新的网络协议。它实现了浏览器与服务器双工通信——浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输。 与HTTP协议的区别 实现

【自动驾驶】控制算法(十一)深度解析车辆纵向控制 | 纵向双 PID 控制算法

写在前面: 🌟 欢迎光临 清流君 的博客小天地,这里是我分享技术与心得的温馨角落。📝 个人主页:清流君_CSDN博客,期待与您一同探索 移动机器人 领域的无限可能。 🔍 本文系 清流君 原创之作&…