Android Bluetooth protocol stack message (bta_sys_sendmsg) sending mechanism -- unique resolution of the whole network

Android Bluetooth pairing connection source code analysis document, very detailed from btif BTA BTM HCI data flow to, and from control - click to download

When reading the code, the first problem encountered by students who began to study the Bluetooth protocol stack is that when they encounter sending events, they can't track the code. Then they don't know what code to look at. My younger brother also encountered this problem when he had a preliminary study. Today, I'll explain the Bluetooth protocol stack message (event) sending mechanism in detail according to my many years of experience.


1, Today, take the search device as an example to explain the message mechanism of Bluetooth protocol stack:

void BTA_DmSearch(tBTA_DM_SEARCH_CBACK* p_cback, bool is_bonding_or_sdp) {
81    tBTA_DM_API_SEARCH* p_msg =
82        (tBTA_DM_API_SEARCH*)osi_calloc(sizeof(tBTA_DM_API_SEARCH));
83  
84    /* Queue request if a device is bonding or performing service discovery */
85    if (is_bonding_or_sdp) {
86      p_msg->hdr.event = BTA_DM_API_QUEUE_SEARCH_EVT;
87    } else {
88      p_msg->hdr.event = BTA_DM_API_SEARCH_EVT;
89    }
90    p_msg->p_cback = p_cback;
91  
92    bta_sys_sendmsg(p_msg);
93  }

1. At this point, I want to send BTA_DM_API_SEARCH_EVT events are generated through bta_sys_sendmsg(p_msg) is sent out. At this time, many students can't track it. That's because the protocol stack has its own set of message sending mechanism, which is complex and not very friendly to beginners. Today, I'll explain the message mechanism of Bluetooth protocol stack in detail.

void bta_sys_sendmsg(void* p_msg) {
165    if (do_in_main_thread(
166            FROM_HERE,
167            base::Bind(&bta_sys_event, static_cast<BT_HDR_RIGID*>(p_msg))) !=
168        BT_STATUS_SUCCESS) {
169      LOG(ERROR) << __func__ << ": do_in_main_thread failed";
170    }

Continue calling bta_sys_event()

static void bta_sys_event(BT_HDR_RIGID* p_msg) {
86    uint8_t id;
87    bool freebuf = true;
88  
89    APPL_TRACE_EVENT("%s: Event 0x%x", __func__, p_msg->event);
90  
91    /* get subsystem id from event */
92    id = (uint8_t)(p_msg->event >> 8); //Get subsystem id
93  
94    /* verify id and call subsystem event handler */
95    if ((id < BTA_ID_MAX) && (bta_sys_cb.reg[id] != NULL)) {
96      freebuf = (*bta_sys_cb.reg[id]->evt_hdlr)(p_msg);
97    } else {
98      LOG_INFO("Ignoring receipt of unregistered event id:%s",
99               BtaIdSysText(id).c_str());
100    }
101  
102    if (freebuf) {
103      osi_free(p_msg);
104    }
105  }

2. So what is the subsystem id? That means which profile or service sent it. Otherwise, how can I find the corresponding event?

Each event will be sent with its own id
The following is the subsystem id corresponding to each profile or service. At this time, the id we carry is BTA_ID_DM_SEARCH 2
/system/bt/bta/sys/bta_sys.h

 /* SW sub-systems */
62  #define BTA_ID_SYS 0 /* system manager */
63  /* BLUETOOTH PART - from 0 to BTA_ID_BLUETOOTH_MAX */
64  #define BTA_ID_DM_SEARCH 2      /* device manager search */
65  #define BTA_ID_DM_SEC 3         /* device manager security */
66  #define BTA_ID_DG 4             /* data gateway */
67  #define BTA_ID_AG 5             /* audio gateway */
68  #define BTA_ID_OPC 6            /* object push client */
69  #define BTA_ID_OPS 7            /* object push server */
70  #define BTA_ID_FTS 8            /* file transfer server */
71  #define BTA_ID_CT 9             /* cordless telephony terminal */
72  #define BTA_ID_FTC 10           /* file transfer client */
73  #define BTA_ID_SS 11            /* synchronization server */
74  #define BTA_ID_PR 12            /* Printer client */
75  #define BTA_ID_BIC 13           /* Basic Imaging Client */
76  #define BTA_ID_PAN 14           /* Personal Area Networking */
77  #define BTA_ID_BIS 15           /* Basic Imaging Server */
78  #define BTA_ID_ACC 16           /* Advanced Camera Client */
79  #define BTA_ID_SC 17            /* SIM Card Access server */
80  #define BTA_ID_AV 18            /* Advanced audio/video */
81  #define BTA_ID_HD 20            /* HID Device */
82  #define BTA_ID_CG 21            /* Cordless Gateway */
83  #define BTA_ID_BP 22            /* Basic Printing Client */
84  #define BTA_ID_HH 23            /* Human Interface Device Host */
85  #define BTA_ID_PBS 24           /* Phone Book Access Server */
86  #define BTA_ID_PBC 25           /* Phone Book Access Client */
87  #define BTA_ID_JV 26            /* Java */
88  #define BTA_ID_HS 27            /* Headset */
89  #define BTA_ID_MSE 28           /* Message Server Equipment */
90  #define BTA_ID_MCE 29           /* Message Client Equipment */
91  #define BTA_ID_HL 30            /* Health Device Profile*/
92  #define BTA_ID_GATTC 31         /* GATT Client */
93  #define BTA_ID_GATTS 32         /* GATT Client */
94  #define BTA_ID_SDP 33           /* SDP Client */
95  #define BTA_ID_BLUETOOTH_MAX 34 /* last BT profile */
96  
97  #define BTA_ID_MAX (44 + BTA_DM_NUM_JV_ID)

2.1 continue to look at BTA_ sys_ The code in the event () function: bta_sys_cb.reg[] ! = NULL, pointing is not equal to null? The description must point to a function. Who does it point to? Continue to look down:

View this structure variable.
/* system manager control block definition */
  tBTA_SYS_CB bta_sys_cb;
Let's first look at this structure. The first structure member is the reg []:

/* system manager control block */
47  typedef struct {
48    tBTA_SYS_REG* reg[BTA_ID_MAX]; /* registration structures */
49    bool is_reg[BTA_ID_MAX];       /* registration structures */
50    bool forward_hw_failures;
51    uint16_t sys_features;         /* Bitmask of sys features */
52  
53    tBTA_SYS_CONN_CBACK* prm_cb; /* role management callback registered by DM */
54    tBTA_SYS_CONN_CBACK*
55        ppm_cb; /* low power management callback registered by DM */
56    tBTA_SYS_CONN_CBACK*
57        p_sco_cb; /* SCO connection change callback registered by AV */
58    tBTA_SYS_CONN_CBACK* p_role_cb; /* role change callback registered by AV */
59    tBTA_SYS_COLLISION colli_reg;   /* collision handling module */
60  #if (BTA_EIR_CANNED_UUID_LIST != TRUE)
61    tBTA_SYS_EIR_CBACK* eir_cb; /* add/remove UUID into EIR */
62    tBTA_SYS_CUST_EIR_CBACK* cust_eir_cb; /* add/remove customer UUID into EIR */
63  #endif
64    tBTA_SYS_SSR_CFG_CBACK* p_ssr_cb;
65    /* VS event handler */
66    tBTA_SYS_VS_EVT_HDLR* p_vs_evt_hdlr;
67  
68  } tBTA_SYS_CB;

Continue to watch BTA_ sys_ This code of the event () function: bta_sys_cb.reg[] ! = NULL, we found reg [] in the above structure. It turns out that it is an array of structure pointers.
It's a little complicated. Continue to look at this structure pointer array: tBTA_SYS_REG:
There are two function pointer variables in this structure. (PS: if you don't understand function pointer variables, it's important to review the c language!!!)
 

/* registration structure */
 typedef struct {
  tBTA_SYS_EVT_HDLR* evt_hdlr;
   tBTA_SYS_DISABLE* disable;
 } tBTA_SYS_REG;

So these two function pointer variables must point to the two functions, so where is the value assigned or pointed to?
So let's search TBTA_ SYS_ Does the reg structure define variables elsewhere?
Through the search, we find that a structure variable is defined and filled in each profile or service. Then we find the structure variable of our corresponding id:

/system/bt/bta/dm/bta_dm_api.cc
 static const tBTA_SYS_REG bta_dm_search_reg = {bta_dm_search_sm_execute,
                                                bta_dm_search_sm_disable};

Here we finally find the place of assignment, define a structure array and initialize it.

2.2 the structure array and BTA_ sys_ This code of the event () function: BTA_ sys_ cb. reg[] ! = How does null correspond?

So now you need to point to the past? Where did it point to? It must be where init is initialized.

/system/bt/bta/dm/bta_dm_api.cc

void BTA_dm_init() {
48    bta_sys_register(BTA_ID_DM_SEARCH, &bta_dm_search_reg);
49    /* if UUID list is not provided as static data */
50    bta_sys_eir_register(bta_dm_eir_update_uuid);
51    bta_sys_cust_eir_register(bta_dm_eir_update_cust_uuid);
52  }

We found that it was registered in init and called BTA_ sys_ Register (bta_id_dm_search, & bta_dm_search_reg), set id= BTA_ID_DM_SEARCH, and BTA_ dm_ search_ Reg this structure array passed in. Keep looking at this function.

/system/bt/bta/sys/bta_sys_main.cc

void bta_sys_register(uint8_t id, const tBTA_SYS_REG* p_reg) {
119    bta_sys_cb.reg[id] = (tBTA_SYS_REG*)p_reg;
120    bta_sys_cb.is_reg[id] = true;
121  }

Finally found bta_sys_cb.reg[id] = (tBTA_SYS_REG*)p_reg

2.3 continue to look at BTA_ sys_ This sentence of the event() function: (* bta_sys_cb. Reg [ID] - [evt_hdlr) (p_msg)
This is the function pointer mentioned above. The first bracket points to bta_dm_search_sm_execute() this function, and p_msg passed in.


3. Let's move on:
/system/bt/bta/dm/bta_dm_main.cc

3.1 processing methods of Android 11 and previous versions:

bool bta_dm_search_sm_execute(BT_HDR* p_msg) {
231    tBTA_DM_ST_TBL state_table;
232    uint8_t action;
233    int i;
234  
235    APPL_TRACE_EVENT("bta_dm_search_sm_execute state:%d, event:0x%x",
236                     bta_dm_search_cb.state, p_msg->event);//This state is controlled by a global variable
237  
238    /* look up the state table for the current state */
239    state_table = bta_dm_search_st_tbl[bta_dm_search_cb.state];//Query current status
240  
241    bta_dm_search_cb.state =
242        state_table[p_msg->event & 0x00ff][BTA_DM_SEARCH_NEXT_STATE];//Get p_ MSG - > Event line, BTA_ DM_ SERRCH_ NEXT_ The state of the state column.
243  
244    /* execute action functions */
245    for (i = 0; i < BTA_DM_SEARCH_ACTIONS; i++) { BTA_DM_SEARCH_ACTIONS = 2,
246      action = state_table[p_msg->event & 0x00ff][i];//Get p_ The first and second action functions of MSG - > Event line are executed successively. There are two action functions, which generally need to be executed.
247      if (action != BTA_DM_SEARCH_IGNORE) {
248        (*bta_dm_search_action[action])((tBTA_DM_MSG*)p_msg); //This is the function pointer mentioned above. The first bracket points to bta_dm_search_sm_execute[action] this function, and p_msg passed in.
249      } else {
250        break;
251      }
252    }
253    return true;
254  }

Take a closer look: action = state_ Table [p_msg - > Event & 0x00ff] [i], we finally see that it is a two-dimensional array, and we need to locate the corresponding action,
First determine the line: we are BTA at the moment_ DM_ API_ Search, that is, the first row, executes actions in the first column and the second column respectively. You can see that action2 does not exist, so execute the first action

 

/* state table for listen state */
  const uint8_t bta_dm_search_idle_st_table[][BTA_DM_SEARCH_NUM_COLS] = {
  
      /* Event                                         Action 1                                           Action 2                               Next State */
      /* API_SEARCH */              {BTA_DM_API_SEARCH,                       BTA_DM_SEARCH_IGNORE,     BTA_DM_SEARCH_ACTIVE},
      /* API_SEARCH_CANCEL */ {BTA_DM_SEARCH_CANCEL_NOTIFY,   BTA_DM_SEARCH_IGNORE,    BTA_DM_SEARCH_IDLE},
    ......
    ......
    ......

At this point, the action we want to execute = BTA_ DM_ API_ SEARCH.
By viewing the variable, it is an enumeration, equal to 0, so action = state_ Table [p_msg - > Event & 0x00ff] [i] is assigned to 0.
 

/* state machine action enumeration list */
43  enum {
44    BTA_DM_API_SEARCH,                 /* 0 bta_dm_search_start */
45    BTA_DM_API_SEARCH_CANCEL,          /* 1 bta_dm_search_cancel */
46    BTA_DM_API_DISCOVER,               /* 2 bta_dm_discover */
47    BTA_DM_INQUIRY_CMPL,               /* 3 bta_dm_inq_cmpl */
48    BTA_DM_REMT_NAME,                  /* 4 bta_dm_rmt_name */
49    BTA_DM_SDP_RESULT,                 /* 5 bta_dm_sdp_result */
	......
	......
	......

(btdm action)_ MSG), we know from the above that action = 0. Let's look at BTA_ dm_ search_ What are the functions in the action [action] array?

/* action function list */
67  const tBTA_DM_ACTION bta_dm_search_action[] = {
68  
69      bta_dm_search_start,               /* 0 BTA_DM_API_SEARCH */
70      bta_dm_search_cancel,              /* 1 BTA_DM_API_SEARCH_CANCEL */
71      bta_dm_discover,                   /* 2 BTA_DM_API_DISCOVER */
72      bta_dm_inq_cmpl,                   /* 3 BTA_DM_INQUIRY_CMPL */
73      bta_dm_rmt_name,                   /* 4 BTA_DM_REMT_NAME */
74      bta_dm_sdp_result,                 /* 5 BTA_DM_SDP_RESULT */
75      bta_dm_search_cmpl,                /* 6 BTA_DM_SEARCH_CMPL */
76      bta_dm_free_sdp_db,                /* 7 BTA_DM_FREE_SDP_DB */
77      bta_dm_disc_result,                /* 8 BTA_DM_DISC_RESULT */
78      bta_dm_search_result,              /* 9 BTA_DM_SEARCH_RESULT */
79      bta_dm_queue_search,               /* 10 BTA_DM_QUEUE_SEARCH */
80      bta_dm_queue_disc,                 /* 11 BTA_DM_QUEUE_DISC */
81      bta_dm_search_clear_queue,         /* 12 BTA_DM_SEARCH_CLEAR_QUEUE */
82      bta_dm_search_cancel_cmpl,         /* 13 BTA_DM_SEARCH_CANCEL_CMPL */
83      bta_dm_search_cancel_notify,       /* 14 BTA_DM_SEARCH_CANCEL_NOTIFY */
84      bta_dm_search_cancel_transac_cmpl, /* 15 BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL
85                                            */
86      bta_dm_disc_rmt_name,              /* 16 BTA_DM_DISC_RMT_NAME */
87      bta_dm_di_disc,                    /* 17 BTA_DM_API_DI_DISCOVER */
88      bta_dm_close_gatt_conn};

Wow, I finally found the function I need, that is, No. 0: bta_dm_search_start.


For Android 12, major changes have taken place here. Instead of cumbersome state machine search, switch is directly used Case statement, simpler.

bool bta_dm_search_sm_execute(BT_HDR_RIGID* p_msg) {
63    APPL_TRACE_EVENT("bta_dm_search_sm_execute state:%d, event:0x%x",
64                     bta_dm_search_cb.state, p_msg->event);
65  
66    tBTA_DM_MSG* message = (tBTA_DM_MSG*)p_msg; //First, put p_msg get
67    switch (bta_dm_search_cb.state) { //This state is controlled by a global variable to obtain the current state.
68      case BTA_DM_SEARCH_IDLE:
69        switch (p_msg->event) {  //Take out the event in the message,
70          case BTA_DM_API_SEARCH_EVT:  //At this time, we finally find the action corresponding to the event according to the transmitted event,
71            bta_dm_search_set_state(BTA_DM_SEARCH_ACTIVE);
72            bta_dm_search_start(message);//The next step is to execute the function.
73            break;

4. Summary

At this time, we finally understand the message sending mechanism of Bluetooth protocol stack. It is really complex. Do we have to find it like this every time? In fact, it's not necessary. We just need to directly find the corresponding action in the corresponding file. Generally, it's in / system/bt/bta/xxx protocol / XXXX_ main. Defined in the CC function. But for a Bluetooth developer, the principle behind it still needs to be understood.
 

Tags: Android bluetooth

Posted by zimick on Thu, 19 May 2022 03:36:28 +0300