• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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