腾讯 Apm 框架 Matrix 源码阅读 - 架构解析

版本

v0.6.5

温馨提示

配合 推荐 Matrix 源码完整注释
可能会有更好的效果

概述

本篇文章是 腾讯开源的 APM 框架 Matrix 系列文章的第二篇,将对 matrix-android-lib这个模块的代码进行阅读。这个模块主要是对Matrix 插件架构进行构建。上一篇为Matrix 源码阅读 - gradle插件

先看一下类图及类功能的简介。
Matrix整体架构.jpg

  • Matrix:Matrix整个框架运行期的入口。也控制着插件的生命周期。所有插件都需要注册到Matrix这个类中进行统一管理
  • AppActiveMatrixDelegate:相当于Application的代理,本身可以感知Activity生命周期,和 APP 进入前台还是 退出到后台 ,感知到以后 会通知给 IAppForeground
  • IPlugin:定义了所有 Plugin的生命周期及通用方法
  • IssuePublisher.OnIssueDetectListener:只有一个onDetectIssue方法,当需要上报问题时会被调用
  • IAppForeground: 只有一个方法就是onForeground 会被 AppActiveMatrixDelegate 调用,可以感知 APP 进入前台还是 退出到后台
  • Plugin: 实现了IPlugin,ssuePublisher.OnIssueDetectListenerIAppForeground。是所有插件的父类,本身兼具插件的 生命周期,感知 问题和 APP状态切换的功能。具体实现有TracePlugin,IOCanaryPlugin,ResourcePlugin,SQLiteLintPlugin后面我们会挨个分析。

下面我们就从 Matrix这个入口类开始看。

1. Matrix

我们使用Matrix一般会这样初始化

    Matrix.Builder builder = new Matrix.Builder(this);
    builder.plugin(new TracePlugin());
    builder.plugin(new IOCanaryPlugin());
    .....
    //详见【1.1】
    Matrix matrix=builder.build();
    //详见【3.1】
    matrix.startAllPlugins();

1.1 Matrix构造方法

看到builder 就知道是使用建造者模式来创建Matrix对象,所以我们二话不说直接看Matrix的构造方法

    private Matrix(Application app, PluginListener listener, HashSet<Plugin> plugins) {
        //保存builder传入的参数
        this.application = app;
        this.pluginListener = listener;
        this.plugins = plugins;
        //初始化Application的代理对象 详见【1.2】
        AppActiveMatrixDelegate.INSTANCE.init(application);
        for (Plugin plugin : plugins) {
            //调用plugin的init方法 详见【2.1】
            plugin.init(application, pluginListener);
            //回调plugin onInit生命周期
            pluginListener.onInit(plugin);
        }

    }

可以看到Matrix的构造方法中,做了三件事

  1. 首先是将builder中传入的参数保存到自己的成员变量中,其中最重要的就是HashSet中存储的各个Plugin.
  2. 初始化 AppActiveMatrixDelegate 这个Application的代理对象
  3. 循环调用所有Plugin的init方法

1.2 AppActiveMatrixDelegate.init()

值得说一下的是 AppActiveMatrixDelegate 这个类是个 枚举单例,不了解枚举单例好处及和其他几种单例方式区别的同学,可以自行百度,谷歌一下,网上文章一大把。
我们继续看AppActiveMatrixDelegate.init()

    //详见【1.3】
    Controller controller = new Controller();

    public void init(Application application) {
        //保证只初始化一次
        if (isInit) {
            return;
        }
        this.isInit = true;
        //获取 子线程 handler
        this.handler = new Handler(MatrixHandlerThread.getDefaultHandlerThread().getLooper());
        //监听 onConfigurationChanged 和 onLowMemory
        application.registerComponentCallbacks(controller);
        //监听activity生命周期
        application.registerActivityLifecycleCallbacks(controller);
    }

可以看到在init()方法中, application注册了ActivityLifecycleCallbacksComponentCallbacks2这两个监听,并且这两个监听指向了同一个对象Controller.有了这两个监听ActivityLifecycleCallbacks就具有了 感知Activity生命周期和APP活动的能力。

1.3 Controller

private final class Controller implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {

