Statsd In android 9 (1)
android系统中有很多不同功能的日志,如dumpsys dumpstate。anr以及crash时候也有单点的日志。然而,
一些系统的问题,如性能功耗以及稳定性问题是由于不明确的单点的缺陷或者故障扩散导致的。仅靠最后问题发生
时的日志有时难以定位问题,还有一些问题,例如黑屏,原因有很多种,所以能否将可能相关的事件汇聚到一处,
做数据分析也会方便一些。大概基于这种目的,android p版本中新增一种日志上报方式,接口位于:
新增一个用于处理统计数据的常驻进程 statsd
statsd 与logd一样使用sock收集日志
所有日志上报函数均直接使用入参写入sock,没有中间数据接口
statsd的收集在java以及native均有涉及,包含pull 以及 push两个模式
下面部分代码引用自 aosp android-9.0.0_r22
StatsLog接口类
StatsLog类继承于StatsLogInternal,而StatsLogInternal是在编译期由protobuf自动生成的,主要
是一些常量以及数据结构的定义。
StatsLog类中主要有3个接口,是通过binder调用到服务端:
还有从Internal类里继承而来的native方法,framework中上报的方法使用的是write,以及 write_non_chained
其他都是同名的重载函数,
最终调用的函数位于:
out/soong/.intermediates/frameworks/base/tools/stats_log_api_gen/statslog.h/gen/statslog.h
system/core/libstats/include/stats_event_list.h
stats_event_list.write
123456789101112131415161718 try_stats_write(int32_t code, char const* arg1, int64_t arg2){if (kStatsdEnabled) {stats_event_list event(kStatsEventTag);event << android::elapsedRealtimeNano();event << code;if (arg1 == NULL) {arg1 = "";}event << arg1;event << arg2;return event.write(LOG_ID_STATS);} else {return 1;}}
stats_event_list创建一个以事件为id的logger,并把信息写入,缓存,最后使用write_to_logger,
将android_log_context写入logger。
一开始以为通过binder调用写入事件,这里看起来为了提高性能使用的还是native的方法, 并且通过直接用函数
入参的方式来减少结构封包解包的性能开销。由于没有封包的过程,造成了参数不同的重载函数很多,这里使用
自动生成的方式生成了很多函数。所以这几个类都在 out/soong/.intermediates/里。
systlem/core/libstats/stats_event_list.h
12345678910111213141516171819 int write_to_logger(android_log_context ctx, log_id_t id) {int retValue = 0;if (WRITE_TO_LOGD) {retValue = android_log_write_list(ctx, id);}if (WRITE_TO_STATSD) {// log_event_list's cast operator is overloaded.int ret = stats_write_list(ctx);// In debugging phase, we may write to both logd and statsd. Prefer to// return statsd socket write error code here.if (ret < 0) {retValue = ret;}}return retValue;}
最后可以选择是直接将事件输出到 logd中还是输出到statsd中。当然,无论是logd或是statsd都是通过
sock写入的。
statsd服务
statsd 服务分为两个部分,一部分是java的服务代理,用于在java侧提供接口,并注册一些服务监听。
如应用安装更新等。
StatsCompanionService.java
123 traceBeginAndSlog("StartStatsCompanionService");mSystemServiceManager.startService(StatsCompanionService.Lifecycle.class);traceEnd();
另一部分运行在native的statsd中。
frameworks/base/cmds/statsd/src/main.cpp
1234567891011121314151617181920212223242526272829303132333435363738394041 // Set up the bindersp<ProcessState> ps(ProcessState::self());ps->setThreadPoolMaxThreadCount(9);ps->startThreadPool();ps->giveThreadPoolName();IPCThreadState::self()->disableBackgroundScheduling(true);// Create the servicesp<StatsService> service = new StatsService(looper);if (defaultServiceManager()->addService(String16("stats"), service) != 0) {ALOGE("Failed to add service");return -1;}service->sayHiToStatsCompanion();service->Startup();sp<StatsSocketListener> socketListener = new StatsSocketListener(service);if (kUseLogd) {ALOGI("using logd");// Start the log reader threadstatus_t err = start_log_reader_thread(service);if (err != NO_ERROR) {return 1;}}if (kUseStatsdSocket) {ALOGI("using statsd socket");// Backlog and /proc/sys/net/unix/max_dgram_qlen set to large valueif (socketListener->startListener(600)) {exit(1);}}// Loop forever -- the reports run on this thread in a handler, and the// binder calls remain responsive in their pool of one thread.while (true) {looper->pollAll(-1);}
Comments