通过am start -W package/componentName可以开启一个Activity
例如
am start -W com.tcl.testdemo1/.MainActivity
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.tcl.testdemo1/.MainActivity }
Status: ok
Activity: com.tcl.testdemo1/.MainActivity
ThisTime: 2144
TotalTime: 2144
WaitTime: 2262
Complete
我们可以得到三个时间
WaitTime、TotalTime、ThisTime分别是怎么统计的,统计的是Activity启动哪一段时间段
“adb shell am start -W ”的实现在 /frameworks/base/services/core/java/com/android/server/am/ActivityManagerShellCommand.java 文件中。通过Binder调用ActivityManagerService.startActivityAndWait() 接口
代码位置
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@Override
public int onCommand(String cmd) {
......
switch (cmd) {
case "start":
case "start-activity":
return runStartActivity(pw);
......
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
int runStartActivity(PrintWriter pw) throws RemoteException {
......
intent = makeIntent(UserHandle.USER_CURRENT);//会把mWaitOption设置为了true
......
final long startTime = SystemClock.uptimeMillis(); //计算WaitTime的开始的时间
. . . . . .
if (mWaitOption) {
result = mInterface.startActivityAndWait(null, null, intent, mimeType,
null, null, 0, mStartFlags, profilerInfo,
options != null ? options.toBundle() : null, mUserId);
res = result.result;
} else {
res = mInterface.startActivityAsUser(null, null, intent, mimeType,
null, null, 0, mStartFlags, profilerInfo,
options != null ? options.toBundle() : null, mUserId);
}
final long endTime = SystemClock.uptimeMillis(); //计算WaitTime结束的时间
......
调用result = mInterface.startActivityAndWait 启动成功,返回result。 启动成功后launched为true
下面就是我们看到的输入am start -W 后打印的结果,
if (mWaitOption && launched) {
if (result == null) {
result = new WaitResult();
result.who = intent.getComponent();
}
pw.println("Status: " + (result.timeout ? "timeout" : "ok"));
if (result.who != null) {
pw.println("Activity: " + result.who.flattenToShortString());
}
if (result.thisTime >= 0) {
pw.println("ThisTime: " + result.thisTime);
}
if (result.totalTime >= 0) {
pw.println("TotalTime: " + result.totalTime);
}
pw.println("WaitTime: " + (endTime-startTime));
pw.println("Complete");
pw.flush();
}
结果有 status:,Activity:,ThisTime:,TotalTime:,WaitTime:,Complete字段等。
可以看到WaitTime 是 endTime-startTime 就是结束时间减开始时间
一、WaitTime
那 mInterface.startActivityAndWait是走到哪一步返回了。
接下来源码跟踪下这些字段的赋值。
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@Override
public final WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
enforceNotIsolatedCaller("startActivityAndWait");
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, false, ALLOW_FULL_ONLY, "startActivityAndWait", null);
WaitResult res = new WaitResult(); //WaitResult在这里new出来,Activity启动时间对象
// TODO: Switch to user app stacks here.
mActivityStartController.obtainStarter(intent, "startActivityAndWait")
.setCaller(caller)
.setCallingPackage(callingPackage)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setStartFlags(startFlags)
.setActivityOptions(bOptions)
.setMayWait(userId)
.setProfilerInfo(profilerInfo)
.setWaitResult(res)
.execute();
return res; //这里return的是WaitResult对象
}
/frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java
int execute() {
......
return startActivityMayWait(mRequest.caller, mRequest.callingUid,
mRequest.callingPackage, mRequest.intent, mRequest.resolvedType,
mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
mRequest.resultWho, mRequest.requestCode, mRequest.startFlags,
mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig,
mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId,
mRequest.inTask, mRequest.reason,
mRequest.allowPendingRemoteAnimationRegistryLookup);
...... //这里return的是int类型,当然没人接它,感觉没啥用处。
}
private int startActivityMayWait(......){
......
final ActivityRecord[] outRecord = new ActivityRecord[1];
int res = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo,
voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid,
callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options,
ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason,
allowPendingRemoteAnimationRegistryLookup);
......
if (outResult != null) { //这个就是WaitResult对象,当然不为空
//res可能返回三个不同结果START_SUCCESS、START_TASK_TO_FRONT、START_DELIVERED_TO_TOP,我们的重点在START_SUCCESS
outResult.result = res;
final ActivityRecord r = outRecord[0];
switch(res) {
case START_SUCCESS: {
mSupervisor.mWaitingActivityLaunched.add(outResult);//把outResult加入到队列中是想干啥,当然是赋值了,totalTime,ThisTime用。
do {
try {
mService.wait(); //启动成功后直接wait住了,等待唤醒。
} catch (InterruptedException e) {
}
} while (outResult.result != START_TASK_TO_FRONT
&& !outResult.timeout && outResult.who == null);
if (outResult.result == START_TASK_TO_FRONT) {
res = START_TASK_TO_FRONT;
}
break;
}
case START_DELIVERED_TO_TOP: {
......
break;
}
case START_TASK_TO_FRONT: {
......
break;
}
}
}
mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(res, outRecord[0]);
return res;
}
一共三点:
1,startActivity什么时候返回;
2,mSupervisor.mWaitingActivityLaunched.add(outResult) 是怎么个赋值;
3,mService.wait() 什么时候唤醒。
唤醒后就直接返回了START_SUCCESS,然后一路返回,到最开始,这个时候waitTime就计算出来了。
二、TotalTime、ThisTime
我们知道Activity显示出来会走到ActivityRecord的reportLaunchTimeLocked
/frameworks/base/services/core/java/com/android/server/am/ActivityRecord.java
private void reportLaunchTimeLocked(final long curTime) {
//这个LaunchTimeTracker是个关键,下来跟踪一下。
final LaunchTimeTracker.Entry entry = mStackSupervisor.getLaunchTimeTracker().getEntry(
getWindowingMode());
if (entry == null) {
return;
}
final long thisTime = curTime - displayStartTime;
final long totalTime = entry.mLaunchStartTime != 0
? (curTime - entry.mLaunchStartTime) : thisTime;
if (SHOW_ACTIVITY_START_TIME) {
Trace.asyncTraceEnd(TRACE_TAG_ACTIVITY_MANAGER, "launching: " + packageName, 0);
EventLog.writeEvent(AM_ACTIVITY_LAUNCH_TIME,
userId, System.identityHashCode(this), shortComponentName,
thisTime, totalTime);
StringBuilder sb = service.mStringBuilder;
sb.setLength(0);
sb.append("Displayed ");
sb.append(shortComponentName);
sb.append(": ");
TimeUtils.formatDuration(thisTime, sb);
if (thisTime != totalTime) {
sb.append(" (total ");
TimeUtils.formatDuration(totalTime, sb);
sb.append(")");
}
Log.i(TAG, sb.toString()); //ActivityManager: Displayed packagename/.xxx: +3s534ms
}
//这个就是更新mWaitingActivityLaunched的集合,更新WaitResult
mStackSupervisor.reportActivityLaunchedLocked(false, this, thisTime, totalTime);
if (totalTime > 0) {
//service.mUsageStatsService.noteLaunchTime(realActivity, (int)totalTime);
}
displayStartTime = 0;
entry.mLaunchStartTime = 0;
}
这里有几个关键字
curTime表示该函数调用的时间点.
displayStartTime表示一连串启动Activity中的最后一个Activity的启动时间点.
mLaunchStartTime表示一连串启动Activity中第一个Activity的启动时间点.
thisTime:最后一个activity从启动到绘制完成的时间
totalTime:是第一个activity的启动时间到最后一个activity的绘制完成时间。如果只启动一个activity,则thisTime和totalTime一致。
看下displayStartTime、mLaunchStartTime的赋值
/frameworks/base/services/core/java/com/android/server/am/LaunchTimeTracker.java
static class Entry {
long mLaunchStartTime;
long mFullyDrawnStartTime;
void setLaunchTime(ActivityRecord r) {
if (r.displayStartTime == 0) {
r.fullyDrawnStartTime = r.displayStartTime = SystemClock.uptimeMillis();
if (mLaunchStartTime == 0) {
startLaunchTraces(r.packageName);
mLaunchStartTime = mFullyDrawnStartTime = r.displayStartTime;
}
} else if (mLaunchStartTime == 0) {
startLaunchTraces(r.packageName);
mLaunchStartTime = mFullyDrawnStartTime = SystemClock.uptimeMillis();
}
}
setLaunchTime 的调用的地方有两处
1、ActivityStackSupervisor.java
int startSpecificActivityLocked(){
......
getLaunchTimeTracker().setLaunchTime(r);
......
}
2、ActivityStack.java
int minimalResumeActivityLocked(){
......
mStackSupervisor.getLaunchTimeTracker().setLaunchTime(r);
......
}
启动Activity执行顺序先1后2,
1、只启动一个Activity
这个时候displayStartTime == mLaunchStartTime 就是进程启动之前的时间点。
thisTime = TotalTime
2、连续启动2个Activity
这个时候displayStartTime就是第一个Activity的启动时间,mLaunchStartTime就是第二个Activity的启动时间。
thisTime 是最后一个activity启动的时间点。
在上面的图中,我用①②③分别标注了三个时间段,在这三个时间段内分别干了什么事呢?
在第①个时间段内,AMS 创建 ActivityRecord 记录块和选择合理的 Task、将当前Resume 的 Activity 进行 pause
在第②个时间段内,启动进程、调用无界面 Activity 的 onCreate() 等、 pause/finish 无界面的 Activity
在第③个时间段内,调用有界面 Activity 的 onCreate、onResume
看到这里应该清楚 ThisTime、TotalTime、WaitTime 三个时间的关系了吧:
WaitTime 就是总的耗时,包括前一个应用 Activity pause 的时间和新应用启动的时间;
ThisTime 表示一连串启动 Activity 的最后一个 Activity 的启动耗时;
TotalTime 表示新应用启动的耗时,包括新进程的启动和 Activity 的启动,但不包括前
一个应用 Activity pause 的耗时。也就是说,开发者一般只要关心 TotalTime 即可,这个时间才是自己应用真正启动的耗时。
Event log中 TAG=am_activity_launch_time 中的两个值分表表示 ThisTime、TotalTime,跟通过 “adb shell am start -W ” 得到的值是一致的。