Matrix-APKChecker源码分析(1)

栏目: IOS · Android · 发布时间: 5年前

内容简介:Matrix是微信开源的APM工具,APKChecker是其中针对APK文件做静态分析的工具,是Matrix的一部分。上面两篇腾讯云的相关文章,介绍了Matrix&ApkChecker的一些基本功能。本文针对APKChecker的源码做一个简单的分析,聊一下该工具各个功能的实现原理。采用的是

微信自研 APM 利器,Matrix 正式开源了

Matrix-ApkChecker — Apk 分析减包利器

Matrix是微信开源的APM工具,APKChecker是其中针对APK文件做静态分析的工具,是Matrix的一部分。上面两篇腾讯云的相关文章,介绍了Matrix&ApkChecker的一些基本功能。本文针对APKChecker的源码做一个简单的分析,聊一下该 工具 各个功能的实现原理。采用的是 Matrix 工程,master分支4月16号的代码为分析源码。

依赖库

简单看一下工程目录和gradle配置的依赖关系。显然,前文链接中的ApkChecker的代码目录是matrix-apk-canary。

Matrix-APKChecker源码分析(1)

  • libs文件夹中,有apktool的jar包,反编译工具在这里也是意料之中
  • resources目录中,有android的framework jar包,分析APK文件一些基础数据类型在Android framework层中定义
  • gradle配置中,可以看到依赖了常用的gson工具类、Android的common工具包、本地工程matrix-common
  • 走读一下matrix-common,基本上可以判定该module主要是matrix公用的数据结构与工具组件

代码结构

Matrix-APKChecker源码分析(1)

从代码目录上看,它的包名目录定义的十分清晰,基本上可以一目了然:

  • exception:异常定义
  • job:工作任务,包含任务管理、配置和常量定义
  • output:输出
  • result:分析结果相关
  • task:分析任务,基本可以通过任务命名直接对应上相关文档中的功能
  • ApkChecker类:最后输出jar包的程序入口

简单梳理一下类图关系,能够进一步了解源码的设计思路。

Matrix-APKChecker源码分析(1)

可以看出,基本上可以分为四部分:

  • 左侧是入口类和核心任务类,里面封装了主要的分析实现过程
  • 上侧是基础的任务实现部分,图中省略了很多功能任务类,只列了三个,可以看到一个简单的继承关系,和一个工厂模式的处理
  • 右侧是任务结果部分,可以看到主要有Json和html两种格式。这部分主要是针对每个任务的结果输出,同样是一个继承关系和相应的工厂处理
  • 下侧是整个分析任务的结果输出,可以简单认为它是对TaskResult的整理和真正的结果文件化输出。依然是两种格式的继承关系和工厂处理

综合起来看,如果对执行流程感兴趣,去看ApkJob类的实现就好了;对每个分析功能感兴趣,去task包目录下找对应的功能实现类就好了;对最后分析结果是如何输出的感兴趣,可以查一下TaskResult和JobResult相关的实现就好了。

核心流程走读

这里简单分析入口类ApkChecker和任务管理类ApkJob。

ApkChecker

入口类只有不到一百行的代码,十分简洁。主要除了封装了main函数入口,还处理了输入参数异常情况下输出HELP提示的过程。

public static void main(String... args){
    if (args.length > 0) {
        ApkChecker m = new ApkChecker();
        m.run(args);
    } else {
        System.out.println(INTRODUCT + HELP);
        System.exit(0);
    }
}

private void run(String[] args){
  ApkJob job = new ApkJob(args);
  try {
      job.run();
  } catch (Exception e) {
      e.printStackTrace();
      System.exit(-1);
  }
}

很明显,main函数封装的主要是ApkJob,核心函数是它的run接口。此处注意,输入参数args,作为ApkJob的构造函数参数传入,想来是作为了该类的成员变量处理了。

ApkJob

该类有530行左右的代码,如前文类图描述的,成员属性包括了两个分析任务的ApkTask的列表、一个输出结果工具JobResult的列表。除此之外,还有前面传进来的参数args和相关的配置参数描述类JobConfig、一个多线程执行器ExecutorService。构造方法中基本上做一些初始化工作。

run函数比较函数流程比较易懂,只有十几行:

