【关注我,后续持续新增专题博文,谢谢!!!】
上一篇我们讲了:
这一篇我们开始讲:
目录
[二、Activity 启动时间确认](#二、Activity 启动时间确认)
一、问题时间点确定
Perfetto 文件命名规则
Perfetto 生成的跟踪文件通常遵循以下命名规则:
默认命名规则
Perfetto 默认生成的跟踪文件通常以
trace开头,后跟时间戳或其他唯一标识符,时间戳为抓取该perfetto 文件结束时的时间。。例如:
trace_20230412_123456.perfetto-tracetrace_<timestamp>.perfetto-trace自定义命名规则
用户可以通过命令行或配置文件指定输出文件名。例如:
perfetto --txt -c config.pbtxt -o custom_name.perfetto-trace此时文件名为
custom_name.perfetto-trace。Android 设备上的命名规则
在 Android 设备上,Perfetto 生成的跟踪文件通常存储在
/data/misc/perfetto-traces/目录下,文件名可能包含以下信息:
- 时间戳(如
trace_20230412_123456.perfetto-trace)- 会话 ID(如
trace_session_123.perfetto-trace)文件扩展名
Perfetto 跟踪文件的扩展名通常为
.perfetto-trace或.pftrace。问题发生的时间确定
通过时间戳定位问题
Perfetto 跟踪文件包含高精度的时间戳,可以通过以下方式确定问题发生的时间:
- 在 Perfetto UI 中打开跟踪文件,查看事件的时间轴。
- 使用
perfetto --query命令查询跟踪文件中的时间范围。跟踪文件元数据
Perfetto 跟踪文件包含元数据,记录跟踪的开始和结束时间。可以通过以下命令查看:
perfetto --query -i trace.perfetto-trace输出中会包含
trace_start_time和trace_end_time。事件时间戳
在 Perfetto UI 中,可以选中特定事件查看其时间戳。时间戳通常以纳秒或微秒为单位,可以转换为可读时间格式。
与其他日志关联
将 Perfetto 跟踪文件的时间戳与系统日志或其他日志文件的时间戳对齐,可以更精确地定位问题发生的时间。
时间同步
确保设备或系统的时钟与 Perfetto 跟踪文件的时间戳同步,避免因时间偏差导致定位错误。
Pefertto 中 start time 的计算方式
通过 slice 表查询
执行以下 SQL 查询可以直接获取指定 slice 的时间信息:
SELECT * FROM slice WHERE id = 28852;查询结果包含
ts(时间戳,单位为纳秒)和dur(持续时间),可以通过转换获取绝对时间或相对时间。通过 surfaceflinger 主线程事件获取
onMessageRefresh是 SurfaceFlinger 主线程的关键事件,其时间戳可直接反映刷新周期。在 Perfetto 中可以通过以下方式定位:
- 在 UI 界面选择
surfaceflinger进程的主线程(通常为com.android.surfaceflinger)。- 查找
onMessageRefresh事件的ts字段,该值为系统绝对时间(纳秒级)。时间戳转换
若需将纳秒时间戳转换为可读格式(如 Unix 时间戳或日期时间),可使用以下方法:
Python 示例 :
import datetime timestamp_ns = 123456789000 # 替换为实际 ts 值 timestamp_s = timestamp_ns / 1e9 print(datetime.datetime.fromtimestamp(timestamp_s))注意事项
- Perfetto 的时间戳基于系统启动时钟(
CLOCK_BOOTTIME),需注意与 UTC 时间的偏移。- SurfaceFlinger 的刷新事件通常以
VSYNC信号为基准,onMessageRefresh的时间可能包含帧调度延迟。systrace 时间戳与内核时间的对应关系
systrace 工具生成的时间戳(TIMESTAMP)基于内核时钟源,通常与内核日志(kernel log)中的时间记录存在直接关联。内核日志的时间标记可能采用 UTC 格式或其他本地时区格式,需通过以下方式建立对应关系:
内核日志中查找时间对应关系
定位关键事件
在 systrace 输出中选取具有明确特征的事件(如进程调度、中断触发),记录其 TIMESTAMP 值。
搜索内核日志
在 kernel log 中使用
grep或工具过滤相同事件的日志行,例如:
dmesg | grep "特定事件关键词"时间格式转换
若内核日志使用 UTC 时间,需将其转换为本地时间戳以便对比。例如通过
date -d "@$(timestamp)"转换 Unix 时间戳。
验证时间同步性
时钟源检查
确认内核时钟源与 systrace 的时钟源一致(如
clocksource设置为tsc或kvm-clock)。可通过以下命令查看:
cat /sys/devices/system/clocksource/clocksource0/current_clocksource时间偏移校准
若存在固定偏移,可能是时区或系统启动时间差异导致。可通过计算 systrace 与内核日志中同一事件的时间差进行校准。
示例操作流程
- 从 systrace 中提取事件 A 的 TIMESTAMP:
123456.789- 在内核日志中搜索事件 A 的 UTC 时间:
[2023-01-01T00:00:00.000] Event A occurred- 将 UTC 时间转换为 Unix 时间戳:
date -d "2023-01-01T00:00:00.000" +%s.%N- 比较转换后的 Unix 时间戳与 systrace TIMESTAMP,确认偏移量。
注意事项
- 确保内核日志的时钟未被频繁调整(如 NTP 同步可能导致跳跃)。
- 高精度时间对比需启用内核的
CONFIG_PRINTK_TIME和CONFIG_PRINTK_TIME_FULL配置选项。
二、Activity 启动时间确认
systrace 查看应用启动时间
通过 systrace 可以分析应用的启动时间,特别是从 system_server 的 launching 行获取关键指标。这些数据在 ActivityMetricsLogger.java 文件中记录,包含冷启动、热启动、温启动的具体时间信息。
启动时间指标说明
ActivityMetricsLogger.java 文件中输出的启动时间指标分为以下三类:
冷启动时间
应用进程不存在,系统需要创建新进程并初始化 Activity。时间包括进程创建、加载资源和初始化组件。
热启动时间
应用进程已存在,Activity 仍在内存中。时间仅包括恢复 Activity 到前台的过程。
温启动时间
应用进程存在但 Activity 被销毁,需要重建 Activity。时间包括恢复进程状态和重建 Activity。
三、前台进程确认方式
前台进程识别方法
通过 Event Log 分析
wm_on_resume_called标记表示目标 Activity 被唤醒到前台,wm_on_paused_called标记表示目标 Activity 退到后台。检查 Component Name 对应的 Activity 状态变化。检查应用进程的输入事件
在目标应用进程中搜索
deliverInputEvent相关 Trace。Android 事件机制会将输入事件派发给获得焦点的应用,前台应用通常存在此类 Trace。分析 System Server 事件队列
在
system_server的InputDispatcher中检查输出队列事件数量:
- 输入事件通过
InputChannel从InputDispatcher传递到应用端ViewRootImpl.java。- 排除干扰项:
ExInputReceiver、PointerEventDispatcher0、swipe-up、ColorSideGestureright等非前台应用。检查 System Server 焦点应用信息
在
ActivityTaskManagerService.java中查找Focused app:相关 Trace。该信息在 Activity 执行resume后打印,直接反映当前前台应用。跟踪应用主线程状态
在目标应用主线程 Trace 中查找
PerformResume和PerformPause标签:
- 两个标签之间的时间段可认定为应用处于前台状态。
- 需结合 Activity 生命周期日志验证准确性。
使用 BatteryHistorian 工具
通过功耗分析工具 BatteryHistorian 的
Top app泳道数据:
- 直观展示用户在不同时间段切换的应用。
- 适合长时间跨度的前台应用行为分析。
四、binder信息格式解析
binder调用日志格式解析
日志格式分为两种模式:请求模式(P->)和响应模式(N<-),具体结构如下:
请求模式
P->*,*,*响应模式
N<-*,*,*字段含义说明
第一字段:调用方向标识
P:表示进程发起binder请求(客户端调用服务端)N:表示进程响应binder请求(服务端返回结果)<-:符号固定存在,表示数据传输方向(请求发出或结果返回)第二字段:接口描述符
- 采用索引化设计,将高频调用的binder接口转换为数字标识
- 目的是减少日志数据量,提升传输效率
- 实际接口名称需要通过索引表转换还原
第三字段:传输类型标识
0:表示BLOCKING阻塞式传输(同步调用)1:表示ONEWAY非阻塞传输(异步调用)第四字段:事务代码
- 对应AIDL文件中定义的方法编号
- 首方法固定编号为0,后续方法按声明顺序递增
- 例如:AIDL中第3个定义的方法对应Code=2
典型示例分析
P->42,1,0表示:客户端发起异步调用(ONEWAY),调用接口索引42对应的方法,事务代码为0(首方法)
N<-16,0,3表示:服务端同步返回结果,处理的是接口索引16的请求,事务代码为3(第4个方法)
技术实现说明
- 索引优化机制通过维护高频接口映射表实现
- ONEWAY标识位决定是否等待服务端返回
- 事务代码与AIDL方法定义顺序严格对应
- 该日志格式由Onetrace模块在系统底层植入
五、亮灭屏信息
systrace 查看屏幕状态的方法
通过 systrace 分析
system_server进程的DisplayPowerMode行可以获取屏幕状态信息。具体方法如下:查看 DisplayPowerMode 行
- 在 systrace 结果中定位
system_server进程。- 查找
DisplayPowerMode行,该行会显示屏幕状态的实时变化。- 状态值对应关系:
状态如下: public static final int POWER_MODE_OFF = 0;
public static final int POWER_MODE_DOZE = 1;
public static final int POWER_MODE_NORMAL = 2;
public static final int POWER_MODE_DOZE_SUSPEND = 3;
public static final int POWER_MODE_ON_SUSPEND = 4;
搜索 setDisplayState TAG
- 在 systrace 中搜索
setDisplayState标签。- 该标签同样会显示屏幕状态变化,数值含义与
DisplayPowerMode一致:
0:灭屏1:亮屏2:解锁注意事项
- 确保 systrace 抓取时包含
system_server进程和Display相关标签。- 结合其他系统事件(如输入事件、WakeLock)分析,可以更准确判断屏幕状态切换的上下文。
扩展应用
- 通过分析状态切换的时间点,可以定位亮灭屏延迟或异常问题。
- 结合 CPU 频率、线程调度等信息,可进一步优化功耗或性能问题。
补充中......
【关注我,后续持续新增专题博文,谢谢!!!】
下一篇讲解: