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