【Android】关于binder_calls_stats服务

Android 9上有了binder_calls_stats服务,提供了java层的binder统计,

Android中的Binder Call Stats(Binder调用统计)是一项用于监控和记录Android系统中Binder通信的统计信息的功能。Binder是Android中的一种进程间通信(IPC)机制,用于在不同的进程之间传递数据和调用方法。

Binder Call Stats提供了有关Binder调用的性能和统计数据,帮助开发人员分析和优化系统的性能。它可以提供以下信息:

  1. Binder调用次数:统计Binder方法被调用的次数,包括进程间的远程调用和本地调用。

  2. Binder调用耗时:记录Binder方法的执行时间,包括调用传输数据的时间和远程进程执行方法的时间。

  3. Binder调用堆栈跟踪:跟踪Binder调用的堆栈信息,可以帮助开发人员确定调用路径和定位性能瓶颈。

  4. Binder调用的进程和线程信息:记录Binder调用发生的进程和线程信息,有助于分析系统中不同组件之间的通信情况。

通过分析Binder Call Stats,开发人员可以识别性能瓶颈、优化IPC通信,改进应用程序的响应性能和资源利用率。

要收集Binder Call Stats,开发人员可以使用Android系统提供的工具和API,例如使用adb shell命令进行监测,或者使用Trace类和Debug类提供的方法进行手动埋点和记录统计数据。

需要注意的是,Binder Call Stats对于普通应用程序开发人员来说可能并不常用,主要用于系统级开发和性能调优。

java 复制代码
public class BinderCallsStatsService extends Binder {
30
31    private static final String TAG = "BinderCallsStatsService";
32
33    private static final String PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING
34            = "persist.sys.binder_calls_detailed_tracking";
35
36    public static void start() {
37        BinderCallsStatsService service = new BinderCallsStatsService();
38        ServiceManager.addService("binder_calls_stats", service);
39        boolean detailedTrackingEnabled = SystemProperties.getBoolean(
40                PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING, false);
41
42        if (detailedTrackingEnabled) {
43            Slog.i(TAG, "Enabled CPU usage tracking for binder calls. Controlled by "
44                    + PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING
45                    + " or via dumpsys binder_calls_stats --enable-detailed-tracking");
46            BinderCallsStats.getInstance().setDetailedTracking(true);
47        }
48    }
49
50    public static void reset() {
51        Slog.i(TAG, "Resetting stats");
52        BinderCallsStats.getInstance().reset();
53    }
54
55    @Override
56    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
57        if (args != null) {
58            for (final String arg : args) {
59                if ("-a".equals(arg)) {
60                    // We currently dump all information by default
61                    continue;
62                } else if ("--reset".equals(arg)) {
63                    reset();
64                    pw.println("binder_calls_stats reset.");
65                    return;
66                } else if ("--enable-detailed-tracking".equals(arg)) {
67                    SystemProperties.set(PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING, "1");
68                    BinderCallsStats.getInstance().setDetailedTracking(true);
69                    pw.println("Detailed tracking enabled");
70                    return;
71                } else if ("--disable-detailed-tracking".equals(arg)) {
72                    SystemProperties.set(PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING, "");
73                    BinderCallsStats.getInstance().setDetailedTracking(false);
74                    pw.println("Detailed tracking disabled");
75                    return;
76                } else if ("-h".equals(arg)) {
77                    pw.println("binder_calls_stats commands:");
78                    pw.println("  --reset: Reset stats");
79                    pw.println("  --enable-detailed-tracking: Enables detailed tracking");
80                    pw.println("  --disable-detailed-tracking: Disables detailed tracking");
81                    return;
82                } else {
83                    pw.println("Unknown option: " + arg);
84                }
85            }
86        }
87        BinderCallsStats.getInstance().dump(pw);
88    }
89}
90

可以看到,是通过BinderCallsStats来进行统计的,而BinderCallsStats通过在Java层Binder对象中的使用来进行记录,

frameworks/base/core/java/android/os/Binder.java

java 复制代码
    // Entry point from android_util_Binder.cpp's onTransact
