百度App性能优化工具篇 - Thor原理及实践

01 背景

App开发进程中,假如遇到一些疑难问题或许功用问题(如低端机卡顿),因为无法拿到更多体系的有效信息很难有效定位。这时,Hook不失为一种好的处理计划,Hook技能是在程序运转的进程中,动态的修正代码,植入自己的代码逻辑,修正原有程序履行流程的技能。Hook技能有如下几点才干:

耗时监控】在代码前后动态插入Trace打点,计算耗时;

功用监控】IO监控、内存监控、View绘制监控、大图检测等;

安全审查】Hook灵敏API(例如定位),用以安全评定;

逆向和脱壳】对病毒样本进行逆向和脱壳剖析;

Hook技能由来已久,现在业界Java和Native Hook都有不少优异的开源结构,可是假如咱们需求将Hook才干运用到线上,都或多或少有些问题,例如兼容性、安稳性、动态性等等。

鉴于此,咱们开发了一套Thor容器结构,供给规范的Hook接口,下降学习本钱,一起将开源结构依照接口适配成插件动态下发按需装置,确保Hook才干的齐备和轻量性,而且后续出现愈加优异以及自研的结构的能够无缝的接入和Hook才干拓宽,而且不需求上层事务代码和插件进行适配,确保兼容性。

02 现状

Android体系的编程言语首要分为Java和C/C++,Hook方向也首要分为Native和Java Hook两种,其间Native Hook原理也首要分为PLT / Inline Hook两大类,然后Java Hook也分为替换进口点Hook(Replace Entrypoint Hook)和类Inline Hook两大类。

Native 办法履行流程大约如下:

百度App性能优化工具篇 - Thor原理及实践

Native 办法履行进程中会先经过PLT表找到GOT表中函数大局偏移地址,然后履行其机器码指令,PLT Hook首要是指经过修正GOT中函数的大局偏移地址来到达Hook的意图,代表结构如:xHook、bHook等;Inline Hook则首要是指直接将函数履行的机器码指令进行修正和指令修正来到达Hook的意图,代表结构如:Android-Inline-Hook等。

GOT(Global Offset Table):大局偏移表用于记载在 ELF 文件中所用到的同享库中符号的肯定地址。

PLT(Procedure Linkage Table):进程链接表的作用是将位置无关的符号转移到肯定地址。当一个外部符号被调用时,PLT 去引证 GOT 中的其符号对应的肯定地址,然后转入并履行。

Java 办法履行流程大约如下:

百度App性能优化工具篇 - Thor原理及实践

Java 办法履行进程中会经过办法在虚拟机中对应的结构Method或ArtMethod结构体中的进口点(Entrypoint),来找到对应的字节码/机器码指令履行。替换进口点Hook(Replace Entrypoint Hook)是指替换Method/ArtMethod中的进口点来到达Hook的意图,代表结构如:Xposed、Dexposed、YAHFA等;类Inline Hook是指将进口点对应的字节码/机器码进指令进行修正和指令修正来到达Hook的意图,代表结构如:Epic等,因为安卓虚拟机的JIT/AOT机制的存在,函数履行地址或许会进行各种改变,所以通常会将字节码强行编译成机器码,然后统一经过修正机器码指令来Hook。

2.1 常见Native Hook结构

2.1.1 xHook结构

xHook结构经过PLT Hook计划来完结的,PLT Hook是经过直接修正GOT表,使得在调用该同享库的函数时跳转到的是用户自界说的Hook功用代码。流程如下:

百度App性能优化工具篇 - Thor原理及实践

了解PLT Hook的原理之后,知道该Hook办法有如下特点:

  • 因为修正的是GOT表中的数据,因而修正后,一切对该函数进行调用的当地就都会被Hook到。这个效果的影响范围是该PLT和GOT所处的整个so库。

  • PLT与GOT表中只是包括本ELF需求调用的同享库函数项目,因而不在PLT表中的函数无法Hook到(比方非export导出函数就无法Hook到)。

2.1.1 Andorid-Inline-Hook结构

Inline Hook的原理则是直接修正函数在.text实际履行的机器码来完结Hook,不仅对一切SO收效,还能Hook非export导出函数,补齐了PLT Hook办法的缺乏。流程如下:

百度App性能优化工具篇 - Thor原理及实践

可是因为你直接修正的是机器码指令,因为指令架构版别的差异以及后续要进行指令修正,容易有兼容性的问题。

2.2 常见JavaHook结构

2.2.1 Dexposed结构

Dexposed结构只支撑Dalvik虚拟机,此虚拟机经过Method结构体中accessFlags字段来判别当时办法是字节码仍是机器码。该结构经过修正accessFlags字段为ACC_NATIVE,将Java原办法注册为Native办法,调用时会先调用Native Hook办法,再反射调用Java原办法来完结Hook的意图,流程图如下所示:

百度App性能优化工具篇 - Thor原理及实践

2.2.2Epic结构

Epic结构则是在Dexposed的基础上,添加了对ART虚拟机Hook的才干。因为ART虚拟机的复杂性(AOT和JIT),Java代码履行的进口或许随时都在改变,假如经过ArtMethod中的entry_point_from_quick_compiled_code_字段进口进行Hook,或许会产生不可预期的溃散。Epic则是在 Wifeld, Marvin 的论文ArtHook: Callee-side Method Hook Injection on the New Android Runtime ART基础上做了完结,大约思路是把entry_point_from_quick_compiled_code_指向的机器码地址(未编译的字节码也会强制编译成机器码,类似于Inline Hook)进行修正,跳转到跳板代码,然后经过跳转代码进行分发,调用Hook办法之后再调用原办法,来到达Hook的意图。流程图如下:

百度App性能优化工具篇 - Thor原理及实践

2.3 常见结构比照

百度App性能优化工具篇 - Thor原理及实践

经过剖析和比照可知,开源结构存在比较典型的几个问题如下:

  • Hook才干不齐备:无法一起满意一切的Hook场景(Java Hook和Native Hook);

  • 兼容性问题:因为现有结构或许存在各式各样的安稳性问题,导致假如后续替换Hook结构,则一切的事务Hook逻辑都要修正存在兼容性问题;

  • 不支撑动态Hook:只能将代码内置到主包中,无法动态下发装置完结动态Hook;

  • 没有容错机制:大部分结构都有安稳性问题且没有容灾机制,假如导致运用溃散,会导致灾难性的结果。

03 计划选型

从现有情况来看,假如一起需求Java/Native Hook的才干,那么至少需求集成两个结构,事务代码也只能在主包中编写,添加包体积。其次假如替换运用愈加优异或许自研的结构时,一切的事务代码也要跟着修正,学习和适配兼容的本钱巨大。最终Hook结构导致的溃散,因为没有动态才干和容灾机制也只能从头发布运用和铺渠道,影响用户体会。

尽管每个结构都有各自的一些问题,可是要求咱们从头开始开发一款一起支撑Java和Native Hook的结构,没有安稳性问题而且兼容一切安卓版别、轻量且容灾的结构,重复造轮子而且ROI太低,所以咱们要开发自己的一套容器结构,取利益补短板,充分利用好已有的结构来完结目标。

百度App作为超级App,本身就是一个航空母舰,容器结构要在其上线至少需求到达以下几点要求:

  • 齐备性:需求支撑一切的Hook才干(Java和Native Hook),能够掩盖一切代码范围;

  • 兼容性:插件确保向后兼容,即便替换底层Hook结构,事务完全无感知,不需求从头学习和适配新的Hook结构;

  • 轻量动态性:体积要尽量确保轻量,这关于手百尤为重要,而且支撑经过云控下发的办法动态装置运转;

  • 容灾性:产生连续发动溃散时能够自封闭康复,不会持续影响线上用户。

04 Thor揭秘

为了满意上述要求,咱们开发了Thor容器结构,供给规范的Hook接口,包括Java和Native Hook接口,事务方不需求关怀底层完结逻辑(好像虚拟文件体系VFS),只需求了解如何运用这些接口即可,极大的下降学习接入本钱。一起将安稳的开源结构依照接口适配成插件,将这些Hook才干进行笼统,按需动态的装置加载,确保Hook才干的齐备性和轻量性。而且后续出现愈加优异以及自研的结构的能够无缝的接入,对上层也是无感知的,不需求上层事务代码和插件进行适配,很好的确保了兼容性。