        @Override
        public void onActivityStarted(Activity activity) {
            //更新当前页面名称 详见【1.4】
            updateScene(activity);
            //广播 APP切换到前台的 事件 详见【1.5】
            onDispatchForeground(getVisibleScene());
        }
        @Override
        public void onActivityStopped(Activity activity) {
            if (getTopActivityName() == null) {
                 //广播 APP切换到后台的 事件 详见【1.6】
                onDispatchBackground(getVisibleScene());
            }
        }
        .....
        @Override
        public void onTrimMemory(int level) {
            MatrixLog.i(TAG, "[onTrimMemory] level:%s", level);
            if (level == TRIM_MEMORY_UI_HIDDEN && isAppForeground) { // fallback
                 //广播 APP切换到后台的 事件
                onDispatchBackground(visibleScene);
            }
        }
    }

可以看到Controller是真正感知APP状态的类。

1.4 Controller .updateScene()

    private void updateScene(Activity activity) {
      //记录当前activity的名称
        visibleScene = activity.getClass().getName();
    }

1.5 Controller .onDispatchForeground()

  private void onDispatchForeground(String visibleScene) {
      //如果APP已经是可见的,就不做任何操作
        if (isAppForeground || !isInit) {
            return;
        }
        handler.post(new Runnable() {
            @Override
            public void run() {
                //修改APP状态为可见
                isAppForeground = true;
                synchronized (listeners) {
                    for (IAppForeground listener : listeners) {
                        //通知给各个监听者
                        listener.onForeground(true);
                    }
                }
            }
        });

    }

1.6 Controller .onDispatchBackground()

 private void onDispatchBackground(String visibleScene) {
        //如果APP已经是不可见的,就不做任何操作
        if (!isAppForeground || !isInit) {
            return;
        }
        handler.post(new Runnable() {
            @Override
            public void run() {
                isAppForeground = false;
                synchronized (listeners) {
                    for (IAppForeground listener : listeners) {
                        //通知给各个监听者
                        listener.onForeground(false);
                    }
                }
            }
        });


    }

2.1Plugin.init()

Matrix的构造方法中AppActiveMatrixDelegate对象初始化完成后就调用了Plugin.init()方法

    @Override
    public void init(Application app, PluginListener listener) {
        ....
        //将plugin当前的状态切换到 PLUGIN_INITED
        status = PLUGIN_INITED;
        this.application = app;
        this.pluginListener = listener;
        //将自己注册到  AppActiveMatrixDelegate 中 详见【2.2】
        AppActiveMatrixDelegate.INSTANCE.addListener(this);
    }

2.2 AppActiveMatrixDelegate.INSTANCE.addListener(this);

可以看到Plugin在init的时候将自己注册到了AppActiveMatrixDelegate中,当APP前后台状态改变是 Plugin就能感知到

    public void addListener(IAppForeground listener) {
        synchronized (listeners) {
            //添加监听器
            listeners.add(listener);
        }
    }

3.1 Matrix.startAllPlugins()

startAllPlugins这个方法比较简单就是启动所有的插件,Matrix作为插件的管理者理还具有其他类似的方法如 stopAllPlugins,destroyAllPlugins

    //启动所有插件
    public void startAllPlugins() {
        for (Plugin plugin : plugins) {
            plugin.start();
        }
    }

Plugin.onDetectIssue()

  //组织 问题的 Json数据 并调用 监听的 onReportIssue 方法
    @Override
    public void onDetectIssue(Issue issue) {
        if (issue.getTag() == null) {
            // set default tag
            issue.setTag(getTag());
        }
        issue.setPlugin(this);
        JSONObject content = issue.getContent();
        // add tag and type for default
        try {
            if (issue.getTag() != null) {
                content.put(Issue.ISSUE_REPORT_TAG, issue.getTag());
            }
            if (issue.getType() != 0) {
                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());

        } catch (JSONException e) {
            MatrixLog.e(TAG, "json error", e);
        }

        //MatrixLog.e(TAG, "detect issue:%s", issue);
        pluginListener.onReportIssue(issue);
    }

Plugin提供了简单的统一的数据上报方法,并对上报数据封装成统一格式的Json字符串。

总结:

  1. Matrix是整个框架的入口也是所有插件的管理者
  2. 所有的插件都需要继承PluginPlugin本身已经具备了 问题上报和感知APP前后台状态的能力。

系列文章

参考资料

推荐阅读更多精彩内容