public void run()throws Exception {
    if (parseParams()) {
        ApkTask unzipTask = TaskFactory.factory(TaskFactory.TASK_TYPE_UNZIP, jobConfig, new HashMap<String, String>());
        preTasks.add(unzipTask);
        for (String format : jobConfig.getOutputFormatList()) {
            JobResult result = JobResultFactory.factory(format, jobConfig);
            if (result != null) {
                jobResults.add(result);
            } else {
                Log.w(TAG, "Unknown output format name '%s' !", format);
            }
        }
        execute();
    } else {
        ApkChecker.printHelp();
    }
}
  • 解析参数

    解析参数函数涉及到代码量,比较大。因为支持配置文件和参数两种形式的参数,核心解析函数parseGlobalParams()长达126行,经过解析和校验后,在成功的情况下,jobConfig成员被参数设置好,用于后续的分析任务。

  • 在预处理任务列表中添加一个解压任务

    预处理任务列表在整个类中,只有此处添加了一个解压任务。之所以设计成列表,应该是考虑代码的可拓展性。从业务上说,在每项检查点的任务执行之前,要先把目标APK解压出来,也是应有之意。

  • 处理配置的输出格式,将所有格式加入输出结果工具列表

    可以理解是参数解析好之后,通过传入参数做的第一件事。就是先把输出工具处理好,为后续分析结果的输出做好准备。

  • 执行execute 函数

    预处理执行完,就是正经的任务分析流程了。

    private void execute()throws Exception {
        try {
    
            for (ApkTask preTask : preTasks) {
                preTask.init();
                TaskResult taskResult = preTask.call();
                if (taskResult != null) {
                    TaskResult formatResult = null;
                    for (JobResult jobResult : jobResults) {
                        formatResult = TaskResultFactory.transferTaskResult(taskResult.taskType, taskResult, jobResult.getFormat(), jobConfig);
                        if (formatResult != null) {
                            jobResult.addTaskResult(formatResult);
                        }
                    }
                }
            }
            for (ApkTask task : taskList) {
                task.init();
            }
            List<Future<TaskResult>> futures = executor.invokeAll(taskList, timeoutSeconds, TimeUnit.SECONDS);
            for (Future<TaskResult> future : futures) {
                TaskResult taskResult = future.get();
                if (taskResult != null) {
                    TaskResult formatResult = null;
                    for (JobResult jobResult : jobResults) {
                        formatResult = TaskResultFactory.transferTaskResult(taskResult.taskType, taskResult, jobResult.getFormat(), jobConfig);
                        if (formatResult != null) {
                            jobResult.addTaskResult(formatResult);
                        }
                    }
                }
            }
            executor.shutdownNow();
    
            for (JobResult jobResult : jobResults) {
                jobResult.output();
            }
            Log.d(TAG, "parse apk end, try to delete tmp un zip files");
            FileUtils.deleteDirectory(new File(jobConfig.getUnzipPath()));
    
        } catch (Exception e) {
            Log.e(TAG, "Task executor execute with error:" + e.getMessage());
            throw e;
        }
    }
    

    该函数45行,分开看还是很好理解的。

    • 第一个for循环。执行预处理列表任务,主要是解压目标APK的任务,并输出结果
    • 中间两个for循环及相关部分。初始化参数配置指定的每个检查任务;executor多线程执行每个任务;将每个任务的检查结果依次添加到输出结果中;关闭executor
    • 第三个for循环及相关部分。结果输出工具把分析结果按照参数指定的格式依次输出到文件中;删除解压的APK文件。

小结

这里主要分析了Matrix/ApkChecker的代码结构和主要执行流程。可以大致总结出几点:

  • 总体上,代码在各层级命名、包划分、结构设计、函数实现等各方面可读性都很强
  • 利用继承和组合特性,使用工厂模式,让代码可拓展性也不错。比如新增一个分析功能,只需要实现一个ApkTask和相关参数类型即可;新增一种输出格式,只需要新增JobResult/TaskResult相关子类和关系即可
  • 参数解析部分代码有些冗余,不太利于拓展和阅读

下一篇会学习一下具体检查任务的实现。


以上所述就是小编给大家介绍的《Matrix-APKChecker源码分析(1)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Art and Science of Java

The Art and Science of Java

Eric Roberts / Addison-Wesley / 2007-3-1 / USD 121.60

In The Art and Science of Java, Stanford professor and well-known leader in CS Education Eric Roberts emphasizes the student-friendly exposition that led to the success of The Art and Science of C. By......一起来看看 《The Art and Science of Java》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

在线进制转换器
在线进制转换器

各进制数互转换器

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具