Android 9上有了binder_calls_stats服务,提供了java层的binder统计,
Android中的Binder Call Stats(Binder调用统计)是一项用于监控和记录Android系统中Binder通信的统计信息的功能。Binder是Android中的一种进程间通信(IPC)机制,用于在不同的进程之间传递数据和调用方法。
Binder Call Stats提供了有关Binder调用的性能和统计数据,帮助开发人员分析和优化系统的性能。它可以提供以下信息:
-
Binder调用次数:统计Binder方法被调用的次数,包括进程间的远程调用和本地调用。
-
Binder调用耗时:记录Binder方法的执行时间,包括调用传输数据的时间和远程进程执行方法的时间。
-
Binder调用堆栈跟踪:跟踪Binder调用的堆栈信息,可以帮助开发人员确定调用路径和定位性能瓶颈。
-
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驱动程序的各种统计和状态信息,包括:
-
总体信息:包括Binder线程池的大小、当前正在等待的线程数等。
-
事务计数:显示有关Binder事务(包括进程间通信和本地调用)的计数信息,例如总事务数、活动事务数、等待事务数等。
-
线程信息:列出了所有活动的Binder线程的详细信息,包括线程ID、所属进程、线程状态等。
-
回收信息:显示已回收的Binder对象和节点的数量。
通过读取binder_status
文件,您可以获取有关Binder驱动程序的运行状况和性能指标的信息,这对于调试和分析Binder相关问题非常有用。然而,由于它提供的信息非常底层和详细,需要一定的理解和背景知识才能正确解读和使用这些数据。
请注意,访问binder_status
文件需要root权限或系统签名,并且在正常情况下,一般用户不需要直接访问或操作该文件。