10. Android <卡顿十>高度封装Matrix卡顿, 修改Matrix源码和发布自己的插件

在集成Matrix的时候,商业化使用的时候,即使是腾讯官方的,也要很多问题和bug,或者需要修改自己需要的需求,所以要自己看懂源码修改,和发布自己的插件

  • 1).官方版本存在Bug且停止更新(2022年后无维护)

  • 2). Matrix和KOOM和LeakCanary,3者同时集成,用到的Shark冲突问题

源码整体的结构:

1.Matrix存在的问题

1.1 不能找到stack, 一直是空的,key, (比较严重的问题)

比如像这种情况:

json 复制代码
{
  "machine": "BEST",
  "cpu_app": 1.6837534748442526e-5,
  "mem": 17180917760,
  "mem_free": 13995736,
  "detail": "NORMAL",
  "cost": 401,
  "scene": "default",
  "stack": "",
  "stackKey": "",
  "tag": "GW_Trace_EvilMethod",
  "process": "com.gwm.cloudsmartvoice",
  "time": 1741239663891
}

显示的是"tag": "GW_Trace_EvilMethod"!

所以可以知道是插桩出了问题! 继续看源码,找到解决方案:

手动在EvilMethodTracer,慢方法触发器中添加,

AppMethodBeat.i(AppMethodBeat.METHOD_ID_DISPATCH);

AppMethodBeat.o(AppMethodBeat.METHOD_ID_DISPATCH);

