[Matrix系列-1]: matrix 启动流程源码解析

2,051 阅读4分钟

一、背景

Matrix-android 当前监控范围包括:应用安装包大小,帧率变化,启动耗时,卡顿,慢方法,SQLite 操作优化,文件读写,内存泄漏等等。

而Trace-Canary包含:帧率fps、启动耗时、卡顿、ANR四个部分。

由于matrix整个系统非常的庞大,所以尽量分开去解读。以免造成心里压力~

二、从初始化流程入手

首先从matrix使用的初始化流程说起。重点关注注释中标注的数字。

// Switch.
DynamicConfigImplDemo dynamicConfig = new DynamicConfigImplDemo();

sContext = this;
MatrixLog.i(TAG, "Start Matrix configurations.");

// 1,Builder.不是必须的,有些插件可以单独配置
Matrix.Builder builder = new Matrix.Builder(this);

// Reporter. Matrix will callback this listener when found issue then emitting it.
// 2,注册plugin监听:包含生命周期如init、start、stop、destroy,还有检测到问题的时候的
onReportIssue回调。
builder.pluginListener(new TestPluginListener(this));


// 3, Configure trace canary.
TracePlugin tracePlugin = configureTracePlugin(dynamicConfig);
builder.plugin(tracePlugin);


//...当然,还有其他插件,后续分析~~ 挖坑 ,哈哈哈

//4, build的时候就创建各种plugin,里面调用了plugin的init方法。
Matrix.init(builder.build());

// 5,Trace Plugin 需要主动调用start()
tracePlugin.start();

MatrixLog.i(TAG, "Matrix configurations done.");

简要分析:

  1. 构建Matrix.Builder,用来注册需要的插件。 Builder不是必须的,可以单独初始化某个plugin
  2. 注册plugin的生命周期回调:init()start()stop()destroy(),以及检测到问题后的回调:(onReportIssue(Issue issue)
  3. 调用configureTracePlugin()方法构建tracePlugin对象返回,注册
  4. 调动build()生成matrix对象,里面会调用所有已注册的plugin的init方法
  5. tracePlugin 调用start()方法

2.1 configureTracePlugin()方法

private TracePlugin configureTracePlugin(DynamicConfigImplDemo dynamicConfig) {
    //配置开关
    boolean fpsEnable = dynamicConfig.isFPSEnable();
    boolean traceEnable = dynamicConfig.isTraceEnable();
    boolean signalAnrTraceEnable = dynamicConfig.isSignalAnrTraceEnable();

    File traceFileDir = new File(getApplicationContext().getFilesDir(), "matrix_trace");
    if (!traceFileDir.exists()) {
        if (traceFileDir.mkdirs()) {
            MatrixLog.e(TAG, "failed to create traceFileDir");
        }
    }
    //创建anr文件夹用来存储anr文件
    File anrTraceFile = new File(traceFileDir, "anr_trace");    // path : /data/user/0/sample.tencent.matrix/files/matrix_trace/anr_trace
    // 创建日志print的文件夹 ??
    File printTraceFile = new File(traceFileDir, "print_trace");    // path : /data/user/0/sample.tencent.matrix/files/matrix_trace/print_trace

    TraceConfig traceConfig = new TraceConfig.Builder()
            .dynamicConfig(dynamicConfig)
            .enableFPS(fpsEnable)
            .enableEvilMethodTrace(traceEnable)
            // anr?
            .enableAnrTrace(traceEnable)
            .enableStartup(traceEnable)
            .enableIdleHandlerTrace(traceEnable)                    // Introduced in Matrix 2.0 ,新引入的idleHandler监控
            .enableMainThreadPriorityTrace(true)                    // Introduced in Matrix 2.0 新引入的主线程优先级监控
            .enableSignalAnrTrace(signalAnrTraceEnable)             // Introduced in Matrix 2.0  新引入的信号anr监控, native anr??
            .anrTracePath(anrTraceFile.getAbsolutePath())
            .printTracePath(printTraceFile.getAbsolutePath())
            .splashActivities("sample.tencent.matrix.SplashActivity;") //??
            .isDebug(true)
            .isDevEnv(false)
            .build();

    //Another way to use SignalAnrTracer separately
    //useSignalAnrTraceAlone(anrTraceFile.getAbsolutePath(), printTraceFile.getAbsolutePath());
    // 返回对象
    return new TracePlugin(traceConfig);
}

主要工作就是配置tracePlugin的各种功能,可以根据自身项目的需要进行取舍。

2.2 Matrix.Build的build()方法

build()方法最终会创建matrix对象。

public Matrix build() {
    if (pluginListener == null) {
        pluginListener = new DefaultPluginListener(application);
    }
    return new Matrix(application, pluginListener, plugins);
}
private Matrix(Application app, PluginListener listener, HashSet<Plugin> plugins) {
    this.application = app;
    this.pluginListener = listener;
    this.plugins = plugins;
    //1,AppActiveMatrixDelegate是一个枚举类,注册了activity回调和onLowMemory回调
    AppActiveMatrixDelegate.INSTANCE.init(application);
    // 2,调用插件的init的方法
    for (Plugin plugin : plugins) {
        plugin.init(application, pluginListener);
        //通知pluginListener,初始化完成
        pluginListener.onInit(plugin);
    }

}

2.2.1 AppActiveMatrixDelegate.init(Application application)

两个作用:

  • 注册registerComponentCallbacks 回调,目的是监听系统的onTrimMemory回调
  • 注册activity生命周期回调,目的是维护一个前后台的状态
public void init(Application application) {
    if (isInit) {
        MatrixLog.e(TAG, "has inited!");
        return;
    }
    this.isInit = true;
    if (null != MatrixHandlerThread.getDefaultHandlerThread()) {
        this.handler = new Handler(MatrixHandlerThread.getDefaultHandlerThread().getLooper());
    }
    application.registerComponentCallbacks(controller);
    application.registerActivityLifecycleCallbacks(controller);
}

registerActivityLifecycleCallbacks()作用:

管理和维护App前后台状态,并通过 onDispatchForeground()中回调接口IAppForegroundonForeground(boolean isForeground)方法,因为plugin都实现了这个接口,因此每个plugin都能感知到前后台状态切换。

需要注意的是该回调是在子线程中,线程名字为default_matrix_thread。这个线程是matrix的工作线程,由MatrixHandlerThread类来管理。

@Override
public void onActivityStarted(Activity activity) {
    updateScene(activity);
    onDispatchForeground(getVisibleScene());
}


@Override
public void onActivityStopped(Activity activity) {
    if (getTopActivityName() == null) {
        onDispatchBackground(getVisibleScene());
    }
}
@Override
public void onTrimMemory(int level) {
    MatrixLog.i(TAG, "[onTrimMemory] level:%s", level);
    if (level == TRIM_MEMORY_UI_HIDDEN && isAppForeground) { // fallback
        onDispatchBackground(visibleScene);
    }
}

2.2.2 调用plugin的init方法

这里我们具体看tracePlugin的init的方法。

@Override
public void init(Application app, PluginListener listener) {
    super.init(app, listener);
    MatrixLog.i(TAG, "trace plugin init, trace config: %s", traceConfig.toString());
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
        MatrixLog.e(TAG, "[FrameBeat] API is low Build.VERSION_CODES.JELLY_BEAN(16), TracePlugin is not supported");
        unSupportPlugin();
        return;
    }
     //猜测跟anr有关 
    looperAnrTracer = new LooperAnrTracer(traceConfig);

    frameTracer = new FrameTracer(traceConfig);

    evilMethodTracer = new EvilMethodTracer(traceConfig);

    startupTracer = new StartupTracer(traceConfig);
}

