Android性能优化-实践篇:Frida监测Binder调用

一、前言

在目前的卡顿优化中,主线程的Binder调用优化是一个绕不过的问题,实际上,在目前的工具上,例如使用Perfetto,可以看到binder_transaction,针对某个特定的binder_transaction,也可以找到对端,但是如果想要知道对端的name、code甚至是堆栈,就是一件非常困难的事情。

二、eBPF+golang监控Binder调用

此前,在看雪上面看到一篇文章,原创btrace:binder_transaction+eBPF+Golang实现通用的Android APP动态行为追踪工具,此文通过eBPF+golang实现了对Binder调用的监测,但是只能拿到调用的name+function,如下图所示。

这是一个可以直接push到Android系统执行的工具,但是在使用此工具的时候,发现了一些问题

  • 1、不同手机上面的Code和Function映射不一致,需要多次编译
  • 2、只有部分应用可以正常映射,例如抖音、微信,别的应用一概不行。

第二个问题经过debug发现是由于拿到的data.ptr.buffer是内核态地址,但是此处不可能是内核态地址,而是用户态的,对于内部的原理不清楚,但是通过mask高位就可以正常读取了,猜测是内核做了一次转换。

修改如下:

c++ 复制代码
bpf_probe_read_user(binder_transaction_event->chunk_data, probe_read_size, (void *)((data.ptr.buffer + i * CHUNK_SIZE) & 0x0000FFFFFFFFFFFF));

编译后重新push,测试可以使用。

具体的原理可以参考原文,大致的原理如下:

  • 1、通过eBPF挂载binder_transaction
  • 2、解析Parcel数据,拿到其中的ServerName和Code
  • 3、通过映射拿到Code对应的Function
  • 4、以可读的形式输出

eBPF也是非常强大的工具,但是偏底层,这里我们不再赘述,以后有机会再做分享。

三、Frida+Binder

对于性能优化来讲,我们想要的几个信息是:

  • 1、拿到ServerName+Function
  • 2、拿到耗时
  • 3、拿到堆栈

目前前面的工具已经可以满足第一点,但是后面的不好拿到,那么Frida能做到吗?答案是肯定的。

3.1 分析

首先,观察aidl调用,可以看到第一个调用的方法是writeInterfaceToken,这个方法完成了对ServerName的写入,所以我们可以通过这个拿到ServerName,将ServerName与Parcel做映射。

基本上所有的Java层Binder调用都要经过BinderProxy,所以我们可以Hook BinderProxy的transact方法拿到Code、Parcel,通过从映射里面取数据,我们直接拿到ServerName,这里还有Code信息。

实测解析会出现一些问题,但是目前我们是在Java层进行Hook,所以我们直接hook writeInterfaceToken,在这里直接保存Parcel对ServerName的映射。

然后,Frida可以直接无视私有类,直接通过ClassLoader加载出BinderTransactionNameResolver类,直接进行方法转换,拿到FunctionName。

最后,我们打印出方法前后的方法耗时,以及堆栈信息。

至此,我们就拿到了所有信息

3.2 实现

这里我直接贴一下实现:

JavaScript 复制代码
Java.perform(() => {
    const BinderProxy = Java.use("android.os.BinderProxy");
    const Parcel = Java.use("android.os.Parcel");
    const ResolverClass = Java.use("com.android.internal.os.BinderTransactionNameResolver");
    const binderResolver = ResolverClass.$new();
    const Thread = Java.use("java.lang.Thread");
    var parcelMap = new Map();
    Parcel.writeInterfaceToken.implementation = function (name) {
        parcelMap[this] = name;
        return this.writeInterfaceToken(name);
    }
    BinderProxy.transact.overload('int', 'android.os.Parcel', 'android.os.Parcel', 'int').implementation = function (code, data, reply, flags) {
        let log = "\n=== [Binder Call Detected] ===\n";
        log += "→ Code :", code;
        const thread = Thread.currentThread();
        log += "→ Thread:" + thread.getName() + "\n";
        try {
            var name = parcelMap[data];
            log += "→ InterfaceToken:" + name + "\n";
            const stubClassName = name + "$Stub";
            let stubClass = null;
            try {
                stubClass = Java.use(stubClassName);
                const methodName = binderResolver.getMethodName(stubClass.class, code);
                log += "→ Method Name:" + methodName + "\n";
            } catch (e) {
                console.warn("⚠️ Stub class not found or getMethodName failed:", stubClassName);
            }
            const Throwable = Java.use("java.lang.Throwable");
            const stack = Throwable.$new().getStackTrace();
            var startTime = Date.now();
            var ret = this.transact(code, data, reply, flags);
            log += `Binder call cost : ${Date.now() - startTime}ms`;
            if (thread.getName() == "main") {
                log += "→ Java Stack:\n";
                for (let i = 0; i < stack.length; i++) {
                    log += "    at " + stack[i].toString() + "\n";
                }
            }
            console.log(log);
            return ret;
        } catch (e) {
            console.error("❌ Error parsing Parcel manually:", e);
        }
        return this.transact(code, data, reply, flags);
    };
});

结果如下:

四、总结

到此,我们拿到了检测Binder调用的所有信息,对于卡顿优化,这是个很有用的输入,可以检测到我们应用是否存在异常的在主线程的Binder调用。

但是Frida只是用于线下检测,如果要用线上监听的话,需要考虑别的方式实现。

参考

1、原创btrace:binder_transaction+eBPF+Golang实现通用的Android APP动态行为追踪工具

相关推荐
私人珍藏库1 天前
[Android] 美颜通 -实时视频通话直播美颜
智能手机·app·音视频·软件·多功能
私人珍藏库2 天前
[Android] 聊天记录微备份 -聊天记录备份+本地数据备份
android·人工智能·app·软件·多功能
私人珍藏库2 天前
[Android] PocketPal -本地离线AI助手+大模型部署神器
android·人工智能·app·软件·多功能
正经教主3 天前
开发一个APP的方案选择(一)
app
私人珍藏库4 天前
[Android] VOKA -人体解剖3D图谱+医学人体解剖
3d·智能手机·app·工具·软件·多功能
私人珍藏库4 天前
[Android] Zone悬浮球 PRO2.0.2- 玩机悬浮窗+安卓纯净
智能手机·app·工具·软件·多功能
私人珍藏库5 天前
[Android] 滔滔对讲3.0.8.1-手机变对讲机+海量频道+高级版
智能手机·app·工具·软件·多功能
私人珍藏库5 天前
[Android] 发票制作器-内置多行业专业模板
android·人工智能·app·软件·多功能
老白讲技术7 天前
2026年国内APP开发与软件定制服务商能力观察:从AI应用到行业系统开发
大数据·人工智能·ai·app·软件需求·app开发
私人珍藏库7 天前
[Android] 一木百宝箱-万能百宝箱+抖音去水印等几百种功能
android·人工智能·app·软件·多功能