714    private boolean execTransact(int code, long dataObj, long replyObj,
715            int flags) {
716        BinderCallsStats binderCallsStats = BinderCallsStats.getInstance();
717        BinderCallsStats.CallSession callSession = binderCallsStats.callStarted(this, code);
718        Parcel data = Parcel.obtain(dataObj);
719        Parcel reply = Parcel.obtain(replyObj);
720        // theoretically, we should call transact, which will call onTransact,
721        // but all that does is rewind it, and we just got these from an IPC,
722        // so we'll just call it directly.
723        boolean res;
724        // Log any exceptions as warnings, don't silently suppress them.
725        // If the call was FLAG_ONEWAY then these exceptions disappear into the ether.
726        final boolean tracingEnabled = Binder.isTracingEnabled();
727        try {
728            if (tracingEnabled) {
729                Trace.traceBegin(Trace.TRACE_TAG_ALWAYS, getClass().getName() + ":" + code);
730            }
731            res = onTransact(code, data, reply, flags);
732        } catch (RemoteException|RuntimeException e) {
733            if (LOG_RUNTIME_EXCEPTION) {
734                Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e);
735            }
736            if ((flags & FLAG_ONEWAY) != 0) {
737                if (e instanceof RemoteException) {
738                    Log.w(TAG, "Binder call failed.", e);
739                } else {
740                    Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e);
741                }
742            } else {
743                reply.setDataPosition(0);
744                reply.writeException(e);
745            }
746            res = true;
747        } finally {
748            if (tracingEnabled) {
749                Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
750            }
751        }
752        checkParcel(this, code, reply, "Unreasonably large binder reply buffer");
753        reply.recycle();
754        data.recycle();
755
756        // Just in case -- we are done with the IPC, so there should be no more strict
757        // mode violations that have gathered for this thread.  Either they have been
758        // parceled and are now in transport off to the caller, or we are returning back
759        // to the main transaction loop to wait for another incoming transaction.  Either
760        // way, strict mode begone!
761        StrictMode.clearGatheredViolations();
762        binderCallsStats.callEnded(callSession);
763
764        return res;
765    }

而更加底层的统计,可以查看/dev/binder 里面的binder_status

binder_status是Android系统中的一个特殊文件,用于提供有关Binder驱动程序状态的信息。该文件位于/proc/binder/status路径下,只有在具有root权限或系统签名的设备上才能访问。

binder_status文件提供了有关Binder驱动程序的各种统计和状态信息,包括:

  1. 总体信息:包括Binder线程池的大小、当前正在等待的线程数等。

  2. 事务计数:显示有关Binder事务(包括进程间通信和本地调用)的计数信息,例如总事务数、活动事务数、等待事务数等。

  3. 线程信息:列出了所有活动的Binder线程的详细信息,包括线程ID、所属进程、线程状态等。

  4. 回收信息:显示已回收的Binder对象和节点的数量。

通过读取binder_status文件,您可以获取有关Binder驱动程序的运行状况和性能指标的信息,这对于调试和分析Binder相关问题非常有用。然而,由于它提供的信息非常底层和详细,需要一定的理解和背景知识才能正确解读和使用这些数据。

请注意,访问binder_status文件需要root权限或系统签名,并且在正常情况下,一般用户不需要直接访问或操作该文件。

相关推荐
大白要努力!2 小时前
Android opencv使用Core.hconcat 进行图像拼接
android·opencv
天空中的野鸟3 小时前
Android音频采集
android·音视频
小白也想学C4 小时前
Android 功耗分析(底层篇)
android·功耗
曙曙学编程4 小时前
初级数据结构——树
android·java·数据结构
闲暇部落6 小时前
‌Kotlin中的?.和!!主要区别
android·开发语言·kotlin
诸神黄昏EX8 小时前
Android 分区相关介绍
android
大白要努力!9 小时前
android 使用SQLiteOpenHelper 如何优化数据库的性能
android·数据库·oracle
Estar.Lee9 小时前
时间操作[取当前北京时间]免费API接口教程
android·网络·后端·网络协议·tcp/ip
Winston Wood9 小时前
Perfetto学习大全
android·性能优化·perfetto
Dnelic-12 小时前
【单元测试】【Android】JUnit 4 和 JUnit 5 的差异记录
android·junit·单元测试·android studio·自学笔记