具体逻辑后面分析,这里先看主要的流程。后续再单独介绍各个tracer子类。

另外,TracePlugin继承了Plugin基类。父类Plugin的init方法:

@Override
public void init(Application app, PluginListener listener) {
    if (application != null || pluginListener != null) {
        throw new RuntimeException("plugin duplicate init, application or plugin listener is not null");
    }
    status = PLUGIN_INITED;
    this.application = app;
    this.pluginListener = listener;
    //监听前后台状态的切换。 
    AppActiveMatrixDelegate.INSTANCE.addListener(this);
}

简要分析:

感知前后台状态的切换。

2.3 Matrix.init(Matrix matrix)

在看了 plugins 注册和初始化工作之后,是时候要去真正的执行每个plugin的具体逻辑了。

所以,我们需要回到主流程初始化中的Matrixinit(Matrix matrix)方法。


private static volatile Matrix sInstance;

public static Matrix init(Matrix matrix) {
    if (matrix == null) {
        throw new RuntimeException("Matrix init, Matrix should not be null.");
    }
    synchronized (Matrix.class) {
        if (sInstance == null) {
            sInstance = matrix;
        } else {
            MatrixLog.e(TAG, "Matrix instance is already set. this invoking will be ignored");
        }
    }
    return sInstance;
}

没什么东西,通过静态变量sInstance 引用,方便后续使用。

三、类的职责

经过上面的分析,从matrix顶层设计的角度出发,简单的整理出涉及到的类:

image.png

四、时序图

image.png

LooperAnrTrace 为例进行了分析,其他的trace或者plugin也差不多。后续分析到的时候在详细理解

五、总结

matrix类是整个初始化的入口,它负责管理不同功能的plugins,同时还要回调调用者也就是app端插件的生命周期和检测结果。

AppActiveMatrixDelegate类负责监听前后台变化,维护一个前后台的状态。必要时通知监听者。