在Android Studio Logcat中过滤关键字“Displayed”,能够看到对应的冷启动耗时日志。html
使用adb shell获取应用的启动时间python
adb shell am start -W [packageName]/[AppstartActivity全路径]
android
执行后会获得三个时间:ThisTime、TotalTime和WaitTime,详情以下:web
ThisTime 最后一个Activity启动耗时。shell
TotalTime 全部Activity启动耗时。编程
WaitTime AMS启动Activity的总耗时。json
通常查看获得的TotalTime,即应用的启动时间,包括建立进程 + Application初始化 + Activity初始化到界面显示的过程。bash
特色:app
面向切面编程,经过预编译和运行期动态代理实现程序功能统一维护的一种技术。函数
做用
利用AOP能够对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合性下降,提升程序的可重用性,同时大大提升了开发效率。
AOP核心概念
1)、横切关注点
对哪些方法进行拦截,拦截后怎么处理。
2)、切面(Aspect)
类是对物体特征的抽象,切面就是对横切关注点的抽象。
3)、链接点(JoinPoint)
被拦截到的点(方法、字段、构造器)。
4)、切入点(PointCut)
对JoinPoint进行拦截的定义。
5)、通知(Advice)
拦截到JoinPoint后要执行的代码,分为前置、后置、环绕三种类型。
准备 首先,为了在Android使用AOP埋点须要引入AspectJ,在项目根目录的build.gradle下加入:
classpath 'com.hujiang.aspectjx:gradle-android-plugin- aspectjx:2.0.0'
而后,在app目录下的build.gradle下加入:
apply plugin: 'android-aspectjx'
implement 'org.aspectj:aspectjrt:1.8.+'
复制代码
AOP埋点实战 JoinPoint通常定位在以下位置:
首先,咱们举一个小栗子:
@Before("execution(* android.app.Activity.on**(..))")
public void onActivityCalled(JoinPoint joinPoint) throws Throwable {
...
}
复制代码
在execution中的是一个匹配规则,第一个*表明匹配任意的方法返回值,后面的语法代码匹配全部Activity中on开头的方法。
处理Join Point的类型:
如何统计Application中的全部方法耗时?
@Aspect
public class ApplicationAop {
@Around("call (* com.json.chao.application.BaseApplication.**(..))")
public void getTime(ProceedingJoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
String name = signature.toShortString();
long time = System.currentTimeMillis();
try {
joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
Log.i(TAG, name + " cost" + (System.currentTimeMillis() - time));
}
}
复制代码
注意
当Action为Before、After时,方法入参为JoinPoint。 当Action为Around时,方法入参为ProceedingPoint。
Around和Before、After的最大区别:
ProceedingPoint不一样于JoinPoint,其提供了proceed方法执行目标方法。
总结AOP特性:
强烈推荐结合第三节讲解的Systrace工具使用,能够很是快速地定位到耗时方法,上线的时候,能够考虑屏蔽掉AOP功能。
//apply plugin: 'android-aspectjx'
检测开始代码处添加:
Debug.startMethodTracing();
检测结束代码处添加:
Debug.stopMethodTracing();
使用adb pull将生成的**.trace文件导出到电脑,而后使用Android Studio的Profiler加载
打开Profiler -> CPU -> 点击 Record -> 点击 Stop -> 查看Profiler下方Top Down/Bottom Up 区域找出耗时的热点方法。
Profile CPU
一、Trace types
Trace Java Methods
会记录每一个方法的时间、CPU信息。对运行时性能影响较大。
Sample Java Methods
相比于Trace Java Methods会记录每一个方法的时间、CPU信息,它会在应用的Java代码执行期间频繁捕获应用的调用堆栈,对运行时性能的影响比较小,可以记录更大的数据区域。
Sample C/C++ Functions
需部署到Android 8.0及以上设备,内部使用simpleperf跟踪应用的native代码,也能够命令行使用simpleperf。
Trace System Calls
检查应用与系统资源的交互状况。 查看全部核心的CPU瓶。 内部采用systrace,也可使用systrace命令。
二、Event timeline 显示应用程序中在其生命周期中转换不一样状态的活动,如用户交互、屏幕旋转事件等。
三、CPU timeline 显示应用程序实时CPU使用率、其它进程实时CPU使用率、应用程序使用的线程总数。
四、Thread activity timeline 列出应用程序进程中的每一个线程,并使用了不一样的颜色在其时间轴上指示其活动。
绿色:线程处于活动状态或准备好使用CPU。 黄色:线程正等待IO操做。(重要) 灰色:线程正在睡眠,不消耗CPU时间。
Profile提供的检查跟踪数据窗口有四种
一、Call Chart
提供函数跟踪数据的图形表示形式。
水平轴:表示调用的时间段和时间。 垂直轴:显示被调用方。 橙色:系统API。 绿色:应用自有方法 蓝色:第三方API(包括Java API) 提示:右键点击Jump to source跳转至指定函数。
二、Flame Chart
将具备相同调用方顺序的彻底相同的方法收集起来。
水平轴:执行每一个方法的相对时间量。 垂直轴:显示被调用方。 注意:看顶层的哪一个函数占据的宽度最大(平顶),可能存在性能问题。
三、Top Down
递归调用列表,提供self、children、total时间和比率来表示被调用的函数信息。 Flame Chart是Top Down列表数据的图形化。
四、Bottom Up
展开函数会显示其调用方。 按照消耗CPU时间由多到少的顺序对函数排序。 注意点:
Wall Clock Time:程序执行时间。 Thread Time:CPU执行的时间。
TraceView小结
特色
做用 主要作热点分析,获得两种数据:
使用方式:代码插桩
定义Trace静态工厂类,将Trace.begainSection(),Trace.endSection()封装成i、o方法,而后再在想要分析的方法先后进行插桩便可。
在命令行下执行systrace.py脚本:
python /Users/quchao/Library/Android/sdk/platform-tools/systrace/systrace.py -t 20 sched gfx view wm am app webview -a "com.wanandroid.json.chao" -o ~/Documents/open-project/systrace_data/wanandroid_start_1.html
复制代码
具体参数含义以下:
如何查看数据?
在UIThread一栏能够看到核心的系统方法时间区域和咱们本身使用代码插桩捕获的方法时间区域。
Systrace原理
在系统的一些关键链路(如SystemServcie、虚拟机、Binder驱动)插入一些信息(Label); 经过Label的开始和结束来肯定某个核心过程的执行时间; 把这些Label信息收集起来获得系统关键路径的运行时间信息,最后获得整个系统的运行性能信息; Android Framework里面一些重要的模块都插入了label信息,用户App中能够添加自定义的Lable。
Systrace小结
特性
结合Android内核的数据,生成Html报告。 系统版本越高,Android Framework中添加的系统可用Label就越多,可以支持和分析的系统模块也就越多。 必须手动缩小范围,会帮助你加速收敛问题的分析过程,进而快速地定位和解决问题。
做用
主要用于分析绘制性能方面的问题。 分析系统关键方法和应用方法耗时。
结合AOP,能够在方法的先后,很是方便地批量插入如下代码。最后从运行生成Html报告后,能够快速查找出耗时的方法。
Trace.begainSection();
Trace.endSection();
复制代码