1 ## Power Management 2 3 ### Overview 4 5 Power management (PM) in bluedroid is an event-driven state machine, tickled by 6 various `bta/sys` events via a callback. The actual state switching calls are 7 handled by the BTM HCI interfacing code, with results being posted back to the 8 PM code via the BTA workqueue thread. 9 10 Power states are managed per-device, per-profile, so every incoming event 11 includes a profile ID, app ID, and a `BD_ADDR`. 12 13 The events fired to drive the state machine at the time of this writing are: 14 15 - `BTA_SYS_CONN_OPEN` 16 - `BTA_SYS_CONN_CLOSE` 17 - `BTA_SYS_CONN_IDLE` 18 - `BTA_SYS_CONN_BUSY` 19 - `BTA_SYS_APP_OPEN` 20 - `BTA_SYS_APP_CLOSE` 21 - `BTA_SYS_SCO_OPEN` 22 - `BTA_SYS_SCO_CLOSE` 23 24 Each of these correspond to a function name in `bta/sys/bta_sys_conn.c`, which 25 are called by each profile definition in `bta/$PROFILE`. 26 27 The PM code makes calls into the BTM module to set various power 28 states. Responses are handled in an asynchronous fashion, primarily via the 29 callbacks `bta_dm_pm_cback` and `bta_dm_pm_timer_cback`. Responses are handled 30 through the BTA workqueue thread and the `bta_dm_pm_btm_status` function. Since 31 we might possibly get into a bad state where we never hear back from the 32 controller, timers are used to post messages to the BTA workqueue thread as 33 well, which filters down through the same status function. 34 35 Overall power states are managed *per device*, not per connection, but the power 36 policy is determined by the greatest allowable power action defined across all 37 currently known connections to a given device. Thus, if RFCOMM specifies that 38 it's willing to go to into SNIFF and specifies that as an action, and say, a PAN 39 connection is up which specifies it is willing to go into SNIFF, but its action 40 states it wants ACTIVE, the power management code will change to ACTIVE. 41 42 ### Power management tables 43 44 The tables that determine which power levels are acceptable for which profiles 45 and what actions to take for the above events are defined in the 46 `bta/dm/bta_dm_cfg.c` file, as `bta_dm_pm_cfg`, `bta_dm_pm_spec`, and 47 `bta_dm_ssr_spec`. 48 49 During a lookup attempt, the code iterates over the `bta_dm_pm_cfg` array, 50 looking for a match between the profile and app IDs. When it finds one, it uses 51 the `spec_idx` field to index into `bta_dm_pm_spec` array to determine which 52 power modes are acceptable and what actions to take for each event. 53 54 The action constants are defined in `bta_api.h` and are defined as a series of 55 hex bitfields. The actual actions taken are determined by the 56 `bta_dm_pm_set_mode` function, but a few of the actions listed deserve some 57 additional description: 58 59 - `BTA_DM_PM_NO_ACTION` is effectively a no-op and has a value of zero, so any 60 other profile will override this. 61 - `BTA_DM_PM_NO_PREF` overrides `BTA_DM_PM_NO_ACTION` and if selected as the 62 action that `bta_dm_pm_set_mode` will take, the connection will be removed 63 from `bta_dm_conn_srvcs` and no longer be considered for power management 64 decisions. 65 - `BTA_DM_PM_SNIFF` through `BTA_DM_PM_SNIFF4` are special, in that each 66 level specifies a set of parameters for the SNIFF mode which relate to the 67 min and max intervals, the number of attempts and the timeout. The overall 68 action is still the same, however -- SNIFF mode is attempted. There are 69 definitions available up to SNIFF7, but actual SSR values are only defined 70 up to SNIFF4. Params are defined in `bta_dm_ssr_spec`. 71 - `BTA_DM_PM_ACTIVE` is full-on power. 72 - `BTA_DM_PM_RETRY` has the same effect as `BTA_DM_PM_NO_ACTION`, except a 73 timeout is possible to be set, which effectively allows a power operation to 74 be "retried". 75 76 ### Initialization 77 78 `bta_dm_pm.c`'s `bta_dm_init_pm` function calls out to register 79 `bta_dm_pm_cback` with the bta sys module for incoming power management events, 80 and also registers `bta_dm_pm_btm_cback` with the btm module to handle responses 81 and timeouts of HCI requests (via `bta_dm_pm_btm_status`). 82 83 At this point, the power managment code is basically done until the first set of 84 events come in through `bta_dm_pm_cback`. 85 86 Throughout the `bta_dm_pm.c` file, connections whose power management states are 87 managed are tracked in a global array called `bta_dm_conn_srvcs`. Unfortunately, 88 while this variable is declared as an extern in the `bta_dm_int.h` file, it only 89 seems to be used in the `bta_dm_act.c` file, and only for reinitialization. 90 91 ### Event flow 92 93 #### Events fired from SYS 94 95 1. An event is fired from one of the methods mentioned above in 96 `bta/sys/bta_sys_conn.c` 97 2. The `bta_dm_pm_cback` function is called. 98 - The power mode config is looked up in the `bta_dm_pm_cfg` table. If none 99 are found for the given profile ID and app ID, the function simply 100 returns with no action taken. 101 - If any timers were set for the given `BD_ADDR`, they are stopped. 102 - The SSR params for the CONN_OPEN event are looked up. 103 - The power spec state table (`bta_dm_pm_spec`) is checked to see if 104 there's no action to be performed (`BTA_DM_PM_NO_ACTION`), and if so, 105 returns with no action taken. 106 - `bta_dm_conn_srvcs` is consulted to ensure there's an entry for this 107 connection if it's supposed to be managed according to the power spec 108 state tables. If the spec specifies `BTA_DM_PM_NO_PREF`, then any 109 existing entry in this list is removed, otherwise one is added/updated 110 with the state given to the function. 111 3. `bta_dm_pm_cback` checks to see if the `bta_dm_ssr_spec` specifies SSR 112 adjustments are to be made, and if so, `bta_dm_pm_ssr` is called with the 113 peer `BD_ADDR`. 114 - `bta_dm_pm_ssr` iterates the managed services array to find all connected 115 services for the given `BD_ADDR`, then looks up the ssr values from the 116 `bta_dm_ssr_spec` tables, looking for the smallest max latency to use. 117 - `bta_dm_pm_ssr` calls `BTM_SetSsrParams` to actually send along the SSR 118 params to the bluetooth chip. 119 4. `bta_dm_pm_cback` calls `bta_dm_pm_set_mode` with the peer address and the 120 `timed_out` parameter set to `false`. 121 - For each managed connection, `bta_dm_pm_set_mode` grabs 122 both actions specified for the profile in the `bta_dm_pm_spec` tables. If 123 the first power management action didn't timeout (or was never attempted, 124 according to the `tBTA_DM_PEER_DEVICE` `pm_mode_failed` and 125 `pm_mode_attempted` fields), its timeout and mode are used. Otherwise, 126 the same check is done against the second action and it is used 127 instead. If both actions have been attempted, then the action is set to 128 `BTA_DM_PM_NO_ACTION`. Only the highest power mode action is chosen from 129 all connected profiles. 130 - If the chosen action is `BTA_DM_PM_PARK` or `BTA_DM_PM_SNIFF` but the 131 profile doesn't allow it, this function takes no action. 132 - If a timeout is specified in the power spec table, then an unused timer 133 in `bta_dm_cb.pm_timer` is started. 134 - If the action chosen is `BTA_DM_PM_PARK`, `bta_dm_pm_park` is called, 135 which calls `BTM_ReadPowerMode` and `BTM_SetPowerMode` to make an HCI 136 request to enable PARK for the given peer and connection. 137 - If the action chosen is `BTA_DM_PM_SNIFF`, the peer device's link policy 138 is checked to see if it's allowed. If so, then `bta_dm_pm_sniff` is 139 called, which makes various calls to `BTM_ReadLocalFeatures`, 140 `BTM_ReadRemoteFeatures` and `BTM_SetPowerMode` to ensure SNIFF mode is 141 enabled. 142 - If the action chosen is `BTA_DM_PM_ACTIVE`, a call to `bta_dm_pm_active` 143 is made, which calls `BTM_SetPowerMode` to set the link into ACTIVE 144 mode. 145 146 At this point, if one of the timers in `bta_dm_cb.pm_timer` times out, a call is 147 made through the BTA workqueue thread to `bta_dm_pm_btm_cback`, which then 148 triggers `bta_dm_pm_btm_status`, with the timeout field set to TRUE. HCI 149 responses are also fired as messages through the BTA workqueue thread, which are 150 handled again, through `bta_dm_pm_btm_status`. 151 152 #### Events fired through BTM 153 154 Essentially these messages eventually go through the same functions as events 155 fired from the SYS side of things, except from the initial path they take: 156 157 1. An event is fired from a callback in BTM to `bta_dm_pm_btm_cback`. 158 2. `bta_dm_pm_btm_cback` packages up the given parameters into a 159 `tBTA_DM_PM_BTM_STATUS` struct and posts it to the BTA workqueue thread via 160 `bta_sys_sendmsg`, with the event header set to 161 `BTA_DM_PM_BTM_STATUS_EVT`. 162 3. This is eventually routed to the `bta_dm_pm_btm_status` function. 163 **Determine if this is running on the workqueue thread or not** 164 - The message `status` passed in is actually the current status of the 165 device. 166 - If the status is `BTM_PM_STS_ACTIVE` (still in the ACTIVE power mode), 167 checks the HCI status code: 168 - If that's non-zero and a PARK or SNIFF mode change was attempted, 169 `bta_dm_pm_btm_status` stops any timers started for the device in 170 `bta_dm_pm_set_mode`, clears some status bits in the peer device 171 structure, and then calls back into `bta_dm_pm_set_mode` with the peer 172 device address and timeout set to FALSE. 173 - If the status is zero, and if the peer device `tBTA_DM_PEER_DEVICE` 174 `prev_low` field is set, calls `bta_dm_pm_ssr` to re-send SSR params, 175 stops all timers for the device, and then re-calls `bta_dm_pm_set_mode` 176 with timeout set to FALSE to re-attempt with a second action (if the 177 previous PARK or SNIFF failed, otherwise it'll re-attempt the first 178 action). 179 - If the status is `BTM_PM_STS_PARK` or `BTM_PM_STS_HOLD`, saves the 180 previous low power mode in the peer device's `prev_low` field. 181 - If the status is `BTM_PM_STS_SSR`, simply clears or sets the device 182 `info` field's `BTA_DM_DI_USE_SSR` bit, depending on the value of 183 `tBTA_DM_MSG.value`, which determines if the device can handle SSR. 184 - If the status is `BTM_PM_STS_SNIFF` and the info field has the 185 `BTA_DM_DI_SET_SNIFF` bit set, then `BTA_DM_DI_INT_SNIFF` is set, 186 otherwise `BTA_DM_DI_ACP_SNIFF` is set. 187 - If `BTA_PM_STS_ERROR`, the `BTA_DM_DI_SET_SNIFF` bit is cleared in the 188 device info field. 189 190 At this point, either the method simply returns, or has called back into 191 `bta_dm_pm_set_mode`, in which case the usual flow takes over. 192 193 #### Events fired from timers 194 195 Timers are used exclusively for handling HCI command timeouts, and filter 196 through to a call to `bta_dm_pm_set_mode`: 197 198 1. A timer expires, and calls `bta_dm_pm_timer_cback`. 199 2. `bta_dm_pm_timer_cback` clears the use flag on the timer that fired, and 200 sends off an event to the BTA workqueue thread. 201 3. The event eventually fires off a call to `bta_dm_pm_timer`, which just 202 calls `bta_dm_pm_set_mode` with timeout set to `TRUE`. 203