日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

Binder子系统之调试分析(一)

發布時間:2025/3/15 windows 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Binder子系统之调试分析(一) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一. 概述

在博客以前有寫過關于binder系列,大概寫了10篇關于binder的文章,從binder驅動,到native層,再到framework,一路寫到app層的使用。有興趣的可以看看?Binder系列—開篇。

二.Binder驅動調試

看過Binder系列文章的同學,會發現Binder IPC過程最終都交給Binder Driver來完成,這是真正干跨進程通信活的地方,那么意味著這里會有各種核心的通信log,比如binder open, mmap, ioctl等操作都可以通過某種方式來打開相應調試信息來分析。對于binder driver存在16類調試log開關,如下:

2.1 debug_mask

Log類型 mask值 解釋
BINDER_DEBUG_USER_ERROR 1 用戶使用錯誤
BINDER_DEBUG_FAILED_TRANSACTION 2 transaction失敗
BINDER_DEBUG_DEAD_TRANSACTION 4 transaction死亡
BINDER_DEBUG_OPEN_CLOSE 8 binder的open/close/mmap信息
BINDER_DEBUG_DEAD_BINDER 16 binder/node死亡信息
BINDER_DEBUG_DEATH_NOTIFICATION 32 binder死亡通知信息
BINDER_DEBUG_READ_WRITE 64 binder的read/write信息
BINDER_DEBUG_USER_REFS 128 binder引用計數
BINDER_DEBUG_THREADS 256 binder_thread信息
BINDER_DEBUG_TRANSACTION 512 transaction信息
BINDER_DEBUG_TRANSACTION_COMPLETE 1024 transaction完成信息
BINDER_DEBUG_FREE_BUFFER 2048 可用buffer信息
BINDER_DEBUG_INTERNAL_REFS 4096 binder內部引用計數
BINDER_DEBUG_BUFFER_ALLOC 8192 同步內存分配信息
BINDER_DEBUG_PRIORITY_CAP 16384 調整binder線程的nice值
BINDER_DEBUG_BUFFER_ALLOC_ASYNC 32768 異步內存分配信息

每一項mask值通過將1左移N位,也就是等于2的倍數

2.2 調試開關

通過節點/sys/module/binder/parameters/debug_mask來動態控制選擇開啟上表中的debug log.

(1)例如打開BINDER_DEBUG_OPEN_CLOSE調試開關,則通過adb shell執行如下命令:

echo 8 > /sys/module/binder/parameters/debug_mask

(2)再例如同時打開BINDER_DEBUG_FAILED_TRANSACTION和BINDER_DEBUG_DEAD_BINDER,將各個mask值相加即可,16+2 =18.

echo 18 > /sys/module/binder/parameters/debug_mask

(3)要打開多個開關,只需將各個開關的mask值相加寫入debug_mask即可。打開調試開關后,可通過adb shell,執行cat /proc/kmsg | grep binder,即可查看相應的binder log信息。

2.3 原理

mask相加,其實現其實是利用或運算,通過一個變量控制16個開關,而不是采用16個變量,這是比較經典的設計方案。在binder Driver中通過下面語句完成節點控制debug的功能:

module_param_named(debug_mask, binder_debug_mask, uint, S_IWUSR | S_IRUGO);

module_param_named的功能:

  • 首先會生成/sys/module/binder/parameters/目錄;
  • module_param_named的第一個參數為debug_mask,則會在parameters目錄下創建debug_mask文件節點;
  • 當通過echo NUM > debug_mask命令,會觸發動態修改module_param_named的第二個參數binder_debug_mask值,這是個靜態uint32_t類型數據;
  • 驅動中輸出debug log都是通過調用binder_debug()方法,該方法通過與binder_debug_mask變量做或運算來判斷相應類型的log信息是否需要輸出。

binder_debug宏定義,如下:

#define binder_debug(mask, x...) \do { \if (binder_debug_mask & mask) \pr_info(x); \} while (0)

當然,也可以通過代碼直接修改binder_debug_mask值來控制調試開關,默認值為:

binder_debug_mask = BINDER_DEBUG_USER_ERROR |BINDER_DEBUG_FAILED_TRANSACTION | BINDER_DEBUG_DEAD_TRANSACTION;