4.1 Thor整体结构

4.1.1 Thor架构图

百度App性能优化工具篇 - Thor原理及实践

  • 支撑事务:支撑了低端机、隐私合规、OOM和流水线等多个事务;

  • Thor笼统层:首要包括Java / Native Hook和Thor Module的事务模块等笼统层接口;

  • 运用层插件:包括了SP、IO、线程、内存等基础插件或许事务相关插件,其适配完结了Thor Module的事务模块接口;

  • 完结层插件:Epic(Java Hook)、xHook(PLT Hook)、Android-Inline-Hook(Inline Hook)或许自研等插件,其适配完结了Java / Native Hook接口;

  • Thor结构

  • 插件模块:支撑自主开发插件,支撑插件热插拔,能够经过内置或云控动态下发,即时收效;维护和调度插件的生命周期;

  • 沙盒模块:支撑在沙盒进程装置插件,不影响主进程,重启收效;

  • 校验模块:支撑对插件进行安全校验,确保插件来历安全性;

  • 插件办理界面:支撑对已有插件动态装置和卸载的操控办理界面。

Thor完结层插件和Thor运用层插件都是apk的方式存在,可是也能够以组件源码的方式集成打包到宿主中。

4.2 Thor中心优势

4.2.1易用性

Thor只开发笼统层接口,底层完结对事务是不可见的,不需求重复学习,这样最大程度的确保了易用性。Java/Native Hook都供给了规范的接口供事务方运用,接口如下:

  • Java Hook接口**(Thor供给Java Hook才干的接口)**
public interface IHookEntity {
    ......
    /**
     * Hook指定的办法
     *
*@paramhookedMethod 待Hook的办法Method目标
     * @param hookCallback Hook回调{@link IHookCallback}
     */
    void hookMethod(Member hookedMethod, IHookCallback hookCallback);
    ......
}
假如是Java Hook运用方只需求直接运用该接口的才干即可;假如是才干供给方,则需求将Java Hook才干注入到Thor笼统层的Java Hook接口完结中。
  • Native Hook接口(Thor供给Native Hook才干的接口,包括PLT Hook和Inline Hook)
