Android 性能监控框架 Matrix(0)介绍

5,870 阅读4分钟

介绍

Matrix 是腾讯微信终端团队开发的一套应用性能监控系统(APM),GitHub 地址: Tencent - Matrix

Matrix-android 当前监控范围包括:应用安装包大小、帧率变化、启动耗时、卡顿、慢方法、SQLite 操作优化、文件读写、内存泄漏等。整个库主要由 5 个组件构成:

  1. APK Checker。针对 APK 安装包的分析检测工具,根据一系列设定好的规则,检测 APK 是否存在特定的问题,并输出较为详细的检测结果报告,用于分析排查问题以及版本追踪
  2. Resource Canary。基于 WeakReference 的特性和 Square Haha 库开发的 Activity 泄漏和 Bitmap 重复创建检测工具
  3. Trace Canary。监控界面流畅性、启动耗时、页面切换耗时、慢函数及卡顿等问题
  4. IO Canary。检测文件 IO 问题,包括文件 IO 监控和 Closeable Leak 监控
  5. 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 不可见。