介绍
Matrix 是腾讯微信终端团队开发的一套应用性能监控系统(APM),GitHub 地址: Tencent - Matrix。
Matrix-android 当前监控范围包括:应用安装包大小、帧率变化、启动耗时、卡顿、慢方法、SQLite 操作优化、文件读写、内存泄漏等。整个库主要由 5 个组件构成:
- APK Checker。针对 APK 安装包的分析检测工具,根据一系列设定好的规则,检测 APK 是否存在特定的问题,并输出较为详细的检测结果报告,用于分析排查问题以及版本追踪
- Resource Canary。基于 WeakReference 的特性和 Square Haha 库开发的 Activity 泄漏和 Bitmap 重复创建检测工具
- Trace Canary。监控界面流畅性、启动耗时、页面切换耗时、慢函数及卡顿等问题
- IO Canary。检测文件 IO 问题,包括文件 IO 监控和 Closeable Leak 监控
- SQLite Lint。按官方最佳实践自动化检测 SQLite 语句的使用质量
使用
Matrix 的使用方式很简单,在 Application 中初始化后启动即可:
Matrix.Builder builder = new Matrix.Builder(this);
// 添加需要的插件
builder.plugin(new TracePlugin(...));
builder.plugin(new ResourcePlugin(...));
builder.plugin(new IOCanaryPlugin(...));
builder.plugin(new SQLiteLintPlugin(...));
// 初始化
Matrix matrix = Matrix.init(builder.build());
// 启动
matrix.startAllPlugins();
Matrix 类相当于整个库的统一对外接口,资源监控、IO 监控、卡顿监控等功能实现是由其它具体的 Plugin 完成的。
也可以不在 Application 中启动全部插件,而是在某个场景中启动特定的插件,比如:
public class TestTraceMainActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
// 启动插件
Plugin plugin = Matrix.with().getPluginByClass(TracePlugin.class);
if (!plugin.isPluginStarted()) {
plugin.start();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
// 停止插件
Plugin plugin = Matrix.with().getPluginByClass(TracePlugin.class);
if (plugin.isPluginStarted()) {
plugin.stop();
}
}
}
每个具体的 Plugin 都会实现 IPlugin 接口:
public interface IPlugin {
Application getApplication();
void init(Application application, PluginListener pluginListener);
void start();
void stop();
void destroy();
String getTag();
// 在应用可见/不可见时回调
void onForeground(boolean isForeground);
}
可以通过 PluginListener 监听 Plugin 的生命周期变化,或在 Plugin 上报问题时回调:
public interface PluginListener {
void onInit(Plugin plugin);
void onStart(Plugin plugin);
void onStop(Plugin plugin);
void onDestroy(Plugin plugin);
void onReportIssue(Issue issue);
}
上报的问题使用实体类 Issue 包装,Issue 包含 tag、type 等通用字段,详细信息可以通过 JSON 对象 content 获取:
public class Issue {
private int type;
private String tag;
private String key;
private JSONObject content;
private Plugin plugin;
}
源码简析
Matrix
Matrix 是一个单例类,在构造函数执行时,Matrix 内部的所有 Plugin 都会被初始化:
public class Matrix {
private final HashSet<Plugin> plugins;
private Matrix(Application app, PluginListener listener, HashSet<Plugin> plugins) {
this.plugins = plugins;
AppActiveMatrixDelegate.INSTANCE.init(application); // 下面会分析
// 初始化所有 Plugin,并回调 pluginListener
for (Plugin plugin : plugins) {
plugin.init(application, pluginListener);
pluginListener.onInit(plugin);
}
}
}
Plugin
Plugin 是一个抽象类,每次执行 init / start / stop / destroy 等方法时都会更新状态,并回调 PluginListener:
public abstract class Plugin implements IPlugin, IssuePublisher.OnIssueDetectListener, IAppForeground {
private int status = PLUGIN_CREATE;
@Override
public void init(Application app, PluginListener listener) {
status = PLUGIN_INITED;
AppActiveMatrixDelegate.INSTANCE.addListener(this); // 下面会分析
}
@Override
public void start() {
status = PLUGIN_STARTED;
pluginListener.onStart(this);
}
...
}
如果某个具体 Plugin 上报了一个问题,父类 Plugin 还会对该 Issue 填充 tag、type、process、time 等通用字段,并回调 PluginListener 的 onReportIssue 方法:
@Override
public void onDetectIssue(Issue issue) {
issue.setPlugin(this);
JSONObject content = issue.getContent();
// 拼接 tag、type、process、time 等通用字段
content.put(Issue.ISSUE_REPORT_TAG, issue.getTag());
content.put(Issue.ISSUE_REPORT_TYPE, issue.getType());
content.put(Issue.ISSUE_REPORT_PROCESS, MatrixUtil.getProcessName(application));
content.put(Issue.ISSUE_REPORT_TIME, System.currentTimeMillis());
// 回调
pluginListener.onReportIssue(issue);
}
AppActiveMatrixDelegate
Matrix 和 Plugin 都监听了 AppActiveMatrixDelegate,它的主要作用是在应用可见/不可见时通知观察者:
public enum AppActiveMatrixDelegate {
INSTANCE; // 单例
// 观察者列表
private final Set<IAppForeground> listeners = new HashSet();
// 应用可见时通知观察者
private void onDispatchForeground(String visibleScene) {
handler.post(() -> {
isAppForeground = true;
synchronized (listeners) {
for (IAppForeground listener : listeners) {
listener.onForeground(true);
}
}
});
}
// 应用不可见时通知观察者,逻辑和上面的一样
private void onDispatchBackground(String visibleScene) {
...
}
}
判断应用是否可见的逻辑是通过 ActivityLifecycleCallbacks 接口实现的:
private final class Controller implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {
@Override
public void onActivityStarted(Activity activity) {
// 应用可见
updateScene(activity);
onDispatchForeground(getVisibleScene());
}
@Override
public void onActivityStopped(Activity activity) {
// 没有可见的 Activity 了,相当于进入了后台
if (getTopActivityName() == null) {
onDispatchBackground(getVisibleScene());
}
}
...
@Override
public void onTrimMemory(int level) {
// 应用 UI 不可见
if (level == TRIM_MEMORY_UI_HIDDEN && isAppForeground) { // fallback
onDispatchBackground(visibleScene);
}
}
}
总结
Matrix-android 主要包含 5 个组件:APK Checker、Resource Canary、Trace Canary、IO Canary、SQLite Lint。其中 APK Checker 独立运行;其它 4 个模块需要在 Application 中,通过统一对外接口 Matrix 配置完成后执行。每一个模块相当于一个 Plugin,在执行初始化、启动、停止、销毁、报告问题等操作时,都会回调 PluginListener,并更新状态。
每一个 Issue 都有 tag、type、process、time 等 4 个通用字段。
可以监听 AppActiveMatrixDelegate,在应用可见/不可见时,回调 onForeground 方法,以执行相应的操作。应用可见指的是存在可见的 Activity,应用不可见指的是没有可见的 Activity,或者内存不足了,应用的 UI 不可见。