struct thor_abstract {    // 函数界说:PLT Hook完结结构的函数指针    // lib_name            被Hook的so库的称号    // symbol              被Hook的函数名    // hook_func           Hook办法    // backup_func         原办法备份(函数指针)    int (*thor_plt_hook)(const char *lib_name, const char *symbol, void *hook_func, void **backup_func);    // 函数界说:Inline Hook完结结构的函数指针    // target_func         原办法    // hook_func           Hook办法    // backup_func         原办法备份(函数指针)    int (*thor_inline_hook)(void *target_func, void *hook_func, void **backup_func);    // PLT Hook二期(新增接口,支撑批量plt hook)    struct thor_plt_ext *plt_ext;};
假如是Nava Hook运用方只需求直接运用该接口的才干即可;假如是才干供给方,则需求将Nava Hook才干注入到Thor笼统层的Native Hook接口完结中。
  • Thor Module接口(Thor供给的事务模块接口)
public abstract class ThorModule implements IThorModule {    /**     * 调度插件的加载生命周期     */    public abstract void handleLoadModule();    /**     * 宿主通知和更新插件装备信息生命周期     */    public void onPluginFuncControl(PluginFuncInfo pluginFuncInfo) {    }}

首要供给给事务模块运用,假如需求运用Hook才干,直接在handleLoadModule子类完结中调用Thor的各个Hook才干即可(不是有必要运用的,Thor作为容器结构只是额定供给了Hook的才干而已)。

4.2.2 齐备性

该结构一起支撑Java / Native Hook的才干,具有齐备的Hook才干。上末节讲解了供给给事务方的Java/Native Hook和 Thor Module事务模块等笼统层接口,底层完结则依据接口进行适配之后,经过静态代码依靠注入或动态模块加载注入到笼统层完结中,这样Thor就具备了齐备的Hook才干。 Thor的 Java Hook 才干(类Xposed API) Hook Handler#dispatchMessage办法,代码如下:

ThorHook.findAndHookMethod(Handler.class, "dispatchMessage", new IHookCallback() {    @Override    public void beforeHookedMethod(IHookParam param) {        Message msg = (Message) param.getArguments()[0];        Log.d(TAG, ">>>>>>>>>>>dispatchMessage: " + msg);    }        @Override    public void afterHookedMethod(IHookParam param) {        Log.d(TAG, "<<<<<<<<<<<<dispatchMessage: ");    }}, Message.class);

持续看Thor#findAndHookMethod的逻辑,代码如下:

/**  * 寻觅办法并将其Hook,最终一个参数有必要是Hook办法的回调  **@paramclazzHook办法地点类的类称号*@parammethodNameHook办法名*@paramhookCallback回调{@linkIHookCallback}*@paramparameterTypesHook办法的参数类型*/publicstaticvoidfindAndHookMethod(Class<?>clazz,StringmethodName,IHookCallbackhookCallback,Class<?>...parameterTypes){......MethodmethodExact=ThorHelpers.findMethodExact(clazz,methodName,parameterTypes);hookMethod(methodExact,hookCallback);......}
ThorHook#findAndHookMethod经过类的类类型、函数名和参数,找到相应的Method,再调用ThorHook#hookMethod进行Hook,持续看如下代码:
/** * Hook指定的办法 * * @param hookedMethod 待Hook的办法Method目标 * @param hookCallback Hook回调{@link IHookCallback} */public static void hookMethod(Member hookedMethod, IHookCallback hookCallback) throws HookMethodException {    ......    CallbacksHandler callbacksHandler;    synchronized (sHookedMethodCallbacks) {        callbacksHandler = sHookedMethodCallbacks.get(hookedMethod);        if (callbacksHandler == null) { // 未Hook过的Method            callbacksHandler = new CallbacksHandler();            callbacksHandler.register(hookCallback);            sHookedMethodCallbacks.put(hookedMethod, callbacksHandler);        } else { // Hook过的Method,只需求注册回调即可            callbacksHandler.register(hookCallback);            return;        }    }        ThorManager.getInstance().getHookEntity().hookMethod(hookedMethod, callbacksHandler);}
多个事务方假如Hook了同一个java 办法,会被加到缓存中,Hook回调的时分再逐个进行分发;持续能够看到hookMethod最终调用到了getHookEntity#hookMethod办法,终究会调用到具体Java Hook结构完结的hookMethod办法,例如Epic的适配代码如下:
/** * Epic结构适配类 */public class EpicHookEntity implements IHookEntity {    @Override    public void hookMethod(Member hookedMethod, final IHookCallback hookCallback) {        // Epic Hook办法回调        XC_MethodHook xc_methodHook = new XC_MethodHook() {            @Override            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {                // 将Epic Hook办法信息包装成笼统层Hook办法信息                IHookParam hookParam = new EpicHookParam(param);                if (hookCallback != null) {                    // 调用before回调                    hookCallback.beforeHookedMethod(hookParam);                }            }            @Override            protected void afterHookedMethod(MethodHookParam param) throws Throwable {                // 将Epic Hook办法信息包装成笼统层Hook办法信息                IHookParam hookParam = new EpicHookParam(param);                if (hookCallback != null) {                    // 调用after回调                    hookCallback.afterHookedMethod(hookParam);                }            }        };        // Epic Hook Method        DexposedBridge.hookMethod(hookedMethod, xc_methodHook);    }}
Thor的 Native Hook 才干
运用PLT Hook 对应SO地点PLT表的open函数,Inline Hook puts办法,部分代码如下:
thor_abstract *impl = reinterpret_cast<thor_abstract *>(nativePtr);// plt hook openthor->thor_plt_hook(so_name, "open", (void *) ProxyOpen, (void **) &original_open);// inline hook putsimpl->thor_inline_hook((void *) puts, (void *) new_puts, (void **) &origin_puts);

依据4.2.1中的Native Hook接口可知,thor_plt_hook和thor_inline_hook成员都是函数指针,指针只要指向真实的Native Hook才干,代码才会收效,所以相应的Hook结构也需求依据Native Hook接口进行适配,例如xHook适配PLT Hook部分代码如下:

thor_abstract *thor = reinterpret_cast<thor_abstract *>(nativePtr);// plt hook函数指针赋值thor->thor_plt_hook = xhook_impl_plt_hook;.....// xhook适配部分代码int xhook_impl_plt_hook(const char *so_name, const char *symbol, void *new_func, void **old_func) {    void *soinfo = xhook_elf_open(so_name);    if (!soinfo) {        return -1;    }    if (xhook_hook_symbol(soinfo, symbol, new_func, old_func) != 0) {        return -2;    }    xhook_elf_close(soinfo);    return 0;}

Android-Inline-Hook适配Inline Hook接口部分示例代码如下:

// inline hook函数指针赋值thor->thor_inline_hook = impl_inline_hook;// andorid-inline-hook适配部分代码int impl_inline_hook(void *target_func, void *new_func, void **old_func) {    if (registerInlineHook((uint32_t) target_func, (uint32_t) new_func, (uint32_t **) old_func)) {        return -1;    }    if (inlineHook((uint32_t) target_func) != ELE7EN_OK) {        return -2;    }    return 0;}

咱们在运用这些底层Hook结构适配组件(插件)的进程中,也遇到了一些问题,例如Epic在Hook Handler#dispatchMessage的进程中,会产生不符合预期的溃散,可是在进一步调研了SandHook能够处理该问题之后,立刻就适配了SandHook的完结来处理问题,事务方的代码不需求做任何修正和适配,再例如xHook的作者新写了一款PLT Hook结构bHook,处理了xHook的一些问题(例如增量Hook,unHook才干等等),咱们也很快跟进对bHook结构进行了调研和适配,相同事务方也是无感知的,这两个比如从旁边面佐证了Thor容器结构具有杰出的兼容性和可扩展性。 一起同学们或许会有如下疑惑,假如Hook结构出问题,莫非只能去找更好的开源计划进行适配吗?有没有银弹呢?这其实就回到了计划选型时所说的,因为安卓的碎片化和复杂性,从头开始开发一款一起支撑Java和Native Hook的结构,没有安稳性问题而且兼容一切安卓版别、轻量且容灾的结构,重复造轮子而且ROI太低,所以咱们要开发自己的一套容器结构,取利益补短板,充分利用好已有的结构来完结目标,当然也不扫除在一切开源计划都不满意的情况下,进行深度二次开发或许自研底层Hook结构,不过这些对事务代码都不可见,不需求修正适配。

4.2.3轻量动态性

百度App作为一个航母级运用,关于包体积巨细仍是比较灵敏的,依据Google Store的数据,包体积每添加6M,就下降1%的转化率,影响巨大,所以Thor容器结构要尽或许的做到轻量,基于此,咱们需求把事务代码做成动态加载的插件,甚至是底层适配的Hook完结也要做成动态可加载的插件。 事务代码能够不在宿主中编写,只在插件代码中编写,然后将生成的插件动态下发到手机上,再经过插件加载模块动态加载收效。例如:在需求监控运用IO的情况下,下发IO插件和xHook插件到手机上装置,Hook IO操作(例如:open、read、write等),将不合理的IO操作上报给渠道,一起在不需求监控的时分动态卸载封闭即可。 插件动态加载收效的大致流程如下: Thor容器结构会对插件进行v2签名校验,确保插件来历的安全性;解析插件中的清单文件存储为info目标,包括插件包名、插件进口类、ABI List、插件版别等等;对插件中的SO进行释放,否则classloader会找不到插件中的SO;创立自界说的ThorClassLoader进行插件类加载,会先加载插件中的类再加载宿主中的类,部分代码如下:

/** * 先加载Thor插件中的类,再加载宿主中的类 * * @param name */@Overrideprotected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {    Class<?> clazz = null;    try {        // 加载插件中的类        clazz = findOwnClass(name);    } catch (ClassNotFoundException ignored) {        // ignored    }    if (clazz != null) {        return clazz;    }    // 加载宿主中的类    return mHostClassLoader.loadClass(name);}

实例化插件进口类并判别其接口类型,注入相应的才干到Thor笼统层: 假如是Java Hook接口完结类,则注入Java Hook实例才干给Thor笼统层;假如是Native Hook接口完结类,则注入Native Hook实例才干给Thor笼统层;假如是Thor Module事务接口完结类,则将事务实例存储到map中,等候后续插件办理模块调度相应的生命周期。 大约流程图如下:

百度App性能优化工具篇 - Thor原理及实践
这里咱们或许会有以下疑问:

假如上层的事务层插件先装置,底层完结层插件后装置的情况怎么办?

Thor有一个pending形式会等到完结层装置收效之后,事务层的逻辑再开始履行收效; Android 8.0的classloader有namespace机制,不同的classloader加载相同SO,会有多份SO在内存中,这个时分如何将插件中Native Hook才干传递给Thor笼统层呢? 经过翻看源码,Binder调用中的Parcel类具有Native目标的内存指针,所以咱们也学习相同的办法,将Native目标内存指针地址经过Java层进行传递,然后运用具有相同内存布局的struct结构体进行转换,这样就能够拿到Native Hook完结了。

4.2.4 容灾性

Hook技能毕竟是一个比较hack的技能,谁也无法确保百分百的兼容和安稳性,所以咱们要针对这种特殊的溃散情况进行兜底,将该结构或许形成的影响降到最低。现在有三个容灾才干: Thor容器结构在及时性要求不高的情况下,支撑沙盒进程装置。假如装置进程中产生了溃散,不会影响主进程,用户无感知,而且会主动回滚插件进行止损;Thor容器结构会结合安全形式,能够监控连续发动溃散次数,假如超越阈值,就主动封闭Thor结构,快速自康复及时止损;经过百度内部的功用渠道监控Thor相关溃散,能够经过云控动态封闭Thor结构。 经过这三个容灾才干,根本能够确保百度App不会因为Thor容器结构产生大规模的溃散影响用户体会,能够较好的办理危险。

05 事务实践案例

Thor结构作为一套动态插件容器基础设施,真实让其起作用的是丰厚的插件生态(如IO、内存、线程、隐私等等),能够依据实际需求,大胆的发挥想象,开发适合事务场景的插件。现在该结构能够运用于线下RD开发、线下流水线和线上云控敞开,因为篇幅约束,摘选其间一些案例叙述。

5.1线程插件

因为在开发进程中顺手就能够创立一个线程运转,也没有强制约束运用线程池,这样会导致许多游离线程,线程过多不仅会进步内存运用导致IO扩大和OOM溃散,而且有频频的上下文切换会导致发动和流通度问题。线程插件则经过Thor结构的PLT Hook才干Hook libart.so库中的pthead_create的函数,来监控线程的创立。中心代码如下:

// 原始被办法函数指针static void *(*origin_pthread_create)(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg) = NULL;// Hook之后的Proxy办法void *proxy_pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg) {    ......    // 调用原始办法    void *ret = origin_pthread_create(thread, attr, start_routine, arg);    // 打印Java堆栈    printJavaStackTrace();    return ret;}void doHook(long nativePtr){    thor_abstract *impl = reinterpret_cast<thor_abstract *>(nativePtr);    // plt hook pthread_create    impl->thor_plt_hook("libart.so", "pthread_create", (void *) proxy_pthread_create, (void **) &origin_pthread_create);}}

Hook完结之后,会在创立线程的进程中先调用proxy_pthread_create的署理办法再调用原始的创立线程办法,在署理办法中经过反射打印创立当时线程的Java堆栈。在百度App发动阶段经过线程插件监控记载发现有100+个SP线程,和50+非线程池办理的线程,严重影响发动速度和用户体会。协助组内同学进行优化后(SP迁移KV组件,一切线程经过线程池办理),下降发动进程中线程数100+,优化TTI(Time To Interactive) 1s+。

5.2IO插件

因为在开发进程中有同学会把一些IO操作在主线程中履行,例如文件读写、网络传输,这样会导致主线程卡顿,影响发动速度、流通度等,即便是小文件也或许因为内存缺乏和磁盘缺乏等原因导致IO读写扩大,然后导致长耗时的IO,一起还有一些不合理的IO,例如:读写buffer过小会导致频频的体系调用影响功用,以及重复读同一个文件等。IO插件则经过Thor结构的 PLT Hook才干 Hook IO操作(open、read和write、close等),用来记载监控主线程不合理的IO。中心代码如下:

......thor->thor_plt_hook(so_name, "open", (void *) ProxyOpen, (void **) &original_open);thor->thor_plt_hook(so_name, "read", (void *) ProxyRead, (void **) &original_read);thor->thor_plt_hook(so_name, "write", (void *) ProxyWrite, (void **) &original_write);thor->thor_plt_hook(so_name, "close", (void *) ProxyClose, (void **) &original_close);......

调用open时会先调用ProxyOpen,ProxyOpen中会存储fd(文件描述符)和IOInfo的map映射联系,后续的ProxyRead、ProxyWrite和ProxyClose则经过fd来完善IOInfo的信息,IOInfo部分字段如下:

class IOInfo {    public:        // 文件路径        const std::string file_path_;        // 开始时间        int64_t start_time_s_;        // buffer巨细        long buffer_size_ = 0;        // 连续读写次数        long max_continual_rw_cnt_ = 0;        // 文件巨细        long file_size_ = 0;        // 总耗时        long total_cost_s_ = 0;};

在最终文件Close的时分经过剖析IOInfo即可分分出不合理的IO操作(例如主线程IO耗时过长、IO的buffer过小(导致体系调用增多)、重复读等)。在百度App发动进程中经过IO插件监控记载发现有20+不合理的IO操作,与各个事务方的同学进行协同和优化,终究发动速度TTI优化400ms+,提升了用户体会。

5.3隐私合规插件

因为个人信息法的公布,运用不能够在隐私弹窗确认前获取用户个人信息,基于此,隐私合规插件运用Thor结构的Java Hook的才干,监控记载隐私弹窗前不合理的隐私API调用(例如定位、WI-FI、蓝牙等等),部分代码如下:

// hook getDeviceIdThorHook.findAndHookMethod(TelephonyManager.class, "getDeviceId", new IHookCallbackImpl(), String.class);

隐私合规插件结合了手百内部通用防劣化流水线的才干(这里不打开讲解),每天主动编译打包内置隐私合规插件,然后主动在真机上测验,监控记载隐私弹框前的隐私问题,最终主动剖析、分发问题卡片给相应的事务同学进行修正,有效的规避了合规危险,防止被下架整改;

5.4内存插件

内存优化是功用和安稳性优化中的一大课题,假如内存占用过大,轻则导致频频GC形成卡顿,重则内存溢出导致OOM运用溃散。内存插件则经过Thor结构PLT Hook的才干,监控记载Java堆内存和Native内存(监控 malloc 和 free等函数)。内存插件现在有两个运用场景: 结合线下流水线的才干,每天主动编译打包内置内存插件,然后在真机上运用monkey随机测验,在内存水位高时dump hprof文件,并进行裁剪(经过PLT Hook write办法完结,参考Tailor在hprof文件写入进程中过滤不需求的信息),最终主动分分出内存走漏问题和大目标问题,主动分发问题给相应的事务同学进行修正,将内存问题前置,防止问题上线影响用户体会。结合线上Thor丰厚的云控才干,动态下发到OOM用户手机上敞开内存监控才干,然后回捞上报相关的数据进行问题剖析、分发,处理线下不易复现的线上OOM溃散问题。

06 总结

Hook这个论题由来以久,结构种类繁多,可是没有一款全面性、动态性以及兼容性好的结构,可是正是有这些优异的结构(Xposed、Dexposed、Epic、xHook等),咱们才干学习和学习其优异的设计和理念,补齐缺乏,Thor只是在这条道路上迈出了一小步,后边需求愈加完善和夯实Thor基础设施,而且丰厚插件生态,在Android功用和安稳性治理上添砖加瓦。

——————END ————————

相关链接:

[1] Dexposed链接:github.com/alibaba/dex…

[2] ArtHook论文链接:publications.cispa.saarland/143/

[3] Epic链接:github.com/tiann/epic

[4] xHook链接:github.com/iqiyi/xHook

[5] Android-Inline-Hook链接:github.com/ele7enxxh/A…

[6] Tailor链接:github.com/bytedance/t…

[7] Matrix链接:github.com/Tencent/mat…