Android中Matrix的简单使用
1.简介:
Matrix 是一款微信研发并日常使用的应用性能接入框架,支持iOS, macOS和Android。 Matrix 通过接入各种性能监控方案,对性能监控项的异常数据进行采集和分析,输出相应的问题分析、定位与优化建议,从而帮助开发者开发出更高质量的应用。
2.使用说明:
Matrix-android 当前监控范围包括:应用安装包大小,帧率变化,启动耗时,卡顿,慢方法,SQLite 操作优化,文件读写,内存泄漏等等。
- APK Checker: 针对 APK 安装包的分析检测工具,根据一系列设定好的规则,检测 APK 是否存在特定的问题,并输出较为详细的检测结果报告,用于分析排查问题以及版本追踪
- Resource Canary: 基于 WeakReference 的特性和 Square Haha 库开发的 Activity 泄漏和 Bitmap 重复创建检测工具
- Trace Canary: 监控ANR、界面流畅性、启动耗时、页面切换耗时、慢函数及卡顿等问题
- SQLite Lint: 按官方最佳实践自动化检测 SQLite 语句的使用质量
- IO Canary: 检测文件 IO 问题,包括:文件 IO 监控和 Closeable Leak 监控
- Battery Canary: 监控 App 活跃线程(待机状态 & 前台 Loop 监控)、ASM 调用 (WakeLock/Alarm/Gps/Wifi/Bluetooth 等传感器)、 后台流量 (Wifi/移动网络)等 Battery Historian 统计 App 耗电的数据
- MemGuard
- 检测堆内存访问越界、使用释放后的内存、重复释放等问题
3.特性:
与常规的 APM 工具相比,Matrix 拥有以下特点:
APK Checker
- 具有更好的可用性:JAR 包方式提供,更方便应用到持续集成系统中,从而追踪和对比每个 APK 版本之间的变化
- 更多的检查分析功能:除具备 APKAnalyzer 的功能外,还支持统计 APK 中包含的 R 类、检查是否有多个动态库静态链接了 STL 、搜索 APK 中包含的无用资源,以及支持自定义检查规则等
- 输出的检查结果更加详实:支持可视化的 HTML 格式,便于分析处理的 JSON ,自定义输出等等
Resource Canary
- 分离了检测和分析部分,便于在不打断自动化测试的前提下持续输出分析后的检测结果
- 对检测部分生成的 Hprof 文件进行了裁剪,移除了大部分无用数据,降低了传输 Hprof 文件的开销
- 增加了重复 Bitmap 对象检测,方便通过减少冗余 Bitmap 数量,降低内存消耗
Trace Canary
- 编译期动态修改字节码, 高性能记录执行耗时与调用堆栈
- 准确的定位到发生卡顿的函数,提供执行堆栈、执行耗时、执行次数等信息,帮助快速解决卡顿问题
- 自动涵盖卡顿、启动耗时、页面切换、慢函数检测等多个流畅性指标
- 准确监控ANR,并且能够高兼容性和稳定性地保存系统产生的ANR Trace文件
SQLite Lint
- 接入简单,代码无侵入
- 数据量无关,开发、测试阶段即可发现SQLite性能隐患
- 检测算法基于最佳实践,高标准把控SQLite质量*
- 底层是 C++ 实现,支持多平台扩展
IO Canary
- 接入简单,代码无侵入
- 性能、泄漏全面监控,对 IO 质量心中有数
- 兼容到 Android P
Battery Canary
- 接入简单,开箱即用
- 预留 Base 类和 Utility 工具以便扩展监控特性
Memory Hook
- 一个检测 Android native 内存泄漏的工具
- 无侵入,基于 PLT-hook(iqiyi/xHook),无需重编 native 库
- 高性能,基于 Wechat-Backtrace 进行快速 unwind 堆栈,支持 aarch64 和 armeabi-v7a 架构
Pthread Hook
- 一个检测 Android Java 和 native 线程泄漏及缩减 native 线程栈空间的工具
- 无侵入,基于 PLT-hook(iqiyi/xHook),无需重编 native 库
- 通过对 native 线程的默认栈大小进行减半降低线程带来的虚拟内存开销,在 32 位环境下可缓解虚拟内存不足导致的崩溃问题
WVPreAllocHook
- 一个用于安全释放 WebView 预分配内存以在不加载 WebView 时节省虚拟内存的工具,在 32 位环境下可缓解虚拟内存不足导致的崩溃问题
- 无侵入,基于 PLT-hook(iqiyi/xHook),无需重编 native 库
- 使用该工具后 WebView 仍可正常工作
MemGuard
- 一个基于 GWP-Asan 修改的堆内存问题检测工具
- 无侵入,基于 PLT-hook(iqiyi/xHook),无需重编 native 库
- 可根据正则表达式指定被检测的目标库
- 可检测堆内存访问越界、使用释放后的内存和双重释放等问题
Backtrace Component
- 基于 DWARF 以及 ARM 异常处理数据进行简化并生成全新的 quicken unwind tables 数据,用于实现可快速回溯 native 调用栈的 backtrace 组件。回溯速度约是 libunwindstack 的 15x ~ 30x 左右。
完整的说明查看官方文档:https://github.com/Tencent/matrix#matrix_android_cn
4.依赖导入:
4.1 配置Matrix版本:
在gradle.properties目录下配置Matrix版本
MATRIX_VERSION=2.1.0
4.2 AGP8.0.2导入依赖:
由于我是最新稳定版的Studio,AGP版本为8.0以上,所以这里有两种配置方式,后面讲解AGP8.0新的依赖配置方式和改变,这里就直接上代码.
dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.9.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation group: "com.tencent.matrix", name: "matrix-android-lib", version: MATRIX_VERSION, changing: true
implementation group: "com.tencent.matrix", name: "matrix-android-commons", version: MATRIX_VERSION, changing: true
implementation group: "com.tencent.matrix", name: "matrix-trace-canary", version: MATRIX_VERSION, changing: true
implementation group: "com.tencent.matrix", name: "matrix-io-canary", version: MATRIX_VERSION, changing: true
implementation group: "com.tencent.matrix", name: "matrix-memory-canary", version: MATRIX_VERSION, changing: true
implementation 'com.blankj:utilcodex:1.31.1'
}
4.3 AGP8.0以下导入依赖:
apply plugin: 'com.android.application'
apply plugin: 'com.tencent.matrix-plugin'
matrix {
trace {
enable = true //if you don't want to use trace canary, set false
baseMethodMapFile = "${project.buildDir}/matrix_output/Debug.methodmap"
blackListFile = "${project.projectDir}/matrixTrace/blackMethodList.txt"
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.9.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation group: "com.tencent.matrix", name: "matrix-android-lib", version: MATRIX_VERSION, changing: true
implementation group: "com.tencent.matrix", name: "matrix-android-commons", version: MATRIX_VERSION, changing: true
implementation group: "com.tencent.matrix", name: "matrix-trace-canary", version: MATRIX_VERSION, changing: true
implementation group: "com.tencent.matrix", name: "matrix-io-canary", version: MATRIX_VERSION, changing: true
implementation group: "com.tencent.matrix", name: "matrix-memory-canary", version: MATRIX_VERSION, changing: true
implementation 'com.blankj:utilcodex:1.31.1'
}
4.4 项目的build.gradle配置:
buildscript {
repositories {
google()
mavenCentral()
maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' }
maven { url 'https://repo1.maven.org/maven2/' }
}
dependencies {
classpath 'com.android.tools.build:gradle:8.0.2'
classpath ("com.tencent.matrix:matrix-gradle-plugin:${MATRIX_VERSION}") { changing = true }
}
}
plugins {
id 'com.android.application' version '8.0.2' apply false
id 'com.android.library' version '8.0.2' apply false
}
4.5 完整的配置如下:
App目录下的build.gradle
plugins {
id 'com.android.application'
}
//apply plugin: 'com.android.application'
//apply plugin: 'com.tencent.matrix-plugin'
android {
namespace 'com.example.matrixdemo'
compileSdk 33
defaultConfig {
applicationId "com.example.matrixdemo"
minSdk 23
targetSdk 33
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
/* matrix {
trace {
enable = true //if you don't want to use trace canary, set false
baseMethodMapFile = "${project.buildDir}/matrix_output/Debug.methodmap"
blackListFile = "${project.projectDir}/matrixTrace/blackMethodList.txt"
}
}*/
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.9.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation group: "com.tencent.matrix", name: "matrix-android-lib", version: MATRIX_VERSION, changing: true
implementation group: "com.tencent.matrix", name: "matrix-android-commons", version: MATRIX_VERSION, changing: true
implementation group: "com.tencent.matrix", name: "matrix-trace-canary", version: MATRIX_VERSION, changing: true
implementation group: "com.tencent.matrix", name: "matrix-io-canary", version: MATRIX_VERSION, changing: true
implementation group: "com.tencent.matrix", name: "matrix-memory-canary", version: MATRIX_VERSION, changing: true
implementation 'com.blankj:utilcodex:1.31.1'
}
项目的build.gradle:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
mavenCentral()
maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' }
maven { url 'https://repo1.maven.org/maven2/' }
}
dependencies {
classpath 'com.android.tools.build:gradle:8.0.2'
classpath ("com.tencent.matrix:matrix-gradle-plugin:${MATRIX_VERSION}") { changing = true }
}
}
plugins {
id 'com.android.application' version '8.0.2' apply false
id 'com.android.library' version '8.0.2' apply false
}
5.MatrixUtils工具类:
package com.example.matrixdemo.utils;
import android.app.Application;
import com.blankj.utilcode.util.LogUtils;
import com.example.matrixdemo.impl.MatrixDynamicConfigImpl;
import com.example.matrixdemo.plugin.MatrixPluginListener;
import com.tencent.matrix.Matrix;
import com.tencent.matrix.iocanary.IOCanaryPlugin;
import com.tencent.matrix.iocanary.config.IOConfig;
import com.tencent.matrix.memory.canary.MemoryCanaryPlugin;
import com.tencent.matrix.trace.TracePlugin;
import com.tencent.matrix.trace.config.TraceConfig;
/**
* @author: njb
* @date: 2023/8/10 11:19
* @desc:
*/
public class MatrixUtils {
private static volatile MatrixUtils INSTANCE;
private static final String TAG = "MatrixLog";
private MatrixUtils() {
}
public static MatrixUtils getInstance() {
if (INSTANCE == null) {
synchronized (MatrixUtils.class) {
if (INSTANCE == null) {
INSTANCE = new MatrixUtils();
}
}
}
return INSTANCE;
}
public void initPlugin(Application application, String splashActivity) {
Matrix.Builder builder = new Matrix.Builder(application); // build matrix
builder.pluginListener(new MatrixPluginListener(application)); // add general pluginListener
MatrixDynamicConfigImpl matrixDynamicConfig = new MatrixDynamicConfigImpl(); // dynamic config
boolean fpsEnable = matrixDynamicConfig.isFPSEnable();
boolean traceEnable = matrixDynamicConfig.isTraceEnable();
//Trace plugin
TraceConfig traceConfig = new TraceConfig.Builder()
.dynamicConfig(matrixDynamicConfig)
.enableFPS(fpsEnable)//帧率
.enableEvilMethodTrace(traceEnable)//慢方法
.enableAnrTrace(traceEnable)//anr
.enableStartup(traceEnable)//启动速度
.splashActivities(splashActivity)//首页
//debug模式
.isDebug(true)
//dev环境
.isDevEnv(false)
.build();
TracePlugin tracePlugin = new TracePlugin(traceConfig);
builder.plugin(tracePlugin);
MemoryCanaryPlugin memoryCanaryPlugin = new MemoryCanaryPlugin();
builder.plugin(memoryCanaryPlugin);
// io plugin
IOCanaryPlugin ioCanaryPlugin = new IOCanaryPlugin(new IOConfig.Builder()
.dynamicConfig(matrixDynamicConfig)
.build());
builder.plugin(ioCanaryPlugin);
//init matrix
Matrix.init(builder.build());
tracePlugin.start();
}
}
6.自定义Matrix动态配置接口
package com.example.matrixdemo.impl;
import com.tencent.mrs.plugin.IDynamicConfig;
/**
* @author: njb
* @date: 2023/8/10 11:24
* @desc:
*/
public class MatrixDynamicConfigImpl implements IDynamicConfig {
public MatrixDynamicConfigImpl() {}
public boolean isFPSEnable() { return true;}
public boolean isTraceEnable() { return true; }
public boolean isMatrixEnable() { return true; }
public boolean isDumpHprof() { return false;}
@Override
public String get(String key, String defStr) {
return defStr;
}
@Override
public int get(String key, int defInt) {
return defInt;
}
@Override
public long get(String key, long defLong) {
return defLong;
}
@Override
public boolean get(String key, boolean defBool) {
return defBool;
}
@Override
public float get(String key, float defFloat) {
return defFloat;
}
}
7.自定义插件事件监听:
package com.example.matrixdemo.plugin;
import android.content.Context;
import com.blankj.utilcode.util.LogUtils;
import com.tencent.matrix.plugin.DefaultPluginListener;
import com.tencent.matrix.report.Issue;
import com.tencent.matrix.util.MatrixLog;
/**
* @author: njb
* @date: 2023/8/10 11:21
* @desc:
*/
public class MatrixPluginListener extends DefaultPluginListener {
public static final String TAG = "MatrixPluginListener";
public MatrixPluginListener(Context context) {
super(context);
}
@Override
public void onReportIssue(Issue issue) {
super.onReportIssue(issue);
//todo 处理性能监控数据
MatrixLog.e(TAG, issue.toString());
LogUtils.e(TAG, issue.toString());
}
}
8.Matrix初始化:
package com.example.matrixdemo.app;
import android.app.Application;
import com.example.matrixdemo.utils.MatrixUtils;
/**
* @author: njb
* @date: 2023/8/10 11:31
* @desc:
*/
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
initMatrix();
}
private void initMatrix() {
MatrixUtils.getInstance().initPlugin(this,"com.example.matrixdemo.MainActivity;");
}
}
9.简单使用:
private void testThreadAnr() {
try {
int number = 0;
while (number++ < 5) {
LogUtils.e(TAG, "主线程睡眠导致的ANR:次数" + number + "/5");
try {
Thread.sleep(5000L);
} catch (InterruptedException e) {
e.printStackTrace();
LogUtils.e(TAG, "异常信息为:" + e.getMessage());
}
}
} catch (Throwable e) {
e.printStackTrace();
LogUtils.e(TAG, "异常信息为:" + e.getMessage());
}
}
10.完整测试代码:
这里是模拟主线程睡眠导致的ANR,只是为了简单测试.
package com.example.matrixdemo;
import android.os.Bundle;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.blankj.utilcode.util.LogUtils;
public class MainActivity extends AppCompatActivity {
public TextView textView;
private static final String TAG = "MatrixLog";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
textView = findViewById(R.id.tv_test);
textView.setOnClickListener(v -> testThreadAnr());
}
private void testThreadAnr() {
try {
int number = 0;
while (number++ < 5) {
LogUtils.e(TAG, "主线程睡眠导致的ANR:次数" + number + "/5");
try {
Thread.sleep(5000L);
} catch (InterruptedException e) {
e.printStackTrace();
LogUtils.e(TAG, "异常信息为:" + e.getMessage());
}
}
} catch (Throwable e) {
e.printStackTrace();
LogUtils.e(TAG, "异常信息为:" + e.getMessage());
}
}
}
11.布局代码:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/tv_test"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
12.日志打印:
13.源码地址:
https://gitee.com/jackning_admin/matrixdemo
14.总结:
以上就是微信性能监控框架Matrix的简单封装,可以说非常好用,各种信息也非常全面,后面会尝试所有的性能监控插件的使用,这里只是简单介绍一下使用,在新版本的配置!!!