ini 复制代码
        @Override
        public void onDispatchBegin(String log) {
//            MatrixLog.w(TAG,"onDispatchBegin");
            indexRecord = AppMethodBeat.getInstance().maskIndex("EvilMethodTracer#dispatchBegin");
            AppMethodBeat.i(AppMethodBeat.METHOD_ID_DISPATCH);
        }
        
        ```
      @Override
        public void onDispatchEnd(String log, long beginNs, long endNs) {
//            MatrixLog.w(TAG,"onDispatchEnd"+Thread.currentThread().getName());
            AppMethodBeat.o(AppMethodBeat.METHOD_ID_DISPATCH);
            long dispatchCost = (endNs - beginNs) / Constants.TIME_MILLIS_TO_NANO;
            try {
                if (dispatchCost >= evilThresholdMs) {
                    long[] data = AppMethodBeat.getInstance().copyData(indexRecord);
                    String scene = AppActiveMatrixDelegate.INSTANCE.getVisibleScene();
                    MatrixHandlerThread.getDefaultHandler().post(new AnalyseTask(isForeground(), scene, data, dispatchCost, endNs));
                }
            } finally {
                indexRecord.release();
            }
        }

1.2 如果是抽象类可能不会找到, 经常会到handler

如何阻止某个类被混淆? 设置白名单! 和黑名单

如下是报告的结果:

swift 复制代码
tag[GW_Trace_EvilMethod]type[0];key[null];content[{"machine":"BEST","cpu_app":1.6837534748442526E-5,"mem":17180917760,"mem_free":13995736,"detail":"NORMAL","cost":401,"scene":"default","stack":"0,1048574,1,401\n1,7459,1,0\n2,6490,1,0\n3,5712,1,0\n1,7447,1,0\n2,10554,1,0\n3,2415,1,0\n4,2423,1,0\n3,2792,1,0\n2,2428,1,0\n1,12667,2,0\n1,403,1,0\n1,462,1,0\n2,265,1,0\n3,215,1,0\n4,12669,1,0\n3,260,1,0\n1,7459,1,0\n2,6490,1,0\n3,5712,1,0\n1,7447,1,0\n2,10554,1,0\n3,2415,1,0\n4,2423,1,0\n3,2792,1,0\n2,2428,1,0\n1,7580,1,0\n1,7588,1,397\n1,12667,1,0\n1,7459,1,0\n","stackKey":"7588|","tag":"GW_Trace_EvilMethod","process":"com.gwm.cloudsmartvoice","time":1741239663891}]

查找映射方法,会指向最终的方法,和dispatchMessage ,找不到调用链关系! 1048574,1,android.os.Handler dispatchMessage (Landroid.os.Message;)V

自己有问题的方法:

kotlin 复制代码
abstract public class AsrStateUiMange

查看源码:插桩的源码,不支持抽象方法的插桩

  • 定位文件 : matrix-gradle-plugin/src/main/java/com/tencent/matrix/trace/transformer/MatrixTraceTransformer.java 及其相关的 ClassVisitor/MethodVisitor

  • 修改逻辑 : 找到跳过 ACC_ABSTRACTACC_INTERFACE 的判断条件。目标是跳过接口和抽象的声明方法,但对抽象类中的具体实现方法进行插桩

  • 示例代码修改: // 原始代码可能类似这样,会跳过所有抽象类和接口 if ((access & Opcodes.ACC_ABSTRACT) != 0 || (access & Opcodes.ACC_INTERFACE) != 0) { return super.visitMethod(access, name, desc, signature, exceptions); }

    scss 复制代码
    // 修改为:仅跳过抽象方法和接口中的方法
    boolean isAbstractMethod = (access & Opcodes.ACC_ABSTRACT) != 0;
    boolean isInterfaceClass = (access & Opcodes.ACC_INTERFACE) != 0; // 注意:这个是类的access,可能需要从ClassVisitor获取
    
    if (isAbstractMethod || isInterfaceClass) {
        // 如果是抽象方法或接口类中的任何方法,跳过插桩
        return super.visitMethod(access, name, desc, signature, exceptions);
    }
    // 否则(即抽象类中的具体方法),进行正常插

使用 Matrix 提供的 trace.py 脚本解析数字栈。

1.3 官方Matrix的demo中的悬浮窗帧率,总是不会实时更新帧率的UI

FrameTracer里面的tryCallBackAndReset(),方法, 里面的reset,导致根本采集不到

ini 复制代码
void tryCallBackAndReset() {
    if (count > 20) {
        dropCount /= count;
        this.refreshRate /= count;
        totalDuration /= count;
        for (int i = 0; i < durations.length; i++) {
            durations[i] /= count;
        }
        listener.onFrameMetricsAvailable(lastScene, durations, dropLevel, dropSum,
                dropCount, this.refreshRate, Constants.TIME_SECOND_TO_NANO / totalDuration);
    }
    reset(); // 问题
}

修改后:

ini 复制代码
void tryCallBackAndReset() {
    if (count > 20) {
        dropCount /= count;
        this.refreshRate /= count;
        totalDuration /= count;
        for (int i = 0; i < durations.length; i++) {
            durations[i] /= count;
        }
        listener.onFrameMetricsAvailable(lastScene, durations, dropLevel, dropSum,
                dropCount, this.refreshRate, Constants.TIME_SECOND_TO_NANO / totalDuration);
       reset(); // 修改后
    }
}

1.4 Matrix 无法监控悬浮窗的FPS,帧率,需要自己解决

原因就是Actvity对象和Window对象! 帧率监控用的原理是:

ini 复制代码
Window.OnFrameMetricsAvailableListener onFrameMetricsAvailableListener = new Window.OnFrameMetricsAvailableListener() {
    private float cachedRefreshRate = defaultRefreshRate;
    private float cachedThreshold = dropFrameListenerThreshold / 60f * cachedRefreshRate;
    private int lastModeId = -1;
    private int lastThreshold = -1;
    private WindowManager.LayoutParams attributes = null;

    private void updateRefreshRate(Window window) {
        if (attributes == null) {
            attributes = window.getAttributes();
        }
        if (attributes.preferredDisplayModeId != lastModeId || lastThreshold != dropFrameListenerThreshold) {
            lastModeId = attributes.preferredDisplayModeId;
            lastThreshold = dropFrameListenerThreshold;
            cachedRefreshRate = getRefreshRate(window);
            cachedThreshold = dropFrameListenerThreshold / 60f * cachedRefreshRate;
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    public void onFrameMetricsAvailable(Window window, FrameMetrics frameMetrics, int dropCountSinceLastInvocation) {
        if (isForeground()) {
            // skip not available metrics.
            for (int i = FrameDuration.UNKNOWN_DELAY_DURATION.ordinal(); i <= FrameDuration.TOTAL_DURATION.ordinal(); i++) {
                long v = frameMetrics.getMetric(FrameDuration.indices[i]);
                if (v < 0 || v >= HALF_MAX) {
                    // some devices will produce outliers, especially the Honor series, eg: NTH-AN00, ANY-AN00, etc.
                    return;
                }
            }
            FrameMetrics frameMetricsCopy = new FrameMetrics(frameMetrics);

            updateRefreshRate(window);

            long totalDuration = frameMetricsCopy.getMetric(FrameMetrics.TOTAL_DURATION);
            float frameIntervalNanos = Constants.TIME_SECOND_TO_NANO / cachedRefreshRate;
            float droppedFrames = Math.max(0f, (totalDuration - frameIntervalNanos) / frameIntervalNanos);

            droppedSum += droppedFrames;

            if (dropFrameListener != null && droppedFrames >= cachedThreshold) {
                dropFrameListener.onFrameMetricsAvailable(ProcessUILifecycleOwner.INSTANCE.getVisibleScene(), frameMetricsCopy, droppedFrames, cachedRefreshRate);
            }
            synchronized (listeners) {
                for (IFrameListener observer : listeners) {
                    observer.onFrameMetricsAvailable(ProcessUILifecycleOwner.INSTANCE.getVisibleScene(), frameMetricsCopy, droppedFrames, cachedRefreshRate);
                }
            }
        }
    }
};

activity.getWindow().addOnFrameMetricsAvailableListener(onFrameMetricsAvailableListener, MatrixHandlerThread.getDefaultHandler());

要通过window对象添加addOnFrameMetricsAvailableListener(), 悬浮窗不能拿到Activity,一般都是services,所以要拿到window对象,就能解决问题!

问题就变成了,悬浮窗如何获取window对象? 或者可以看Toast的源码,自己写一个类似Toast的悬浮窗 或者:Choreographer

2. gradle的整体项目的运行流程:原理

2.1 源码架构

源码的目录:matrix-android

css 复制代码
matrix-android/

├── matrix-gradle-plugin      # Gradle插件模块

├── matrix-trace-canary      # 卡顿/ANR监控

├── matrix-memory-canary      # 内存泄漏检测

├── matrix-io-canary          # 文件IO监控

├── gradle/

│  ├── android-publish.gradle  # 发布配置

│  └── check.gradle          # 代码检查

└── settings.gradle          # 模块聚合配置

  


       Matrix架构

       A[Matrix Core] --> B[APM插件]

       A --> C[资源监控插件]

       A --> D[内存优化插件]

       B --> B1[TraceCanary]

       B --> B2[IOCanary]

       C --> C1[Thread Monitor]

       D --> D1[MemoryCanary]

       

       E[Gradle Plugin] -->|动态注入| A

       F[本地Maven] -->|发布| E

       F -->|依赖| G[Demo App]

搞懂了这个,才知道怎么修改和发布 这个项目这么多module,怎么看起始的运行gradle?

要看发布的插件pluin的module

matrix-gradle-plugin

根目录的setting gradle配置开始,然后有ndk的编译

Arguments.gradle 所在的目录位置

php 复制代码
apply from: "$rootDir/gradle/Arguments.gradle"


// Gradle plugin

include ':matrix-gradle-plugin'

}

调用关系:

调用matrix-gradle-plugin.gradlew的里面,然后调用了gradle/XXX.grade文件

matrix-gradle-plugin: 在task中执行发布的脚本,就可以发布了

gradle文件中有有很多的gradle文件!

1).android-publish 每个module都用到了

2).java-publish.gradle matrix-gradle-plugin中用到了

3).build_library.gradle ------> android-publish-private.gradle ------>check.gradle

发布的时候: 是不是一个模块一个模块单独发布的,还是一起发布,那么就有依赖关系,全部打包到不同的模块

目前看是单独发布的,没有依赖关系!

bash 复制代码
 Searched in the following locations:

       - file:/C:/Users/GW00355722/.m2/repository/com/tencent/matrix/matrix-arscutil/2.2.2/matrix-arscutil-2.2.2.pom
build_library.gradle (公共基础配置)

这是所有 Android Library Module 的基础配置脚本 。它被应用在每个模块的 build.gradle 中,作用是确保所有模块的构建配置统一。

通常包含:

  • 通用 Android 配置compileSdkVersion, buildToolsVersion, defaultConfig(minSdk, targetSdk, versionCode, versionName)等。
  • 通用依赖库 :统一引入所有模块都可能用到的依赖,如 androidx.appcompat
  • 应用其他脚本 :通过 apply from: "$rootDir/gradle/android-publish.gradle"apply from: "$rootDir/gradle/check.gradle" 来引入发布和检查能力。
android-publish.gradle (Android模块发布配置)

这个脚本被 Android Library Module (如 matrix-trace-canary, matrix-memory-canary)使用。它基于 maven-publishsigning 插件,配置如何将 AAR 包发布到 Maven 仓库

3.自定义matrix插件发布步骤:(重点)

腾讯最终发布的插件 "com.tencent.matrix:matrix-memory-canary:2.1.0"

3.1 需要你的需要改的代码

3.2.修改自己要发布的版本和名字

找到: gradle.properties 发布的配置:版本信息

Internal (for wechat), External (for public repo), 我们选择External 修改:

VERSION_NAME_PREFIX=3.1.0 // 之前源码是2.1.0

VERSION_NAME_SUFFIX=

PUBLISH_CHANNEL=External // 源码是Internal

android.useAndroidX=true // 保持不

3.3.studio 出现右边的任务发布

找到 :matrix-commons 模块。找到每个模块对应的task

右边的task没见了,提示android task list not buildt

设置一下gradle配置

  • 在Android Studio的Gradle面板中找到 :matrix-gradle-plugin > Tasks > publishing > publishToMavenLocal

3.4 一个插件一个插件的发布到本地, 因为有多个插件模块

4.1点击publishing里面的任务: 发布到本地电脑用publishToMavenLocal,发布私服: PublishComponentPublicationToMavenResitory

发布是没有顺序的,不会因依赖导致发布错误,但是集成到demo中是有依赖关系的

问题: Could not find com.tencent.matrix:matrix-commons:2.2.2

原因 : 您只发布了 matrix-gradle-plugin,但它所依赖的其他模块(如 matrix-commons, matrix-arscutil)在本地仓库中不存在。
解决 : 必须将所有依赖的模块都发布到本地仓库 。您需要按顺序执行以下模块的 publishToMavenLocal:
matrix-android-lib -> matrix-commons -> matrix-arscutil -> matrix-gradle-plugin -> matrix-trace-canary -> ...

或者更简单的方法:在根目录下执行 ./gradlew publishToMavenLocal,Gradle的Task依赖机制会自动按顺序发布所有模块。

3.5 是否发布成功! 发布成功后的位置:

当使用 mavenLocal() 发布时,生成的文件会被发布到本地 Maven 仓库。

在大多数系统中,默认的本地 Maven 仓库位置是用户目录下的 .m2/repository 目录。

例如,在 Windows 系统中,通常是 C:\Users<用户名>.m2\repository;

总结:

  1. 修改版本号 : 在 gradle.properties 中修改 VERSION_NAME_PREFIX (如改为 3.1.0) 和 PUBLISH_CHANNEL=External
  2. 独立发布模块 : Matrix的各个模块(-plugin, -canary) 是相互独立的,可以分别发布到Maven仓库。它们之间的依赖关系是通过Maven坐标在集成时解决的。
  3. 执行发布任务 : 在Android Studio的Gradle面板中,对每个需要发布的模块,执行 publishing > publishToMavenLocal(发布到本地)或 publish(发布到远程仓库)。
  4. 验证发布 : 发布成功后,在 ~/.m2/repository/com/tencent/matrix/ 目录下找到对应版本号的文件夹,检查 .pom, .jar, .aar 文件是否齐全。

4.验证和使用自己发布的插件在官方的demo中替代

4.1 项目的gradle中设置添加依赖:

arduino 复制代码
classpath "com.tencent.matrix:matrix-gradle-plugin:3.2.0"

4.2 配置依赖从本地加载

scss 复制代码
  mavenLocal()

4.3 单个项目的根gradle设置

arduino 复制代码
implementation "com.tencent.matrix:matrix-trace-canary:3.2.0" // 是否需要在根目录

整体如下:

csharp 复制代码
// 项目根build.gradle

buildscript {

    repositories {

       mavenLocal()  // 优先从本地加载

   }

    dependencies {

        classpath "com.tencent.matrix:matrix-gradle-plugin:3.1.0"  # 改为自定义版本

   }

}
csharp 复制代码
// App模块build.gradle

dependencies {

    implementation "com.tencent.matrix:matrix-trace-canary:3.1.0"  # 同步版本

}

如果用的是官方的demo,只需要改一个数字就可以了:

ini 复制代码
buildscript {

    ext {

        minSdkVersion = 19

        targetSdkVersion = 29

        compileSdkVersion = 29

        buildToolsVersion = '29.0.2'

        javaVersion = JavaVersion.VERSION_1_8

        MATRIX_VERSION = "3.1.0"  // 修改这个

        GROUP = 'com.tencent.matrix'

        VERSION_NAME = "${MATRIX_VERSION}"

github的仓库源码,解决了编译的版本, 包含正确的gradle版本

总结:

  1. 项目根 build.gradle:

    scss 复制代码
    buildscript {
        repositories {
            mavenLocal() // 必须添加,优先从本地仓库寻找
            google()
            mavenCentral()
        }
        dependencies {
            classpath "com.android.tools.build:gradle:4.2.1" // 注意Gradle插件版本兼容性
            classpath "com.tencent.matrix:matrix-gradle-plugin:3.1.0" // 你的自定义版本
        }
    }
  2. App模块 build.gradle:

    arduino 复制代码
    apply plugin: 'com.tencent.matrix-plugin' // 应用插件
    
    dependencies {
        implementation "com.tencent.matrix:matrix-android-lib:3.1.0"
        implementation "com.tencent.matrix:matrix-trace-canary:3.1.0"
        implementation "com.tencent.matrix:matrix-memory-canary:3.1.0"
        // ... 其他所需组件
    }

5.发布的解决常见问题

  • 注意事项:确保NDK版本匹配,依赖顺序一致。

报错:Failed to install the following SDK components:

ndk;23.1.7779620 NDK (Side by side) 23.1.7779620

Install the missing components using the SDK manager in Android Studio.

  • NDK缺失报错:通过Android Studio的SDK Manager安装指定版本NDK(如23.1.7779620)。
  • 依赖顺序:插件可独立发布(无编译依赖),但集成时需按功能顺序引入(如trace-canary依赖matrix-core)。

需要用这个编译

bash 复制代码
distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-6.7.1-all.zip

 

A problem occurred configuring root project 'biaozhunProject _aiTextView'.

> Could not resolve all artifacts for configuration ':classpath'.

  > Could not find com.tencent.matrix:matrix-commons:2.2.2.

    Searched in the following locations:

      - file:/C:/Users/GW00355722/.m2/repository/com/tencent/matrix/matrix-commons/2.2.2/matrix-commons-2.2.2.pom

      - https://jitpack.io/com/tencent/matrix/matrix-commons/2.2.2/matrix-commons-2.2.2.pom

      - https://dl.google.com/dl/android/maven2/com/tencent/matrix/matrix-commons/2.2.2/matrix-commons-2.2.2.pom

      - https://repo.maven.apache.org/maven2/com/tencent/matrix/matrix-commons/2.2.2/matrix-commons-2.2.2.pom

    Required by:

        project : > com.tencent.matrix:matrix-gradle-plugin:2.2.2

  > Could not find com.tencent.matrix:matrix-arscutil:2.2.2.

    Searched in the following locations:

      - file:/C:/Users/GW00355722/.m2/repository/com/tencent/matrix/matrix-arscutil/2.2.2/matrix-arscutil-2.2.2.pom

      - https://jitpack.io/com/tencent/matrix/matrix-arscutil/2.2.2/matrix-arscutil-2.2.2.pom

      - https://dl.google.com/dl/android/maven2/com/tencent/matrix/matrix-arscutil/2.2.2/matrix-arscutil-2.2.2.pom

      - https://repo.maven.apache.org/maven2/com/tencent/matrix/matrix-arscutil/2.2.2/matrix-arscutil-2.2.2.pom

    Required by:

        project : > com.tencent.matrix:matrix-gradle-plugin:2.2.2

  


Possible solution:

 - Declare repository providing the artifact, see the documentation at https://docs.gradle.org/current/userguide/declaring_repositories.html

  

找不到

typescript 复制代码
buildscript {

//    ext.shadow_version = '2.2.1'

    repositories {

        mavenLocal()

        maven { url 'https://jitpack.io' }

        google()

        mavenCentral()

    }

    dependencies {

        classpath 'com.android.tools.build:gradle:4.0.2'

        classpath "com.tencent.matrix:matrix-gradle-plugin:2.2.2"

        // NOTE: Do not place your application dependencies here; they belong

        // in the individual module build.gradle files

    }

}

  


allprojects {

    repositories {

        mavenLocal()

        google()

        mavenCentral()

    }

}
task clean(type: Delete) {

    delete rootProject.buildDir

}

下载ndk: 21. 3669的版本

使用的时候: 是用1个,还是用3个,发现用多个也是没有问题的!

csharp 复制代码
  implementation group: "com.tencent.matrix", name: "matrix-android-lib", version: "2.2.2", changing: true

    implementation group: "com.tencent.matrix", name: "matrix-android-commons", version:  "2.2.2", changing: true

    implementation group: "com.tencent.matrix", name: "matrix-trace-canary", version:  "2.2.2", changing: true

自带的saple,用的是7.5  7.4.2

kotlin用的是

classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.20'

版本只需要修改一个这个值就可以了!

MATRIX_VERSION = "2.2.2"

进去会奔溃,没有进行配置

ini 复制代码
// Configure resource canary.

        ResourcePlugin resourcePlugin = configureResourcePlugin(dynamicConfig);

        builder.plugin(resourcePlugin);

有很多版本的问题,jdk。recyclewView的版本,现在选择的是11jdk

跟 下面这个没有关系!

ruby 复制代码
//    compileOptions {

//        sourceCompatibility JavaVersion.VERSION_1_8

//        targetCompatibility JavaVersion.VERSION_1_8

//    }

./gradlew :app:dependencies

F:\2025_important_demo\20250419_important\app\build\intermediates\merged_java_res\debug\out.jar: 另一个程序正在使用此文件,进程无法访问

./gradlew --stop

相关推荐
写代码的stone2 小时前
antd时间选择器组件体验优化之useLayoutEffect 深度解析:确保 DOM 更新时序的关键机制
前端
Lazy_zheng2 小时前
8 个高频 JS 手写题全面解析:含 Promise A+ 测试实践
前端·javascript·面试
子轩学长说2 小时前
Nano banana极致能力测试,不愧为P图之神~
前端
月出2 小时前
社交登录 - Twitter(前后端完整实现)
前端·twitter
万添裁2 小时前
C++的const_cast
开发语言·前端·javascript
小桥风满袖2 小时前
极简三分钟ES6 - 解构赋值
前端·javascript
掘金安东尼2 小时前
什么是 OKLCH 颜色?
前端·javascript·github
疏影横斜2 小时前
Windows 中使用 fnm 管理 node (bash配置)
前端·node.js
用户2519162427112 小时前
Node之net模块
前端·javascript·node.js