另外,在/sys/module/binder/parameters/目錄還有另外兩個節點,分別為proc_no_lock, stop_on_user_error,其實現原理也基本差不多。

  • proc_no_lock節點:與之對應binder驅動的binder_debug_no_lock變量,這是bool類型變量,該開關含義為在輸出某些統計調試方法中是否加鎖;默認為N;
  • stop_on_user_error節點:與之對應binder驅動的binder_stop_on_user_error變量,這是int類型變量,另外,修改該節點還會觸發調用binder_set_stop_on_user_error()方法;該開關含義是指當觸發BINDER_DEBUG_USER_ERROR類型錯誤時是否讓整個binder系統進入休眠等待狀態,默認值為0,代表不會即便發生該類型錯誤系統不會被掛住,而是繼續執行。

三 實戰

3.1 BINDER_DEBUG_OPEN_CLOSE

當打開調試開關BINDER_DEBUG_OPEN_CLOSE時,主要輸出binder的open, mmap, close, flush, release方法中的log信息

具體kernel log,如下:

  • binder_open:?4681:4681
  • binder_mmap:?4681 b6b42000-b6c40000 (1016 K) vma 200071 pagep 79f
  • binder:?4681 close vm area b6b42000-b6c40000 (1016 K) vma 2220051 pagep 79f
  • binder_flush:?4681 woke 0 threads
  • binder_release:?4681 threads 1, nodes 0 (ref 0), refs 2, active transactions 0, buffers 1, pages 1
  • 3.2 解析

    上面各行log所對應的信息項:

  • binder_open:?group_leader->pid:pid
  • binder_mmap:?pid?vm_start-vm_end (vm_size?K) vma vm_flags pagep?vm_page_prot
  • binder:?pid?close vm area vm_start-vm_end (vm_size?K) vma vm_flags pagepvm_page_prot
  • binder_flush:?pid?woke?wake_count?threads
  • binder_release:?pid?threads?threads, nodes?nodes?(ref?incoming_refs), refsoutgoing_refs, active transactions?active_transactions, buffers?buffers, pagespage_count
  • 進一步說明其中部分關鍵詞的含義:

    • vm_page_prot:是指當前進程的VMA訪問權限;
    • wake_count:是指該進程喚醒了處于BINDER_LOOPER_STATE_WAITING休眠等待狀態的線程個數;
    • threads是指該進程中的線程個數;
    • nodes代表該進程中創建binder_node個數;
    • incoming_refs指向當前node的refs個數;
    • outgoing_refs指向其他進程的refs個數;
    • active_transactions是指當前進程中所有binder線程的transactions總和;
    • buffers是指當前進程已分配的buffer個數;
    • page_count是指當前進程已分配的物理page個數。

    3.3 對應函數

    上述log每一行相對應的函數:

  • binder_open()
  • binder_vma_open() 或者 binder_mmap()
  • binder_vma_close()
  • binder_deferred_flush() 由binder_flush調用(見下方調用棧)
  • binder_deferred_release() 由binder_release調用(見下方調用棧)
  • binder_flush調用棧:

    binder_flush binder_defer_work(proc, BINDER_DEFERRED_FLUSH);queue_work(binder_deferred_workqueue, &binder_deferred_work);binder_deferred_func //通過 DECLARE_WORK(binder_deferred_work, binder_deferred_func);binder_deferred_flush

    binder_release調用棧:

    binder_release binder_defer_work(proc, BINDER_DEFERRED_RELEASE);queue_work(binder_deferred_workqueue, &binder_deferred_work);binder_deferred_func //通過 DECLARE_WORK(binder_deferred_work, binder_deferred_func);binder_deferred_release

    當binder所在進程結束時會調用binder_release。 binder_open打開binder驅動/dev/binder,這是字符設備,獲取文件描述符。在進程結束的時候會有一個關閉文件系統的過程中會調用驅動close方法,該方法相對應的是release()方法。

    但并不是每個close系統調用都會觸發調用release()方法. 只有真正釋放設備數據結構才調用release(),內核維持一個文件結構被使用多少次的計數,即便是應用程序沒有明顯地關閉它打開的文件也適用: 內核在進程exit()時會釋放所有內存和關閉相應的文件資源, 通過使用close系統調用最終也會release binder.

    四. 其他實例

    4.1 BINDER_DEBUG_DEAD_BINDER

    //debug_id, node的引用次數,死亡通知個數?
    binder: node?1078337?now dead, refs?1, death?0

    //ref->proc->pid, ref->debug_id, ref->desc(handle)?
    binder:?13839?delete ref?1078335?desc?1?has death notification

    //proc->pid, thread->pid, (u64)cookie, death?
    binder:?1788:1805?BC_DEAD_BINDER_DONE?9ce308c0?found?f10a5400

    4.2 BINDER_DEBUG_FREE_BUFFER

    查詢可用buffer:

    //proc->pid, thread->pid, (u64)data_ptr, buffer->debug_id, buffer->transaction?
    binder:?463:5919?BC_FREE_BUFFER ub4641028?found buffer?1183795?for?finishedtransaction?
    binder:?277:2771?BC_FREE_BUFFER ub6c58028?found buffer?1183806?for?activetransaction

    另外,buffer->transaction ? “active” : “finished”

    位于方法binder_thread_write()

    4.3 BINDER_DEBUG_BUFFER_ALLOC_ASYNC(異步)

    申請和釋放異步buffer:

    //proc->pid, size, proc->free_async_space
    binder:?1788: binder_alloc_buf size?148?async free?520004
    binder:?1788: binder_free_buf size?148?async free?520192

    解析:

    • binder_alloc_buf:進程1788,申請148 Bytes,則該進程的可用異步空間大小520004 Bytes;
    • binder_free_buf: 進程1788,釋放148 Bytes,則該進程的可用異步空間大小520192 Bytes;

    內存大小計算:

    free_async_space = 520004 Bytes,再釋放148 Bytes后,則可用大小應該是 520152 Bytes,這里卻為520192 Bytes,這里多出來的40 Bytes是哪來得呢?這是因為binder_free_buf還會同時釋放struct binder_buffer,該結構體大小則為40 Bytes.

    另外:buffer申請內存binder_alloc_buf和釋放內存binder_free_buf,除了本身內存申請和釋放,會同時伴隨著binder_buffer結構體的創建和釋放,這便是每次操作40 Bytes差距所在。另外, 對于64位系統,binder_buffer大小為80 Bytes.

    初始化值

    proc->free_async_space = proc->buffer_size / 2 = (1M-8K)/2 = 520192 Bytes。當進程剛打開binder驅動,執行完binder_mmap方法后,異步可用空間總大小為 520192 Bytes.

    4.4 BINDER_DEBUG_BUFFER_ALLOC(同步)

    // 參數:proc->pid, size, buffer, buffer_size?
    binder:?1788: binder_alloc_buf size?76?got buffer?c7800128?size?208?
    binder:?1788:?allocate?pages?c7801000-c7800000?
    // 參數:proc->pid, new_buffer_size, new_buffer?
    binder:?1788: add free buffer, size?92, at?c780019c?
    binder:?1788:?free?pages?c7801000-c7800000?
    //參數:proc->pid, buffer, prev?
    binder:?1788: merge free, buffer?c780019c?share page with?c7800128

    解析:

    • binder_alloc_buf: 從proc->free_buffers這棵紅黑色樹,找到一塊大小大于并最接近76Bytes的buffer,該buffer大小為208Bytes;
    • binder_update_page_range:申請一個page大小的物理內存,地址為c7801000-c7800000。
    • binder_insert_free_buffer: 將空閑buffer添加到proc->free_buffers;
    • binder_update_page_range:釋放一個page大小的物理內存,地址為c7801000-c7800000。
    • binder_delete_free_buffer:在執行binder_free_buf()過程,合并釋放的buffer,由于該buffer跟上一個buffer共享同一page,則無需釋放。

    五. 小結

    本文主要介紹控制調試開關和各個開關的含義及原理,最后再通過一個實例來進一步來說明其中一項開關打開后的log信息該如何分析。后續會介紹更多的調試含義和調試工具,以及從上至下binder是如何通信。

    原文地址:http://gityuan.com/2016/08/27/binder-debug/

    總結

    以上是生活随笔為你收集整理的Binder子系统之调试分析(一)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。