TracePlugin初始化时会调用StartupTracer构造函数
public StartupTracer(TraceConfig config) {
//用户配置的splash页
this.splashActivities = config.getSplashActivities();
//监听Application创建完成回调
ActivityThreadHacker.addListener(this);
}
ActivityThreadHacker是怎么监听到application的创建完成的呢?
AppMethodBeat第一次执行i方法时,会执行realExecute 方法,里面调用了ActivityThreadHacker.hackSysHandlerCallback(),这个方法只会执行一次。
hackSysHandlerCallback
hackSysHandlerCallback顾名思义就是hook Handler的Callback来拦截Handler消息。
public static void hackSysHandlerCallback() {
try {
//将第一个方法(Application的attachBaseContext)作为app启动的时间点并记录下来
sApplicationCreateBeginTime = SystemClock.uptimeMillis();
//通过maskIndex用来标记获取堆栈信息的起点,便于回溯
sApplicationCreateBeginMethodIndex = AppMethodBeat.getInstance().maskIndex("ApplicationCreateBeginMethodIndex");
Class<?> forName = Class.forName("android.app.ActivityThread");
Field field = forName.getDeclaredField("sCurrentActivityThread");
field.setAccessible(true);
Object activityThreadValue = field.get(forName);
//通过反射拿到ActivityThread对象的mH
Field mH = forName.getDeclaredField("mH");
mH.setAccessible(true);
Object handler = mH.get(activityThreadValue);
//拿到mH的父类Handler
Class<?> handlerClass = handler.getClass().getSuperclass();
if (null != handlerClass) {
//获取Handler成员变量mCallback
Field callbackField = handlerClass.getDeclaredField("mCallback");
callbackField.setAccessible(true);
Handler.Callback originalCallback = (Handler.Callback) callbackField.get(handler);
//包装成HackCallback进行代理
HackCallback callback = new HackCallback(originalCallback);
callbackField.set(handler, callback);
}
MatrixLog.i(TAG, "hook system handler completed. start:%s SDK_INT:%s", sApplicationCreateBeginTime, Build.VERSION.SDK_INT);
} catch (Exception e) {
MatrixLog.e(TAG, "hook system handler err! %s", e.getCause().toString());
}
}
将app启动时间点记录为sApplicationCreateBeginTime
通过反射拿到ActivityThread对象的mH,mH继承自Handler,然后拿到Handler的mCallback,包装成HackCallback进行代理,消息的handleMessage就会被HackCallback拦截到。
@Override
public boolean handleMessage(Message msg) {
//开关
if (!AppMethodBeat.isRealTrace()) {
//关闭则直接回调原来的handleMessage,不改变逻辑
return null != mOriginalCallback && mOriginalCallback.handleMessage(msg);
}
//是否是启动页
boolean isLaunchActivity = isLaunchActivity(msg);
//isCreated避免重复调用
if (!isCreated) {
//当消息是启动页,Service,Receiver表示Application创建已执行完毕
if (isLaunchActivity || msg.what == CREATE_SERVICE
|| msg.what == RECEIVER) { // todo for provider
//记录Application创建完毕的时间点
ActivityThreadHacker.sApplicationCreateEndTime = SystemClock.uptimeMillis();
//记录消息类型
ActivityThreadHacker.sApplicationCreateScene = msg.what;
isCreated = true;
sIsCreatedByLaunchActivity = isLaunchActivity;
MatrixLog.i(TAG, "application create end, sApplicationCreateScene:%d, isLaunchActivity:%s", msg.what, isLaunchActivity);
synchronized (listeners) {
for (IApplicationCreateListener listener : listeners) {
//回调onApplicationCreateEnd
listener.onApplicationCreateEnd();
}
}
}
}
//回调原来的handleMessage
return null != mOriginalCallback && mOriginalCallback.handleMessage(msg);
}
在app的启动流程中,Activity,Service,Receiver组件的启动是通过ActivityThread中mH去处理的,组件启动表示Application创建完毕,记录Application创建完毕的时间点为sApplicationCreateEndTime,并回调onApplicationCreateEnd。
接口看下isLaunchActivity如何判断是启动页消息呢?
可以先回顾下:Activity的启动流程
在ApplicationThread > Activity阶段,会通过sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction) 发送消息给H,该消息中ClientTransaction的mActivityCallbacks包含用于请求启动Activity的LaunchActivityItem。
private boolean isLaunchActivity(Message msg) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O_MR1) {
if (msg.what == EXECUTE_TRANSACTION && msg.obj != null) {
try {
//ClientTransaction用于辅助管理生命周期
if (null == method) {
Class clazz = Class.forName("android.app.servertransaction.ClientTransaction");
//拿到ClientTransaction的mActivityCallbacks
method = clazz.getDeclaredMethod("getCallbacks");
method.setAccessible(true);
}
List list = (List) method.invoke(msg.obj);
//判断 Request to launch an activity
if (!list.isEmpty()) {
return list.get(0).getClass().getName().endsWith(".LaunchActivityItem");
}
} catch (Exception e) {
MatrixLog.e(TAG, "[isLaunchActivity] %s", e);
}
}
//否则判断消息LAUNCH_ACTIVITY
return msg.what == LAUNCH_ACTIVITY;
} else {
//低版本直接判断消息是LAUNCH_ACTIVITY或RELAUNCH_ACTIVITY
return msg.what == LAUNCH_ACTIVITY || msg.what == RELAUNCH_ACTIVITY;
}
}
这样就得到了Application创建完成的回调onApplicationCreateEnd
onApplicationCreateEnd
@Override
public void onApplicationCreateEnd() {
//如果app没有Activity,上报应用启动
if (!isHasActivity) {
// sApplicationCreateEndTime - sApplicationCreateBeginTime
long applicationCost = ActivityThreadHacker.getApplicationCost();
MatrixLog.i(TAG, "onApplicationCreateEnd, applicationCost:%d", applicationCost);
analyse(applicationCost, 0, applicationCost, false);
}
}
接着看Tracer生命周期的onAlive
@Override
protected void onAlive() {
super.onAlive();
MatrixLog.i(TAG, "[onAlive] isStartupEnable:%s", isStartupEnable);
if (isStartupEnable) {
//监听Activity的onWindowFocusChanged回调(插桩at)
AppMethodBeat.getInstance().addListener(this);
//通过Application注册了所有activity的生命回调
Matrix.with().getApplication().registerActivityLifecycleCallbacks(this);
}
}
通过registerActivityLifecycleCallbacks来监听Activity的生命周期,OnCreate时会回调onActivityCreated
onActivityCreated
//coldCost为0说明这个值没被改动过,表示冷启动
private long coldCost = 0;
//当前Activity计数,onActivityCreated时+1,onActivityDestroyed时-1
private int activeActivityCount;
//是否是温启动
private boolean isWarmStartUp;
//上一个Activity创建的时间点
private long lastCreateActivity = 0L;
//map存Activity创建时的时间点,因为可能存在多个Activity
private HashMap<String, Long> createdTimeMap = new HashMap<>();
//是否统计耗时开关
private boolean isShouldRecordCreateTime = true;
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
MatrixLog.i(TAG, "activeActivityCount:%d, coldCost:%d", activeActivityCount, coldCost);
//Activity个数为0 && coldCost改动过,说明是温启动
if (activeActivityCount == 0 && coldCost > 0) {
lastCreateActivity = uptimeMillis();
MatrixLog.i(TAG, "lastCreateActivity:%d, activity:%s", lastCreateActivity, activity.getClass().getName());
//温启动标记置为true
isWarmStartUp = true;
}
//Activity计数自增
activeActivityCount++;
if (isShouldRecordCreateTime) {
//记录Activity创建时对应的时间点
createdTimeMap.put(activity.getClass().getName() + "@" + activity.hashCode(), uptimeMillis());
}
}
@Override
public void onActivityDestroyed(Activity activity) {
MatrixLog.i(TAG, "activeActivityCount:%d", activeActivityCount);
//Activity计数自减
activeActivityCount--;
}
温启动判断:当前Activity个数为0说明需要重新创建Activity,并且coldCost不是初始值0说明app进程依然在。
将Activity的启动时间点存到createdTimeMap中,在Activity的onWindowFocusChanged执行时,会回调onActivityFocused作为Activity启动完成的时间点,然后计算差值就是Activity启动耗时。
onActivityFocused
结合着官方注释看下面代码
@Override
public void onActivityFocused(Activity activity) {
//正常情况下会执行 ActivityThreadHacker.sApplicationCreateScene = msg.what覆盖默认值
if (ActivityThreadHacker.sApplicationCreateScene == Integer.MIN_VALUE) {
Log.w(TAG, "start up from unknown scene");
return;
}
//获取当前回调的activityName
String activityName = activity.getClass().getName();
//coldCost为0表示冷启动
if (isColdStartup()) {
//是否时候启动页
boolean isCreatedByLaunchActivity = ActivityThreadHacker.isCreatedByLaunchActivity();
//从createdTime取出Activity创建开始时间点
String key = activityName + "@" + activity.hashCode();
Long createdTime = createdTimeMap.get(key);
if (createdTime == null) {
createdTime = 0L;
}
// Activity启动耗时 = 当前时间点-开始时间点,复用并存到createdTimeMap
createdTimeMap.put(key, uptimeMillis() - createdTime);
//firstScreenCost为初始值0,表示第一个获取焦点的Activity,记录时间差为首屏启动耗时
if (firstScreenCost == 0) {
//当前时间 - sApplicationCreateBeginTime
this.firstScreenCost = uptimeMillis() - ActivityThreadHacker.getEggBrokenTime();
}
//如果配置了Splash页并且已经展示过,也就是当前是'careActivity',记录此时的时间差为冷启动耗时,见上图的coldCost
if (hasShowSplashActivity) {
coldCost = uptimeMillis() - ActivityThreadHacker.getEggBrokenTime();
} else {
//如果当前Activity是Splash页,hasShowSplashActivity置为true,此时coldCost还是为0
if (splashActivities.contains(activityName)) {
hasShowSplashActivity = true;
} else {
//如果没有配置Splash页的情况
if (isCreatedByLaunchActivity) {
//如果启动的是Activity,记录首屏耗时为冷启动耗时
coldCost = firstScreenCost;
} else {
//冷启动启动的不是Activity,记录applicationCost为冷启动耗时
firstScreenCost = 0;
coldCost = ActivityThreadHacker.getApplicationCost();
}
}
}
//冷启动耗时分析
if (coldCost > 0) {
Long betweenCost = createdTimeMap.get(key);
//过滤异常情况
if (null != betweenCost && betweenCost >= 30 * 1000) {
MatrixLog.e(TAG, "%s cost too much time[%s] between activity create and onActivityFocused, "
+ "just throw it.(createTime:%s) ", key, uptimeMillis() - createdTime, createdTime);
return;
}
analyse(ActivityThreadHacker.getApplicationCost(), firstScreenCost, coldCost, false);
}
} else if (isWarmStartUp()) {
//温启动耗时分析,温启动时间 = 当前时间 - 温启动onActivityCreated时记录的开始时间点lastCreateActivity
isWarmStartUp = false;
long warmCost = uptimeMillis() - lastCreateActivity;
MatrixLog.i(TAG, "#WarmStartup# activity:%s, warmCost:%d, now:%d, lastCreateActivity:%d", activityName, warmCost, uptimeMillis(), lastCreateActivity);
if (warmCost > 0) {
analyse(0, 0, warmCost, true);
}
}
}
接着analyse根据冷启动和温启动耗时大于等于阈值获取对应的堆栈信息并上报,上一篇文章(APM框架Matrix源码分析(十)EvilMethodTracer之慢函数监控)分析过不再分析了。
小结
-
applicationCost(Application创建耗时):Application的attachBaseContext到ActivityThread中的mH收到组件启动的msg
-
coldCost(冷启动耗时):Application的attachBaseContext到第一个
careActivity的onWindowFocusChanged(配置的Splash页启动也算在这个时间内) -
warmCost(温启动耗时):Launcher Activity的启动耗时