1 /*
2 * Copyright 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "stack_power_tel"
18
19 #include "osi/include/stack_power_telemetry.h"
20
21 #include <bluetooth/log.h>
22 #include <com_android_bluetooth_flags.h>
23 #include <sys/stat.h>
24 #include <time.h>
25
26 #include <atomic>
27 #include <list>
28 #include <map>
29 #include <mutex>
30
31 #include "common/init_flags.h"
32 #include "os/log.h"
33 #include "osi/include/properties.h"
34 #include "stack/include/acl_api_types.h"
35 #include "stack/include/bt_psm_types.h"
36 #include "stack/include/btm_status.h"
37 #include "types/raw_address.h"
38
39 using namespace bluetooth;
40
get_current_time()41 time_t get_current_time() { return time(0); }
42
43 namespace {
44
45 constexpr int64_t kTrafficLogTime = 120; // 120seconds
46 constexpr uint8_t kLogEntriesSize{15};
47 constexpr std::string_view kLogPerChannelProperty =
48 "bluetooth.powertelemetry.log_per_channel.enabled";
49 constexpr std::string_view kPowerTelemetryEnabledProperty =
50 "bluetooth.powertelemetry.enabled";
51 bool power_telemerty_enabled_ = false;
52
GetTimeString(time_t tstamp)53 std::string GetTimeString(time_t tstamp) {
54 char buffer[15];
55 tm* nTm = localtime(&tstamp);
56 strftime(buffer, 15, "%m-%d %H:%M:%S", nTm);
57 return std::string(buffer);
58 }
59
60 enum class State {
61 kDisconnected = 0,
62 kConnected = 1,
63 };
64
65 enum class ChannelType {
66 kUnknown = 0,
67 kRfcomm = 1,
68 kL2cap = 2,
69 };
70
PsmToChannelType(const uint16_t & psm)71 ChannelType PsmToChannelType(const uint16_t& psm) {
72 switch (psm) {
73 case BT_PSM_RFCOMM:
74 return ChannelType::kRfcomm;
75 break;
76 }
77 return ChannelType::kL2cap;
78 }
79
80 struct Duration {
81 time_t begin = 0;
82 time_t end = 0;
83 };
84
85 struct DataTransfer {
86 struct {
87 int64_t bytes{0};
88 } rx, tx;
89 };
90
91 struct LinkDetails {
92 RawAddress bd_addr = RawAddress::kEmpty;
93 uint16_t handle = 0;
94 Duration duration;
95 uint8_t tx_power_level = 0;
96 };
97
98 struct ChannelDetails {
99 RawAddress bd_addr = RawAddress::kEmpty;
100 int32_t psm = 0;
101 struct {
102 uint16_t cid = 0;
103 } src, dst;
104 State state = State::kDisconnected;
105 ChannelType channel_type = ChannelType::kUnknown;
106 DataTransfer data_transfer;
107 Duration duration;
108 struct {
109 time_t last_data_sent = 0;
110 } rx, tx;
111 };
112
113 struct AclPacketDetails {
114 struct {
115 uint32_t pkt_count = 0;
116 int64_t byte_count = 0;
117 } rx, tx;
118 };
119
120 struct AdvDetails {
121 Duration active;
122 };
123
124 struct ScanDetails {
125 int32_t count = 0;
126 };
127
128 struct SniffData {
129 RawAddress bd_addr = RawAddress::kEmpty;
130 uint32_t sniff_count = 0, active_count = 0;
131 time_t sniff_duration_ts = 0, active_duration_ts = 0;
132 time_t last_mode_change_ts = get_current_time();
133 };
134
135 class LogDataContainer {
136 public:
137 struct Duration lifetime;
138 std::map<RawAddress, std::list<ChannelDetails>> channel_map;
139 DataTransfer l2c_data, rfc_data;
140 std::map<uint16_t, SniffData> sniff_activity_map;
141 struct {
142 std::map<uint16_t, LinkDetails> link_details_map;
143 std::list<LinkDetails> link_details_list;
144 } acl, sco;
145 std::list<AdvDetails> adv_list;
146 ScanDetails scan_details, inq_scan_details, le_scan_details;
147 AclPacketDetails acl_pkt_ds, hci_cmd_evt_ds;
148 };
149
150 } // namespace
151
152 struct power_telemetry::PowerTelemetryImpl {
PowerTelemetryImplpower_telemetry::PowerTelemetryImpl153 PowerTelemetryImpl() {
154 idx_containers = 0;
155 traffic_logged_ts_ = get_current_time();
156 log_per_channel_ = osi_property_get_bool(
157 std::string(kLogPerChannelProperty).c_str(), false);
158 power_telemetry_enabled_property_ = osi_property_get_bool(
159 std::string(kPowerTelemetryEnabledProperty).c_str(), true);
160
161 // Enable this feature when both feature flag and sysprops turn on.
162 power_telemerty_enabled_ =
163 com::android::bluetooth::flags::bluetooth_power_telemetry() &&
164 power_telemetry_enabled_property_;
165 }
166
GetCurrentLogDataContainerpower_telemetry::PowerTelemetryImpl167 LogDataContainer& GetCurrentLogDataContainer() {
168 return log_data_containers_[idx_containers];
169 }
170
maybe_log_datapower_telemetry::PowerTelemetryImpl171 void maybe_log_data() {
172 if ((get_current_time() - traffic_logged_ts_) >= kTrafficLogTime) {
173 LogDataTransfer();
174 }
175 }
176
177 void LogDataTransfer();
178 void RecordLogDataContainer();
179
180 mutable std::mutex dumpsys_mutex_;
181 LogDataContainer log_data_containers_[kLogEntriesSize];
182 std::atomic_int idx_containers;
183 time_t traffic_logged_ts_ = 0;
184 struct {
185 struct {
186 int64_t bytes_ = 0;
187 } rx, tx;
188 } l2c, rfc;
189 struct {
190 uint32_t pkt_ = 0;
191 int64_t len_ = 0;
192 } rx, tx;
193
194 struct {
195 uint16_t count_ = 0;
196 } scan, inq_scan, ble_adv, ble_scan;
197
198 struct {
199 uint32_t count_ = 0;
200 } cmd, event;
201 bool scan_timer_started_ = false;
202 bool log_per_channel_ = false;
203 bool power_telemetry_enabled_property_ = false;
204 };
205
LogDataTransfer()206 void power_telemetry::PowerTelemetryImpl::LogDataTransfer() {
207 if (!power_telemerty_enabled_) return;
208
209 LogDataContainer& ldc = GetCurrentLogDataContainer();
210
211 if ((l2c.rx.bytes_ != 0) || (l2c.tx.bytes_ != 0)) {
212 ldc.l2c_data = {
213 .rx =
214 {
215 .bytes = l2c.rx.bytes_,
216 },
217 .tx =
218 {
219 .bytes = l2c.tx.bytes_,
220 },
221 };
222 l2c = {};
223 }
224
225 if ((rfc.rx.bytes_ != 0) || (rfc.tx.bytes_ != 0)) {
226 ldc.rfc_data = {
227 .rx =
228 {
229 .bytes = rfc.rx.bytes_,
230 },
231 .tx =
232 {
233 .bytes = rfc.tx.bytes_,
234 },
235 };
236 rfc = {};
237 }
238
239 if (scan.count_ != 0) {
240 ldc.scan_details = {
241 .count = scan.count_,
242 };
243 scan.count_ = 0;
244 }
245
246 if (inq_scan.count_ != 0) {
247 ldc.inq_scan_details = {
248 .count = inq_scan.count_,
249 };
250 inq_scan.count_ = 0;
251 }
252
253 if ((rx.pkt_ != 0) || (tx.pkt_ != 0)) {
254 ldc.acl_pkt_ds = {
255 .rx =
256 {
257 .pkt_count = rx.pkt_,
258 .byte_count = rx.len_,
259 },
260 .tx =
261 {
262 .pkt_count = tx.pkt_,
263 .byte_count = tx.len_,
264 },
265 };
266 rx.pkt_ = tx.pkt_ = rx.len_ = tx.len_ = 0;
267 }
268
269 if ((cmd.count_ != 0) || (event.count_ != 0)) {
270 ldc.hci_cmd_evt_ds = {
271 .rx =
272 {
273 .pkt_count = event.count_,
274 },
275 .tx =
276 {
277 .pkt_count = cmd.count_,
278 },
279 };
280 cmd.count_ = event.count_ = 0;
281 }
282
283 if (ble_scan.count_ != 0) {
284 ldc.le_scan_details = {
285 .count = ble_scan.count_,
286 };
287 ble_scan.count_ = 0;
288 }
289
290 ldc.lifetime.begin = traffic_logged_ts_;
291 ldc.lifetime.end = get_current_time();
292
293 traffic_logged_ts_ = get_current_time();
294 RecordLogDataContainer();
295 }
296
RecordLogDataContainer()297 void power_telemetry::PowerTelemetryImpl::RecordLogDataContainer() {
298 if (!power_telemerty_enabled_) return;
299
300 LogDataContainer& ldc = GetCurrentLogDataContainer();
301
302 log::info(
303 "bt_power: scan: {}, inqScan: {}, aclTx: {}, aclRx: {}, hciCmd: {}, "
304 "hciEvt: {}, bleScan: {}",
305 ldc.scan_details.count, ldc.inq_scan_details.count,
306 ldc.acl_pkt_ds.tx.pkt_count, ldc.acl_pkt_ds.rx.pkt_count,
307 ldc.hci_cmd_evt_ds.tx.pkt_count, ldc.hci_cmd_evt_ds.rx.pkt_count,
308 ldc.le_scan_details.count);
309
310 idx_containers++;
311 if (idx_containers >= kLogEntriesSize) {
312 idx_containers = 0;
313 }
314
315 log_data_containers_[idx_containers] = LogDataContainer();
316 }
317
GetInstance()318 power_telemetry::PowerTelemetry& power_telemetry::GetInstance() {
319 static power_telemetry::PowerTelemetry power_telemetry;
320 return power_telemetry;
321 }
322
PowerTelemetry()323 power_telemetry::PowerTelemetry::PowerTelemetry() {
324 pimpl_ = std::make_unique<PowerTelemetryImpl>();
325 }
326
LogInqScanStarted()327 void power_telemetry::PowerTelemetry::LogInqScanStarted() {
328 if (!power_telemerty_enabled_) return;
329
330 std::lock_guard<std::mutex> lock(pimpl_->dumpsys_mutex_);
331 pimpl_->inq_scan.count_++;
332 pimpl_->maybe_log_data();
333 }
334
LogInqScanStopped()335 void power_telemetry::PowerTelemetry::LogInqScanStopped() {
336 if (!power_telemerty_enabled_) return;
337
338 std::lock_guard<std::mutex> lock(pimpl_->dumpsys_mutex_);
339 pimpl_->maybe_log_data();
340 }
341
LogBleScan(uint16_t num_resps)342 void power_telemetry::PowerTelemetry::LogBleScan(uint16_t num_resps) {
343 if (!power_telemerty_enabled_) return;
344
345 std::lock_guard<std::mutex> lock(pimpl_->dumpsys_mutex_);
346 pimpl_->ble_scan.count_ += num_resps;
347 pimpl_->maybe_log_data();
348 }
349
LogBleAdvStarted()350 void power_telemetry::PowerTelemetry::LogBleAdvStarted() {
351 if (!power_telemerty_enabled_) return;
352
353 std::lock_guard<std::mutex> lock(pimpl_->dumpsys_mutex_);
354 const time_t current_time = get_current_time();
355 LogDataContainer& ldc = pimpl_->GetCurrentLogDataContainer();
356 ldc.adv_list.emplace_back(AdvDetails{.active.begin = current_time});
357 }
358
LogBleAdvStopped()359 void power_telemetry::PowerTelemetry::LogBleAdvStopped() {
360 if (!power_telemerty_enabled_) return;
361
362 std::lock_guard<std::mutex> lock(pimpl_->dumpsys_mutex_);
363 const time_t current_time = get_current_time();
364
365 LogDataContainer& ldc = pimpl_->GetCurrentLogDataContainer();
366 if (ldc.adv_list.size() == 0) {
367 log::warn("Empty advList. Skip LogBleAdvDetails.");
368 return;
369 }
370 ldc.adv_list.back().active.end = current_time;
371 }
372
LogTxPower(void * res)373 void power_telemetry::PowerTelemetry::LogTxPower(void* res) {
374 if (!power_telemerty_enabled_) return;
375
376 std::lock_guard<std::mutex> lock(pimpl_->dumpsys_mutex_);
377 tBTM_TX_POWER_RESULT* result = (tBTM_TX_POWER_RESULT*)res;
378 LogDataContainer& ldc = pimpl_->GetCurrentLogDataContainer();
379
380 if (result->status != BTM_SUCCESS) {
381 return;
382 }
383
384 for (auto it : ldc.acl.link_details_map) {
385 uint16_t handle = it.first;
386 LinkDetails lds = it.second;
387 if (lds.bd_addr == result->rem_bda) {
388 lds.tx_power_level = result->tx_power;
389 ldc.acl.link_details_map[handle] = lds;
390 break;
391 }
392 }
393 pimpl_->maybe_log_data();
394 }
395
LogLinkDetails(uint16_t handle,const RawAddress & bd_addr,bool is_connected,bool is_acl_link)396 void power_telemetry::PowerTelemetry::LogLinkDetails(uint16_t handle,
397 const RawAddress& bd_addr,
398 bool is_connected,
399 bool is_acl_link) {
400 if (!power_telemerty_enabled_) return;
401
402 std::lock_guard<std::mutex> lock(pimpl_->dumpsys_mutex_);
403 LogDataContainer& ldc = pimpl_->GetCurrentLogDataContainer();
404 std::map<uint16_t, LinkDetails>& link_map =
405 is_acl_link ? ldc.acl.link_details_map : ldc.sco.link_details_map;
406 std::list<LinkDetails>& link_list =
407 is_acl_link ? ldc.acl.link_details_list : ldc.sco.link_details_list;
408
409 if (is_connected == false && link_map.count(handle) != 0) {
410 LinkDetails link_details = link_map[handle];
411 link_details.duration.end = get_current_time();
412 link_list.push_back(link_details);
413 link_map.erase(handle);
414 } else if (is_connected == true) {
415 link_map[handle] = {
416 .bd_addr = bd_addr,
417 .handle = handle,
418 .duration.begin = get_current_time(),
419 .tx_power_level = 0,
420 };
421
422 if (is_acl_link) {
423 SniffData sniff_data;
424 if (ldc.sniff_activity_map.count(handle) != 0) {
425 ldc.sniff_activity_map.erase(handle);
426 }
427 sniff_data.bd_addr = bd_addr;
428 sniff_data.active_count = 1;
429 sniff_data.last_mode_change_ts = get_current_time();
430 ldc.sniff_activity_map[handle] = sniff_data;
431 }
432 }
433
434 pimpl_->maybe_log_data();
435 }
436
LogHciCmdDetail()437 void power_telemetry::PowerTelemetry::LogHciCmdDetail() {
438 if (!power_telemerty_enabled_) return;
439
440 std::lock_guard<std::mutex> lock(pimpl_->dumpsys_mutex_);
441 pimpl_->cmd.count_++;
442 pimpl_->maybe_log_data();
443 }
444
LogHciEvtDetail()445 void power_telemetry::PowerTelemetry::LogHciEvtDetail() {
446 if (!power_telemerty_enabled_) return;
447
448 std::lock_guard<std::mutex> lock(pimpl_->dumpsys_mutex_);
449 pimpl_->event.count_++;
450 pimpl_->maybe_log_data();
451 }
452
LogSniffStarted(uint16_t handle,const RawAddress & bd_addr)453 void power_telemetry::PowerTelemetry::LogSniffStarted(
454 uint16_t handle, const RawAddress& bd_addr) {
455 if (!power_telemerty_enabled_) return;
456
457 std::lock_guard<std::mutex> lock(pimpl_->dumpsys_mutex_);
458 const time_t current_timestamp = get_current_time();
459 SniffData sniff_data;
460 LogDataContainer& ldc = pimpl_->GetCurrentLogDataContainer();
461 if (ldc.sniff_activity_map.count(handle) == 0) {
462 sniff_data.bd_addr = bd_addr;
463 } else {
464 sniff_data = ldc.sniff_activity_map[handle];
465 }
466 sniff_data.sniff_count++;
467 sniff_data.active_duration_ts +=
468 current_timestamp - sniff_data.last_mode_change_ts;
469 sniff_data.last_mode_change_ts = get_current_time();
470 ldc.sniff_activity_map[handle] = sniff_data;
471
472 pimpl_->maybe_log_data();
473 }
474
LogSniffStopped(uint16_t handle,const RawAddress & bd_addr)475 void power_telemetry::PowerTelemetry::LogSniffStopped(
476 uint16_t handle, const RawAddress& bd_addr) {
477 if (!power_telemerty_enabled_) return;
478
479 std::lock_guard<std::mutex> lock(pimpl_->dumpsys_mutex_);
480 const time_t current_timestamp = get_current_time();
481 SniffData sniff_data;
482 LogDataContainer& ldc = pimpl_->GetCurrentLogDataContainer();
483 if (ldc.sniff_activity_map.count(handle) == 0) {
484 sniff_data.bd_addr = bd_addr;
485 } else {
486 sniff_data = ldc.sniff_activity_map[handle];
487 }
488 sniff_data.active_count++;
489 sniff_data.sniff_duration_ts +=
490 current_timestamp - sniff_data.last_mode_change_ts;
491 sniff_data.last_mode_change_ts = get_current_time();
492 ldc.sniff_activity_map[handle] = sniff_data;
493
494 pimpl_->maybe_log_data();
495 }
496
LogScanStarted()497 void power_telemetry::PowerTelemetry::LogScanStarted() {
498 if (!power_telemerty_enabled_) return;
499
500 std::lock_guard<std::mutex> lock(pimpl_->dumpsys_mutex_);
501 pimpl_->scan.count_++;
502 pimpl_->maybe_log_data();
503 }
504
LogTxAclPktData(uint16_t len)505 void power_telemetry::PowerTelemetry::LogTxAclPktData(uint16_t len) {
506 if (!power_telemerty_enabled_) return;
507
508 std::lock_guard<std::mutex> lock(pimpl_->dumpsys_mutex_);
509 pimpl_->tx.pkt_++;
510 pimpl_->tx.len_ += len;
511 pimpl_->maybe_log_data();
512 }
513
LogRxAclPktData(uint16_t len)514 void power_telemetry::PowerTelemetry::LogRxAclPktData(uint16_t len) {
515 if (!power_telemerty_enabled_) return;
516
517 std::lock_guard<std::mutex> lock(pimpl_->dumpsys_mutex_);
518 pimpl_->rx.pkt_++;
519 pimpl_->rx.len_ += len;
520 pimpl_->maybe_log_data();
521 }
522
LogChannelConnected(uint16_t psm,int32_t src_id,int32_t dst_id,const RawAddress & bd_addr)523 void power_telemetry::PowerTelemetry::LogChannelConnected(
524 uint16_t psm, int32_t src_id, int32_t dst_id, const RawAddress& bd_addr) {
525 if (!power_telemerty_enabled_) return;
526
527 std::lock_guard<std::mutex> lock(pimpl_->dumpsys_mutex_);
528 std::list<ChannelDetails> channel_details_list;
529 LogDataContainer& ldc = pimpl_->GetCurrentLogDataContainer();
530 const ChannelType channel_type = PsmToChannelType(psm);
531 ChannelDetails channel_details = {
532 .bd_addr = bd_addr,
533 .psm = psm,
534 .src.cid = static_cast<uint16_t>(src_id),
535 .dst.cid = static_cast<uint16_t>(dst_id),
536 .state = State::kConnected,
537 .channel_type = channel_type,
538 .data_transfer = {},
539 .duration.begin = get_current_time(),
540 .rx = {},
541 .tx = {},
542 };
543
544 if (ldc.channel_map.count(bd_addr) == 0) {
545 ldc.channel_map.insert(std::pair<RawAddress, std::list<ChannelDetails>>(
546 bd_addr, std::list<ChannelDetails>({channel_details})));
547 } else {
548 ldc.channel_map[bd_addr].emplace_back(channel_details);
549 }
550
551 pimpl_->maybe_log_data();
552 }
553
LogChannelDisconnected(uint16_t psm,int32_t src_id,int32_t dst_id,const RawAddress & bd_addr)554 void power_telemetry::PowerTelemetry::LogChannelDisconnected(
555 uint16_t psm, int32_t src_id, int32_t dst_id, const RawAddress& bd_addr) {
556 if (!power_telemerty_enabled_) return;
557
558 std::lock_guard<std::mutex> lock(pimpl_->dumpsys_mutex_);
559 std::list<ChannelDetails> channel_details_list;
560 LogDataContainer& ldc = pimpl_->GetCurrentLogDataContainer();
561 if (ldc.channel_map.count(bd_addr) == 0) {
562 return;
563 }
564
565 const ChannelType channel_type = PsmToChannelType(psm);
566
567 for (auto& channel_detail : ldc.channel_map[bd_addr]) {
568 if (channel_detail.src.cid == src_id && channel_detail.dst.cid == dst_id &&
569 channel_detail.channel_type == channel_type) {
570 channel_detail.state = State::kDisconnected;
571 channel_detail.duration.end = get_current_time();
572 break;
573 }
574 }
575
576 pimpl_->maybe_log_data();
577 }
578
LogTxBytes(uint16_t psm,int32_t src_id,int32_t dst_id,const RawAddress & bd_addr,int32_t num_bytes)579 void power_telemetry::PowerTelemetry::LogTxBytes(uint16_t psm, int32_t src_id,
580 int32_t dst_id,
581 const RawAddress& bd_addr,
582 int32_t num_bytes) {
583 if (!power_telemerty_enabled_) return;
584
585 const ChannelType channel_type = PsmToChannelType(psm);
586 std::lock_guard<std::mutex> lock(pimpl_->dumpsys_mutex_);
587 if (pimpl_->log_per_channel_ == true) {
588 std::list<ChannelDetails> channel_details_list;
589 LogDataContainer& ldc = pimpl_->GetCurrentLogDataContainer();
590 if (ldc.channel_map.count(bd_addr) == 0) {
591 return;
592 }
593
594 for (auto& channel_details : ldc.channel_map[bd_addr]) {
595 if (channel_details.src.cid == src_id &&
596 channel_details.dst.cid == dst_id &&
597 channel_details.channel_type == channel_type) {
598 channel_details.data_transfer.tx.bytes += num_bytes;
599 channel_details.tx.last_data_sent = get_current_time();
600 break;
601 }
602 }
603 }
604 if (channel_type == ChannelType::kRfcomm) {
605 pimpl_->rfc.tx.bytes_ += num_bytes;
606 } else {
607 pimpl_->l2c.tx.bytes_ += num_bytes;
608 }
609 pimpl_->maybe_log_data();
610 }
611
LogRxBytes(uint16_t psm,int32_t src_id,int32_t dst_id,const RawAddress & bd_addr,int32_t num_bytes)612 void power_telemetry::PowerTelemetry::LogRxBytes(uint16_t psm, int32_t src_id,
613 int32_t dst_id,
614 const RawAddress& bd_addr,
615 int32_t num_bytes) {
616 if (!power_telemerty_enabled_) return;
617
618 const ChannelType channel_type = PsmToChannelType(psm);
619 std::lock_guard<std::mutex> lock(pimpl_->dumpsys_mutex_);
620 if (pimpl_->log_per_channel_ == true) {
621 std::list<ChannelDetails> channel_details_list;
622 LogDataContainer& ldc = pimpl_->GetCurrentLogDataContainer();
623 if (ldc.channel_map.count(bd_addr) == 0) {
624 return;
625 }
626
627 for (auto& channel_detail : ldc.channel_map[bd_addr]) {
628 if (channel_detail.src.cid == src_id &&
629 channel_detail.dst.cid == dst_id &&
630 channel_detail.channel_type == channel_type) {
631 channel_detail.data_transfer.rx.bytes += num_bytes;
632 channel_detail.rx.last_data_sent = get_current_time();
633 break;
634 }
635 }
636 }
637
638 switch (channel_type) {
639 case ChannelType::kRfcomm:
640 pimpl_->rfc.rx.bytes_ += num_bytes;
641 break;
642 case ChannelType::kL2cap:
643 pimpl_->l2c.rx.bytes_ += num_bytes;
644 break;
645 case ChannelType::kUnknown:
646 break;
647 }
648
649 pimpl_->maybe_log_data();
650 }
651
Dumpsys(int32_t fd)652 void power_telemetry::PowerTelemetry::Dumpsys(int32_t fd) {
653 if (!power_telemerty_enabled_) return;
654
655 std::lock_guard<std::mutex> lock(pimpl_->dumpsys_mutex_);
656 pimpl_->RecordLogDataContainer();
657
658 dprintf(fd, "\nPower Telemetry Data:\n");
659 dprintf(fd, "\nBR/EDR Scan Events:\n");
660 dprintf(fd, "%-22s %-22s %-15s\n", "StartTimeStamp", "EndTimeStamp",
661 "Number of Scans");
662 for (auto&& ldc : pimpl_->log_data_containers_) {
663 if (ldc.scan_details.count == 0) {
664 continue;
665 }
666 dprintf(fd, "%-22s %-22s %-15d\n",
667 GetTimeString(ldc.lifetime.begin).c_str(),
668 GetTimeString(ldc.lifetime.end).c_str(), ldc.scan_details.count);
669 }
670 dprintf(fd, "\nBR/EDR InqScan Events:\n");
671 dprintf(fd, "%-22s %-22s %-15s\n", "StartTimeStamp", "EndTimeStamp",
672 "Number of InqScans");
673 for (auto&& ldc : pimpl_->log_data_containers_) {
674 if (ldc.inq_scan_details.count == 0) {
675 continue;
676 }
677 dprintf(
678 fd, "%-22s %-22s %-15d\n", GetTimeString(ldc.lifetime.begin).c_str(),
679 GetTimeString(ldc.lifetime.end).c_str(), ldc.inq_scan_details.count);
680 }
681
682 dprintf(fd, "\nACL Packet Details:\n");
683 dprintf(fd, "%-22s %-22s %-12s %-12s %-12s %-12s\n", "StartTimeStamp",
684 "EndTimeStamp", "Tx Packets", "Tx Bytes", "Rx Packets", "Rx Bytes");
685 for (auto&& ldc : pimpl_->log_data_containers_) {
686 if ((ldc.acl_pkt_ds.tx.byte_count == 0) &&
687 (ldc.acl_pkt_ds.rx.byte_count == 0)) {
688 continue;
689 }
690 dprintf(fd, "%-22s %-22s %-12d %-12ld %-12d %-12ld\n",
691 GetTimeString(ldc.lifetime.begin).c_str(),
692 GetTimeString(ldc.lifetime.end).c_str(),
693 ldc.acl_pkt_ds.tx.pkt_count, (long)ldc.acl_pkt_ds.tx.byte_count,
694 ldc.acl_pkt_ds.rx.pkt_count, (long)ldc.acl_pkt_ds.rx.byte_count);
695 }
696
697 dprintf(fd, "\nHCI CMD/EVT Details:\n");
698 dprintf(fd, "%-22s %-22s %-14s %-14s\n", "StartTimeStamp", "EndTimeStamp",
699 "HCI Commands", "HCI Events");
700 for (auto&& ldc : pimpl_->log_data_containers_) {
701 if ((ldc.hci_cmd_evt_ds.tx.pkt_count == 0) &&
702 (ldc.hci_cmd_evt_ds.rx.pkt_count == 0)) {
703 continue;
704 }
705 dprintf(fd, "%-22s %-22s %-14d %-14d\n",
706 GetTimeString(ldc.lifetime.begin).c_str(),
707 GetTimeString(ldc.lifetime.end).c_str(),
708 ldc.hci_cmd_evt_ds.tx.pkt_count, ldc.hci_cmd_evt_ds.rx.pkt_count);
709 }
710 dprintf(fd, "\nBLE Scan Details:\n");
711 dprintf(fd, "%-22s %-22s %-14s\n", "StartTimeStamp", "EndTimeStamp",
712 "Number of scans");
713 for (auto&& ldc : pimpl_->log_data_containers_) {
714 if (ldc.le_scan_details.count == 0) {
715 continue;
716 }
717 dprintf(fd, "%-22s %-22s %-14d\n",
718 GetTimeString(ldc.lifetime.begin).c_str(),
719 GetTimeString(ldc.lifetime.end).c_str(), ldc.le_scan_details.count);
720 }
721 dprintf(fd, "\nL2CAP/RFCOMM Channel Events:\n");
722 dprintf(fd, "%-19s %-7s %-7s %-7s %-8s %-22s", "RemoteAddress", "Type",
723 "SrcId", "DstId", "PSM", "ConnectedTimeStamp");
724 dprintf(fd, " %-22s %-14s ", "DisconnectedTimeStamp", "State");
725 if (pimpl_->log_per_channel_ == true) {
726 dprintf(fd, " %-10s %-10s %-22s %-22s", "TxBytes", "RxBytes",
727 "LastTxTimeStamp", "LastRxTimeStamp");
728 }
729 dprintf(fd, "\n");
730 for (auto&& ldc : pimpl_->log_data_containers_) {
731 for (auto& itr : ldc.channel_map) {
732 const RawAddress& bd_addr = itr.first;
733 std::list<ChannelDetails> channel_details_list = itr.second;
734 for (auto& channel_details : channel_details_list) {
735 dprintf(fd, "%-19s ", ADDRESS_TO_LOGGABLE_CSTR(bd_addr));
736 dprintf(fd, "%-7s %-7d %-7d %-8d %-22s %-22s %-14s",
737 (channel_details.channel_type == ChannelType::kRfcomm)
738 ? "RFCOMM"
739 : "L2CAP",
740 channel_details.src.cid, channel_details.dst.cid,
741 channel_details.psm,
742 GetTimeString(channel_details.duration.begin).c_str(),
743 GetTimeString(channel_details.duration.end).c_str(),
744 (channel_details.state == State::kDisconnected) ? "DISCONNECTED"
745 : "CONNECTED");
746 if (pimpl_->log_per_channel_ == true) {
747 dprintf(fd, "%-10ld %-10ld %-22s %-22s",
748 (long)channel_details.data_transfer.tx.bytes,
749 (long)channel_details.data_transfer.rx.bytes,
750 GetTimeString(channel_details.tx.last_data_sent).c_str(),
751 GetTimeString(channel_details.rx.last_data_sent).c_str());
752 }
753 dprintf(fd, "\n");
754 }
755 }
756 }
757
758 dprintf(fd, "\n\nBluetooth Data Traffic Details\n");
759 dprintf(fd, "L2cap Data Traffic\n");
760 dprintf(fd, "%-22s %-22s %-10s %-10s\n", "StartTime", "EndTime", "TxBytes",
761 "RxBytes");
762 for (auto&& ldc : pimpl_->log_data_containers_) {
763 if (ldc.l2c_data.tx.bytes == 0 && ldc.l2c_data.rx.bytes) {
764 continue;
765 }
766 dprintf(fd, "%-22s %-22s %-10ld %-10ld\n",
767 GetTimeString(ldc.lifetime.begin).c_str(),
768 GetTimeString(ldc.lifetime.end).c_str(),
769 (long)ldc.l2c_data.tx.bytes, (long)ldc.l2c_data.rx.bytes);
770 }
771
772 dprintf(fd, "\nRfcomm Data Traffic\n");
773 dprintf(fd, "%-22s %-22s %-10s %-10s\n", "StartTime", "EndTime", "TxBytes",
774 "RxBytes");
775 for (auto&& ldc : pimpl_->log_data_containers_) {
776 if (ldc.rfc_data.tx.bytes == 0 && ldc.rfc_data.rx.bytes == 0) {
777 continue;
778 }
779 dprintf(fd, "%-22s %-22s %-10ld %-10ld\n",
780 GetTimeString(ldc.lifetime.begin).c_str(),
781 GetTimeString(ldc.lifetime.end).c_str(),
782 (long)ldc.rfc_data.tx.bytes, (long)ldc.rfc_data.rx.bytes);
783 }
784
785 dprintf(fd, "\n\nSniff Activity Details\n");
786 dprintf(fd, "%-8s %-19s %-19s %-24s %-19s %-24s\n", "Handle", "BDADDR",
787 "ActiveModeCount", "ActiveModeDuration(sec)", "SniffModeCount",
788 "SniffModeDuration(sec)");
789 for (auto&& ldc : pimpl_->log_data_containers_) {
790 for (auto itr : ldc.sniff_activity_map) {
791 uint16_t handle = itr.first;
792 SniffData sniff_data = itr.second;
793 dprintf(fd, "%-8d %-19s %-19d %-24ld %-19d %-24ld\n", handle,
794 ADDRESS_TO_LOGGABLE_CSTR(sniff_data.bd_addr),
795 sniff_data.active_count, (long)sniff_data.active_duration_ts,
796 sniff_data.sniff_count, (long)sniff_data.sniff_duration_ts);
797 }
798 }
799
800 dprintf(fd, "\n\nACL Link Details\n");
801 dprintf(fd, "%-6s %-19s %-22s %-22s %-8s\n", "handle", "BDADDR",
802 "ConnectedTimeStamp", "DisconnectedTimeStamp", "TxPower");
803 for (auto&& ldc : pimpl_->log_data_containers_) {
804 for (auto it : ldc.acl.link_details_map) {
805 uint16_t handle = it.first;
806 LinkDetails lds = it.second;
807 dprintf(fd, "%-6d %-19s %-22s %-22s %-8d\n", handle,
808 ADDRESS_TO_LOGGABLE_CSTR(lds.bd_addr),
809 GetTimeString(lds.duration.begin).c_str(),
810 GetTimeString(lds.duration.end).c_str(), lds.tx_power_level);
811 }
812
813 for (auto& it : ldc.acl.link_details_list) {
814 dprintf(fd, "%-6d %-19s %-22s %-22s %-8d\n", it.handle,
815 ADDRESS_TO_LOGGABLE_CSTR(it.bd_addr),
816 GetTimeString(it.duration.begin).c_str(),
817 GetTimeString(it.duration.end).c_str(), it.tx_power_level);
818 }
819 }
820 dprintf(fd, "\nSCO Link Details\n");
821 dprintf(fd, "%-6s %-19s %-22s %-22s\n", "handle", "BDADDR",
822 "ConnectedTimeStamp", "DisconnectedTimeStamp");
823 for (auto&& ldc : pimpl_->log_data_containers_) {
824 for (auto& it : ldc.sco.link_details_list) {
825 dprintf(fd, "%-6d %-19s %-22s %-22s\n", it.handle,
826 ADDRESS_TO_LOGGABLE_CSTR(it.bd_addr),
827 GetTimeString(it.duration.begin).c_str(),
828 GetTimeString(it.duration.end).c_str());
829 }
830 }
831
832 dprintf(fd, "\n\n");
833 }
834