码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • 【systrace学习】atrace打开各系统层tag开关的原理


    atrace命令可以开启trace,让系统中埋下的trace标记开始记录,这是怎么实现的呢,

    我们以系统层的trace为例来查看,

    atrace的代码

    frameworks/native/cmds/atrace/​​​​​​atrace.cpp

    93/* Tracing categories */
    94static const TracingCategory k_categories[] = {
    95    { "gfx",        "Graphics",         ATRACE_TAG_GRAPHICS, {
    96        { OPT,      "events/mdss/enable" },
    97        { OPT,      "events/sde/enable" },
    98    } },
    99    { "input",      "Input",            ATRACE_TAG_INPUT, { } },
    100    { "view",       "View System",      ATRACE_TAG_VIEW, { } },
    101    { "webview",    "WebView",          ATRACE_TAG_WEBVIEW, { } },
    102    { "wm",         "Window Manager",   ATRACE_TAG_WINDOW_MANAGER, { } },

    里面通过设置属性的值,来传递信息,即哪些tag需要进行记录

    606// Set the trace tags that userland tracing uses, and poke the running
    607// processes to pick up the new value.
    608static bool setTagsProperty(uint64_t tags)
    609{
    610    std::string value = android::base::StringPrintf("%#" PRIx64, tags);
    611    if (!android::base::SetProperty(k_traceTagsProperty, value)) {
    612        fprintf(stderr, "error setting trace tags system property\n");
    613        return false;
    614    }
    615    return true;
    616}
    60const char* k_traceTagsProperty = "debug.atrace.tags.enableflags";

    执行函数由于执行的次数很多,所以没有必要每次都读取属性 debug.atrace.tags.enableflags的值来判断当前tag是否需要打印,只需要读一次,保存下来即可。

    但是进程怎么知道属性值变化了呢,这里调用每个系统服务的SYSPROPS_TRANSACTION方法,来推送,

    531// Poke all the binder-enabled processes in the system to get them to re-read
    532// their system properties.
    533static bool pokeBinderServices()
    534{
    535    sp<IServiceManager> sm = defaultServiceManager();
    536    Vector<String16> services = sm->listServices();
    537    for (size_t i = 0; i < services.size(); i++) {
    538        sp<IBinder> obj = sm->checkService(services[i]);
    539        if (obj != NULL) {
    540            Parcel data;
    541            if (obj->transact(IBinder::SYSPROPS_TRANSACTION, data,
    542                    NULL, 0) != OK) {
    543                if (false) {
    544                    // XXX: For some reason this fails on tablets trying to
    545                    // poke the "phone" service.  It's not clear whether some
    546                    // are expected to fail.
    547                    String8 svc(services[i]);
    548                    fprintf(stderr, "error poking binder service %s\n",
    549                        svc.string());
    550                    return false;
    551                }
    552            }
    553        }
    554    }
    555    return true;
    556}

    SYSPROPS_TRANSACTION 方法执行起来做什么?

    status_t BBinder::onTransact(
        uint32_t code, const Parcel& data, Parcel* reply, uint32_t /*flags*/)
    {
        switch (code) {
            ...
            case SYSPROPS_TRANSACTION: {
                report_sysprop_change();
                return NO_ERROR;
            }
            ...
        }
    }
     

    report_sysprop_change()方法会调用属性变化的回调函数,

    1. void report_sysprop_change() {
    2. do_report_sysprop_change();
    3. #if defined(__ANDROID__)
    4. // libutils.so is double loaded; from the default namespace and from the
    5. // 'sphal' namespace. Redirect the sysprop change event to the other instance
    6. // of libutils.so loaded in the 'sphal' namespace so that listeners attached
    7. // to that instance is also notified with this event.
    8. static auto func = get_report_sysprop_change_func();
    9. if (func != nullptr) {
    10. (*func)();
    11. }
    12. #endif
    13. }

    所以,服务进程中写了回调函数后,就可以更新属性的值了。

    这里使用了binder来进行通知。

    InputDispatcher里的trace调用

    3868void InputDispatcher::traceInboundQueueLengthLocked() {
    3869    if (ATRACE_ENABLED()) {
    3870        ATRACE_INT("iq", mInboundQueue.count());
    3871    }
    3872}

    ATRACE_ENABLED

    /system/core/include/cutils/
    H A Dtrace.h168 #define ATRACE_ENABLED() atrace_is_tag_enabled(ATRACE_TAG)
    156#define ATRACE_GET_ENABLED_TAGS() atrace_get_enabled_tags()
    157static inline uint64_t atrace_get_enabled_tags()
    158{
    159    atrace_init();
    160    return atrace_enabled_tags;
    161}
    162
    163/**
    164 * Test if a given tag is currently enabled.
    165 * Returns nonzero if the tag is enabled, otherwise zero.
    166 * It can be used as a guard condition around more expensive trace calculations.
    167 */
    168#define ATRACE_ENABLED() atrace_is_tag_enabled(ATRACE_TAG)
    169static inline uint64_t atrace_is_tag_enabled(uint64_t tag)
    170{
    171    return atrace_get_enabled_tags() & tag;
    172}

    调用traceInit()可以设置属性变化的回调,会调用

    22static void traceInit() {
    23    ::android::add_sysprop_change_callback(atrace_update_tags, 0);
    24}

    这里有个很有意思的知识点,在代码中搜不到traceInit的调用,只看到定义,

    20static void traceInit() __attribute__((constructor));
    21
    22static void traceInit() {
    23    ::android::add_sysprop_change_callback(atrace_update_tags, 0);
    24}

    那到底是怎样设置的回调函数呢?

    其实设置了  __attribute__((constructor))  这个高端写法,在main函数开始的地方,就会调用traceInit方法,我们可以搜一下  __attribute__((constructor))这个用法。也可以写个例子来验证这种调用,情况确实如此。

    查看atrace_update_tags的定义,在里面读取属性"debug.atrace.tags.enableflags"的值,更新了atrace_enabled_tags的值,

    98/**
    99 * If tracing is ready, set atrace_enabled_tags to the system property
    100 * debug.atrace.tags.enableflags. Can be used as a sysprop change callback.
    101 */
    102void atrace_update_tags();
    

    在 system/core/libcutils/trace-dev.inc

    里有其实现,获取了要监控的属性值

    136// Update tags if tracing is ready. Useful as a sysprop change callback.
    137void atrace_update_tags()
    138{
    139    uint64_t tags;
    140    if (CC_UNLIKELY(atomic_load_explicit(&atrace_is_ready, memory_order_acquire))) {
    141        if (atomic_load_explicit(&atrace_is_enabled, memory_order_acquire)) {
    142            tags = atrace_get_property();
    143            pthread_mutex_lock(&atrace_tags_mutex);
    144            atrace_enabled_tags = tags;
    145            pthread_mutex_unlock(&atrace_tags_mutex);
    146        } else {
    147            // Tracing is disabled for this process, so we simply don't
    148            // initialize the tags.
    149            pthread_mutex_lock(&atrace_tags_mutex);
    150            atrace_enabled_tags = ATRACE_TAG_NOT_READY;
    151            pthread_mutex_unlock(&atrace_tags_mutex);
    152        }
    153    }
    154}

    总结:

    细节很多,这里回顾一下大体过程,atrace里设置tag,标识哪些tag可以进行写trace,然后写到属性值debug.atrace.tags.enableflags里,atrace又进行了binder调用所有系统服务的SYSPROPS_TRANSACTION对应的方法,告诉它们,属性值变化了,可以调用属性变化回调函数了。

    系统服务进程就调用预定的回调函数,读取debug.atrace.tags.enableflags的值,保存起来,以后就可以用这个值来和tag进行比较,判断当前的tag是否需要写trace,避免每次都属性值,那个读取代价太大。

    普通应用中的trace原理类似,也是设置了属性值。

    相关知识点:属性值的变化可以设置回调函数。

    binder中竟然有个冷门方法SYSPROPS_TRANSACTION,通知属性值的变化。

    参考资料:

    [Android systrace系列] systrace的信息从哪里来 - zzc1024 - 博客园

    监听SystemProperties变化_m0_52481422的博客-CSDN博客_android 监听property变化

  • 相关阅读:
    【opencv图像处理】-- 6.图像轮廓(面积周长)、多边形逼近、外接矩形、查找/绘制轮廓
    搭建Spark开发环境(第二弹)
    中间件 - 分布式协调服务Zookeeper
    【Axure视频教程】下拉列表控制动态面板
    java毕业设计在线拍卖系统Mybatis+系统+数据库+调试部署
    PHP保存时自动删除末尾的空格,phpstorm自动删除空白字符串
    如何工作和生活相平衡?
    面试题库(十二):分布式和中间件等
    帆软FINEREPORT11报表移动端自动显示报表内容解决方案
    Elasticsearch Mapping类型修改
  • 原文地址:https://blog.csdn.net/aaajj/article/details/126796821
  • 最新文章
  • 攻防演习之三天拿下官网站群
    数据安全治理学习——前期安全规划和安全管理体系建设
    企业安全 | 企业内一次钓鱼演练准备过程
    内网渗透测试 | Kerberos协议及其部分攻击手法
    0day的产生 | 不懂代码的"代码审计"
    安装scrcpy-client模块av模块异常,环境问题解决方案
    leetcode hot100【LeetCode 279. 完全平方数】java实现
    OpenWrt下安装Mosquitto
    AnatoMask论文汇总
    【AI日记】24.11.01 LangChain、openai api和github copilot
  • 热门文章
  • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
    奉劝各位学弟学妹们,该打造你的技术影响力了!
    五年了,我在 CSDN 的两个一百万。
    Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
    面试官都震惊,你这网络基础可以啊!
    你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
    心情不好的时候,用 Python 画棵樱花树送给自己吧
    通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
    13 万字 C 语言从入门到精通保姆级教程2021 年版
    10行代码集2000张美女图,Python爬虫120例,再上征途
Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
正则表达式工具 cron表达式工具 密码生成工具

京公网安备 11010502049817号