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 办法执行流程大略如下:

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 办法执行流程大略如下:

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性能代码。流程如下:

理解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办法的有余。流程如下:

然而因为你间接批改的是机器码指令,因为指令架构版本的差别以及后续要进行指令修复,容易有兼容性的问题。

**2.2 常见Java Hook框架

**2.2.1 Dexposed框架

Dexposed框架只反对Dalvik虚拟机,此虚拟机通过Method构造体中accessFlags字段来判断以后办法是字节码还是机器码。该框架通过批改accessFlags字段为ACC\_NATIVE,将Java原办法注册为Native办法,调用时会先调用Native Hook办法,再反射调用Java原办法来实现Hook的目标,流程图如下所示:

**2.2.2 Epic框架

Epic框架则是在Dexposed的根底上,减少了对ART虚拟机Hook的能力。因为ART虚拟机的复杂性(AOT和JIT),Java代码执行的入口可能随时都在变动,如果通过ArtMethod中的entry\_point\_from\_quick\_compiled\_code\_字段入口进行Hook,可能会产生不可预期的解体。Epic则是在 Wißfeld, Marvin 的论文ArtHook: Callee-side Method Hook Injection on the New Android Runtime ART根底上做了实现,大略思路是把entry\_point\_from\_quick\_compiled\_code\_指向的机器码地址(未编译的字节码也会强制编译成机器码,相似于Inline Hook)进行批改,跳转到跳板代码,而后通过跳转代码进行散发,调用Hook办法之后再调用原办法,来达到Hook的目标。流程图如下:

**2.3 常见框架比照

通过剖析和比照可知,开源框架存在比拟典型的几个问题如下:

  • 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架构图

  • 撑持业务:撑持了低端机、隐衷合规、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指定的办法     *     * @param hookedMethod 待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办法的回调  *  * @param clazz          Hook办法所在类的类名称  * @param methodName     Hook办法名  * @param hookCallback   回调{@link IHookCallback}  * @param parameterTypes Hook办法的参数类型  */public static void findAndHookMethod(Class<?> clazz, String methodName,                                     IHookCallback hookCallback, Class<?>... parameterTypes) {    ......                                     Method methodExact = 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中,期待后续插件治理模块调度相应的生命周期。
大略流程图如下:

这里大家可能会有以下疑难:
如果下层的业务层插件先装置,底层实现层插件后装置的状况怎么办?

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.2 IO插件

因为在开发过程中有同学会把一些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链接:https://github.com/alibaba/de...
[2] ArtHook论文链接:http://publications.cispa.saa...
[3] Epic链接:https://github.com/tiann/epic
[4] xHook链接:https://github.com/iqiyi/xHook
[5] Android-Inline-Hook链接:https://github.com/ele7enxxh/...
[6] Tailor链接:https://github.com/bytedance/...
[7] Matrix链接:https://github.com/Tencent/ma...