From 73326cdd83dc8e00453222a3e72ace6f6d008578 Mon Sep 17 00:00:00 2001 From: Michael Sun Date: Thu, 31 Dec 2020 00:19:41 +0000 Subject: [PATCH 1/9] btaa: handle wakeup notification Compare the wakeup reason to verify if Bluetooth was the wakeup source and record the wakeup event for future processing. Tag: #feature Bug: 177228387 Test: verified locally BTAA module receives and parses Bluetooth wakeup reasons. BYPASS_LONG_LINES_REASON: consist with gd format Change-Id: I301d2a372ddaebdf0818e368019cb8043c2034c5 --- gd/Android.bp | 1 + gd/btaa/Android.bp | 6 ++++ gd/btaa/activity_attribution.h | 1 + gd/btaa/android/activity_attribution.cc | 17 ++++++++++ gd/btaa/attribution_processor.h | 31 ++++++++++++++++++ gd/btaa/host/activity_attribution.cc | 5 +-- .../linux_generic/attribution_processor.cc | 32 +++++++++++++++++++ 7 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 gd/btaa/attribution_processor.h create mode 100644 gd/btaa/linux_generic/attribution_processor.cc diff --git a/gd/Android.bp b/gd/Android.bp index a74a9cfbb6..21ba08c3e2 100644 --- a/gd/Android.bp +++ b/gd/Android.bp @@ -119,6 +119,7 @@ cc_defaults { target: { linux: { srcs: [ + ":BluetoothBtaaSources_linux_generic", ":BluetoothOsSources_linux_generic", ], }, diff --git a/gd/btaa/Android.bp b/gd/btaa/Android.bp index b77a8241c4..671e0188c8 100644 --- a/gd/btaa/Android.bp +++ b/gd/btaa/Android.bp @@ -20,3 +20,9 @@ filegroup { "host/activity_attribution.cc", ], } +filegroup { + name: "BluetoothBtaaSources_linux_generic", + srcs: [ + "linux_generic/attribution_processor.cc", + ], +} diff --git a/gd/btaa/activity_attribution.h b/gd/btaa/activity_attribution.h index bc0ba4f4d6..d22cfe3453 100644 --- a/gd/btaa/activity_attribution.h +++ b/gd/btaa/activity_attribution.h @@ -50,6 +50,7 @@ class ActivityAttribution : public bluetooth::Module { ~ActivityAttribution() = default; void Capture(const hal::HciPacket& packet, hal::SnoopLogger::PacketType type); + void OnWakeup(); void RegisterActivityAttributionCallback(ActivityAttributionCallback* callback); static const ModuleFactory Factory; diff --git a/gd/btaa/android/activity_attribution.cc b/gd/btaa/android/activity_attribution.cc index 6ae070463c..cd6e588191 100644 --- a/gd/btaa/android/activity_attribution.cc +++ b/gd/btaa/android/activity_attribution.cc @@ -23,6 +23,7 @@ #include #include +#include "btaa/attribution_processor.h" #include "module.h" #include "os/log.h" @@ -39,6 +40,7 @@ namespace activity_attribution { const ModuleFactory ActivityAttribution::Factory = ModuleFactory([]() { return new ActivityAttribution(); }); static const std::string kBtWakelockName("hal_bluetooth_lock"); +static const std::string kBtWakeupReason("hs_uart_wakeup"); struct wakelock_callback : public BnWakelockCallback { wakelock_callback(ActivityAttribution* module) : module_(module) {} @@ -57,6 +59,12 @@ struct wakeup_callback : public BnSuspendCallback { wakeup_callback(ActivityAttribution* module) : module_(module) {} Status notifyWakeup(bool success, const std::vector& wakeup_reasons) override { + for (auto& wakeup_reason : wakeup_reasons) { + if (wakeup_reason.find(kBtWakeupReason) != std::string::npos) { + module_->OnWakeup(); + break; + } + } return Status::ok(); } @@ -91,11 +99,16 @@ struct ActivityAttribution::impl { void on_hci_packet(hal::HciPacket packet, hal::SnoopLogger::PacketType type, uint16_t length) {} + void on_wakeup() { + attribution_processor_.OnWakeup(); + } + void register_callback(ActivityAttributionCallback* callback) { callback_ = callback; } ActivityAttributionCallback* callback_; + AttributionProcessor attribution_processor_; }; void ActivityAttribution::Capture(const hal::HciPacket& packet, hal::SnoopLogger::PacketType type) { @@ -122,6 +135,10 @@ void ActivityAttribution::Capture(const hal::HciPacket& packet, hal::SnoopLogger CallOn(pimpl_.get(), &impl::on_hci_packet, truncate_packet, type, original_length); } +void ActivityAttribution::OnWakeup() { + CallOn(pimpl_.get(), &impl::on_wakeup); +} + void ActivityAttribution::RegisterActivityAttributionCallback(ActivityAttributionCallback* callback) { CallOn(pimpl_.get(), &impl::register_callback, callback); } diff --git a/gd/btaa/attribution_processor.h b/gd/btaa/attribution_processor.h new file mode 100644 index 0000000000..e8d67d72a9 --- /dev/null +++ b/gd/btaa/attribution_processor.h @@ -0,0 +1,31 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +namespace bluetooth { +namespace activity_attribution { + +class AttributionProcessor { + public: + void OnWakeup(); + + private: + bool wakeup_ = false; +}; + +} // namespace activity_attribution +} // namespace bluetooth diff --git a/gd/btaa/host/activity_attribution.cc b/gd/btaa/host/activity_attribution.cc index e9f4134400..5f047eefe2 100644 --- a/gd/btaa/host/activity_attribution.cc +++ b/gd/btaa/host/activity_attribution.cc @@ -23,8 +23,9 @@ namespace activity_attribution { struct ActivityAttribution::impl {}; -void ActivityAttribution::RegisterActivityAttributionCallback( - ActivityAttributionCallback* callback) {} +void ActivityAttribution::OnWakeup() {} + +void ActivityAttribution::RegisterActivityAttributionCallback(ActivityAttributionCallback* callback) {} std::string ActivityAttribution::ToString() const { return "Btaa Module"; diff --git a/gd/btaa/linux_generic/attribution_processor.cc b/gd/btaa/linux_generic/attribution_processor.cc new file mode 100644 index 0000000000..3f06f4e785 --- /dev/null +++ b/gd/btaa/linux_generic/attribution_processor.cc @@ -0,0 +1,32 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "btaa/attribution_processor.h" + +#include "os/log.h" + +namespace bluetooth { +namespace activity_attribution { + +void AttributionProcessor::OnWakeup() { + if (wakeup_) { + LOG_INFO("Previous wakeup notification is not consumed."); + } + wakeup_ = true; +} + +} // namespace activity_attribution +} // namespace bluetooth From f2ca418ce30bba2f5e7d75a84fa37d988198ccee Mon Sep 17 00:00:00 2001 From: Michael Sun Date: Thu, 31 Dec 2020 00:46:13 +0000 Subject: [PATCH 2/9] btaa: handle wakelock notification Handle wakelock acquire and release notification from system suspend service and record the wakelock duration upon release. Tag: #feature Bug: 177232907 Test: verified locally BTAA can capture and timestamp BT wakelocks BYPASS_LONG_LINES_REASON: consist with gd format Change-Id: I51dfdbec62b66d5a93f45d8ea2c52a16ce3beec1 --- gd/btaa/Android.bp | 1 + gd/btaa/activity_attribution.h | 2 + gd/btaa/android/activity_attribution.cc | 25 +++++++ gd/btaa/attribution_processor.h | 3 + gd/btaa/host/activity_attribution.cc | 4 ++ .../linux_generic/attribution_processor.cc | 2 + gd/btaa/linux_generic/wakelock_processor.cc | 67 +++++++++++++++++++ gd/btaa/wakelock_processor.h | 38 +++++++++++ 8 files changed, 142 insertions(+) create mode 100644 gd/btaa/linux_generic/wakelock_processor.cc create mode 100644 gd/btaa/wakelock_processor.h diff --git a/gd/btaa/Android.bp b/gd/btaa/Android.bp index 671e0188c8..de1ea925c3 100644 --- a/gd/btaa/Android.bp +++ b/gd/btaa/Android.bp @@ -24,5 +24,6 @@ filegroup { name: "BluetoothBtaaSources_linux_generic", srcs: [ "linux_generic/attribution_processor.cc", + "linux_generic/wakelock_processor.cc", ], } diff --git a/gd/btaa/activity_attribution.h b/gd/btaa/activity_attribution.h index d22cfe3453..2f0ae26af9 100644 --- a/gd/btaa/activity_attribution.h +++ b/gd/btaa/activity_attribution.h @@ -50,6 +50,8 @@ class ActivityAttribution : public bluetooth::Module { ~ActivityAttribution() = default; void Capture(const hal::HciPacket& packet, hal::SnoopLogger::PacketType type); + void OnWakelockAcquired(); + void OnWakelockReleased(); void OnWakeup(); void RegisterActivityAttributionCallback(ActivityAttributionCallback* callback); diff --git a/gd/btaa/android/activity_attribution.cc b/gd/btaa/android/activity_attribution.cc index cd6e588191..f673215a4f 100644 --- a/gd/btaa/android/activity_attribution.cc +++ b/gd/btaa/android/activity_attribution.cc @@ -24,6 +24,7 @@ #include #include "btaa/attribution_processor.h" +#include "btaa/wakelock_processor.h" #include "module.h" #include "os/log.h" @@ -46,9 +47,11 @@ struct wakelock_callback : public BnWakelockCallback { wakelock_callback(ActivityAttribution* module) : module_(module) {} Status notifyAcquired() override { + module_->OnWakelockAcquired(); return Status::ok(); } Status notifyReleased() override { + module_->OnWakelockReleased(); return Status::ok(); } @@ -99,6 +102,19 @@ struct ActivityAttribution::impl { void on_hci_packet(hal::HciPacket packet, hal::SnoopLogger::PacketType type, uint16_t length) {} + void on_wakelock_acquired() { + wakelock_processor_.OnWakelockAcquired(); + } + + void on_wakelock_released() { + uint32_t wakelock_duration_ms = 0; + + wakelock_duration_ms = wakelock_processor_.OnWakelockReleased(); + if (wakelock_duration_ms != 0) { + attribution_processor_.OnWakelockReleased(wakelock_duration_ms); + } + } + void on_wakeup() { attribution_processor_.OnWakeup(); } @@ -109,6 +125,7 @@ struct ActivityAttribution::impl { ActivityAttributionCallback* callback_; AttributionProcessor attribution_processor_; + WakelockProcessor wakelock_processor_; }; void ActivityAttribution::Capture(const hal::HciPacket& packet, hal::SnoopLogger::PacketType type) { @@ -135,6 +152,14 @@ void ActivityAttribution::Capture(const hal::HciPacket& packet, hal::SnoopLogger CallOn(pimpl_.get(), &impl::on_hci_packet, truncate_packet, type, original_length); } +void ActivityAttribution::OnWakelockAcquired() { + CallOn(pimpl_.get(), &impl::on_wakelock_acquired); +} + +void ActivityAttribution::OnWakelockReleased() { + CallOn(pimpl_.get(), &impl::on_wakelock_released); +} + void ActivityAttribution::OnWakeup() { CallOn(pimpl_.get(), &impl::on_wakeup); } diff --git a/gd/btaa/attribution_processor.h b/gd/btaa/attribution_processor.h index e8d67d72a9..98bfa6e717 100644 --- a/gd/btaa/attribution_processor.h +++ b/gd/btaa/attribution_processor.h @@ -16,11 +16,14 @@ #pragma once +#include + namespace bluetooth { namespace activity_attribution { class AttributionProcessor { public: + void OnWakelockReleased(uint32_t duration_ms); void OnWakeup(); private: diff --git a/gd/btaa/host/activity_attribution.cc b/gd/btaa/host/activity_attribution.cc index 5f047eefe2..2d9462a533 100644 --- a/gd/btaa/host/activity_attribution.cc +++ b/gd/btaa/host/activity_attribution.cc @@ -23,6 +23,10 @@ namespace activity_attribution { struct ActivityAttribution::impl {}; +void ActivityAttribution::OnWakelockAcquired() {} + +void ActivityAttribution::OnWakelockReleased() {} + void ActivityAttribution::OnWakeup() {} void ActivityAttribution::RegisterActivityAttributionCallback(ActivityAttributionCallback* callback) {} diff --git a/gd/btaa/linux_generic/attribution_processor.cc b/gd/btaa/linux_generic/attribution_processor.cc index 3f06f4e785..5130825953 100644 --- a/gd/btaa/linux_generic/attribution_processor.cc +++ b/gd/btaa/linux_generic/attribution_processor.cc @@ -21,6 +21,8 @@ namespace bluetooth { namespace activity_attribution { +void AttributionProcessor::OnWakelockReleased(uint32_t duration_ms) {} + void AttributionProcessor::OnWakeup() { if (wakeup_) { LOG_INFO("Previous wakeup notification is not consumed."); diff --git a/gd/btaa/linux_generic/wakelock_processor.cc b/gd/btaa/linux_generic/wakelock_processor.cc new file mode 100644 index 0000000000..bd3b3edc89 --- /dev/null +++ b/gd/btaa/linux_generic/wakelock_processor.cc @@ -0,0 +1,67 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "btaa/wakelock_processor.h" + +#include "os/log.h" + +namespace bluetooth { +namespace activity_attribution { + +static const int kWakelockMaxDurationMs(10000); + +WakelockProcessor::WakelockProcessor() { + wakelock_net_count_ = 0; + wakelock_acquired_time_ = {}; +} + +uint32_t WakelockProcessor::OnWakelockReleased() { + auto cur_time = std::chrono::system_clock::now(); + uint32_t wakelock_duration_ms = 0; + + if (wakelock_net_count_ == 0) { + LOG_INFO("Release a never acquired wakelock, ignored."); + } else { + wakelock_net_count_--; + if (wakelock_net_count_ == 0) { + wakelock_duration_ms = static_cast( + std::chrono::duration_cast(cur_time - wakelock_acquired_time_).count()); + wakelock_acquired_time_ = {}; + } + } + + return wakelock_duration_ms; +} + +void WakelockProcessor::OnWakelockAcquired() { + auto cur_time = std::chrono::system_clock::now(); + + if (wakelock_net_count_ == 0) { + if (wakelock_acquired_time_.time_since_epoch().count()) { + LOG_INFO("Previous wakelock acquired time is not consumed, dropped."); + } + wakelock_acquired_time_ = cur_time; + } else if (cur_time - wakelock_acquired_time_ > std::chrono::milliseconds(kWakelockMaxDurationMs)) { + LOG_INFO("Wakelock held for too long, likely we missed a release notification. Resetting wakelock stats."); + wakelock_net_count_ = 0; + wakelock_acquired_time_ = cur_time; + } + + wakelock_net_count_++; +} + +} // namespace activity_attribution +} // namespace bluetooth diff --git a/gd/btaa/wakelock_processor.h b/gd/btaa/wakelock_processor.h new file mode 100644 index 0000000000..8b700d2d84 --- /dev/null +++ b/gd/btaa/wakelock_processor.h @@ -0,0 +1,38 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace bluetooth { +namespace activity_attribution { + +class WakelockProcessor { + public: + WakelockProcessor(); + + uint32_t OnWakelockReleased(); + void OnWakelockAcquired(); + + private: + std::chrono::time_point wakelock_acquired_time_; + uint8_t wakelock_net_count_; +}; + +} // namespace activity_attribution +} // namespace bluetooth From ab349c16505fcec8f821d842c30b1c7567f594b0 Mon Sep 17 00:00:00 2001 From: Michael Sun Date: Thu, 31 Dec 2020 01:00:18 +0000 Subject: [PATCH 3/9] btaa: HCI command process Introduce the first phase of BTAA HCI command process. Upon receives a HCI command packet, processing module will search the opcode against a lookup table, only simple (contains only device info) and identifiable command will be processed. Pair information of connection handle and device address are associated and recorded for future references. The lookup table is a skelton implementation that does not contain 100% correct information. Tag: #feature Bug: 177230507 Test: verified locally BTAA can partially process HCI commands BYPASS_LONG_LINES_REASON: consist with gd format Change-Id: I7c8640e60ffa06f45953403549d28dc530383bd9 --- gd/btaa/Android.bp | 3 + gd/btaa/cmd_evt_classification.h | 34 ++ gd/btaa/hci_processor.h | 41 +++ .../linux_generic/cmd_evt_classification.cc | 331 ++++++++++++++++++ gd/btaa/linux_generic/hci_processor.cc | 93 +++++ 5 files changed, 502 insertions(+) create mode 100644 gd/btaa/cmd_evt_classification.h create mode 100644 gd/btaa/hci_processor.h create mode 100644 gd/btaa/linux_generic/cmd_evt_classification.cc create mode 100644 gd/btaa/linux_generic/hci_processor.cc diff --git a/gd/btaa/Android.bp b/gd/btaa/Android.bp index de1ea925c3..2aea7eefb1 100644 --- a/gd/btaa/Android.bp +++ b/gd/btaa/Android.bp @@ -20,10 +20,13 @@ filegroup { "host/activity_attribution.cc", ], } + filegroup { name: "BluetoothBtaaSources_linux_generic", srcs: [ "linux_generic/attribution_processor.cc", + "linux_generic/cmd_evt_classification.cc", + "linux_generic/hci_processor.cc", "linux_generic/wakelock_processor.cc", ], } diff --git a/gd/btaa/cmd_evt_classification.h b/gd/btaa/cmd_evt_classification.h new file mode 100644 index 0000000000..f7e21da9c0 --- /dev/null +++ b/gd/btaa/cmd_evt_classification.h @@ -0,0 +1,34 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "btaa/activity_attribution.h" +#include "hci/hci_packets.h" + +namespace bluetooth { +namespace activity_attribution { + +struct CmdEvtActivityClassification { + Activity activity; + uint16_t connection_handle_pos; + uint16_t address_pos; +}; + +CmdEvtActivityClassification lookup_cmd(hci::OpCode opcode); + +} // namespace activity_attribution +} // namespace bluetooth diff --git a/gd/btaa/hci_processor.h b/gd/btaa/hci_processor.h new file mode 100644 index 0000000000..3aa4d06076 --- /dev/null +++ b/gd/btaa/hci_processor.h @@ -0,0 +1,41 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "btaa/activity_attribution.h" +#include "hal/snoop_logger.h" +#include "hci/address.h" + +namespace bluetooth { +namespace activity_attribution { + +struct BtaaHciPacket { + Activity activity; + hci::Address address; + uint16_t byte_count; + BtaaHciPacket() {} + BtaaHciPacket(Activity activity, hci::Address address, uint16_t byte_count) + : activity(activity), address(address), byte_count(byte_count) {} +} __attribute__((__packed__)); + +class HciProcessor { + public: + std::vector OnHciPacket(hal::HciPacket packet, hal::SnoopLogger::PacketType type, uint16_t length); +}; + +} // namespace activity_attribution +} // namespace bluetooth diff --git a/gd/btaa/linux_generic/cmd_evt_classification.cc b/gd/btaa/linux_generic/cmd_evt_classification.cc new file mode 100644 index 0000000000..57421de4f7 --- /dev/null +++ b/gd/btaa/linux_generic/cmd_evt_classification.cc @@ -0,0 +1,331 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "btaa/cmd_evt_classification.h" + +namespace bluetooth { +namespace activity_attribution { + +CmdEvtActivityClassification lookup_cmd(hci::OpCode opcode) { + CmdEvtActivityClassification classification = {}; + switch (opcode) { + case hci::OpCode::INQUIRY: + case hci::OpCode::INQUIRY_CANCEL: + case hci::OpCode::PERIODIC_INQUIRY_MODE: + case hci::OpCode::EXIT_PERIODIC_INQUIRY_MODE: + classification = {.activity = Activity::SCAN, .connection_handle_pos = 0, .address_pos = 0}; + break; + + case hci::OpCode::CREATE_CONNECTION: + case hci::OpCode::CREATE_CONNECTION_CANCEL: + case hci::OpCode::ACCEPT_CONNECTION_REQUEST: + case hci::OpCode::LINK_KEY_REQUEST_REPLY: + case hci::OpCode::LINK_KEY_REQUEST_NEGATIVE_REPLY: + case hci::OpCode::PIN_CODE_REQUEST_REPLY: + case hci::OpCode::PIN_CODE_REQUEST_NEGATIVE_REPLY: + case hci::OpCode::REJECT_CONNECTION_REQUEST: + case hci::OpCode::REMOTE_NAME_REQUEST: + case hci::OpCode::REMOTE_NAME_REQUEST_CANCEL: + case hci::OpCode::ACCEPT_SYNCHRONOUS_CONNECTION: + case hci::OpCode::REJECT_SYNCHRONOUS_CONNECTION: + case hci::OpCode::IO_CAPABILITY_REQUEST_REPLY: + case hci::OpCode::USER_CONFIRMATION_REQUEST_REPLY: + case hci::OpCode::USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY: + case hci::OpCode::USER_PASSKEY_REQUEST_REPLY: + case hci::OpCode::USER_PASSKEY_REQUEST_NEGATIVE_REPLY: + case hci::OpCode::REMOTE_OOB_DATA_REQUEST_REPLY: + case hci::OpCode::REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY: + case hci::OpCode::IO_CAPABILITY_REQUEST_NEGATIVE_REPLY: + case hci::OpCode::ENHANCED_ACCEPT_SYNCHRONOUS_CONNECTION: + case hci::OpCode::REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY: + case hci::OpCode::SWITCH_ROLE: + case hci::OpCode::READ_STORED_LINK_KEY: + classification = {.activity = Activity::CONNECT, .connection_handle_pos = 0, .address_pos = 3}; + break; + + case hci::OpCode::CENTRAL_LINK_KEY: + case hci::OpCode::READ_DEFAULT_LINK_POLICY_SETTINGS: + case hci::OpCode::WRITE_DEFAULT_LINK_POLICY_SETTINGS: + case hci::OpCode::WRITE_SCAN_ENABLE: + case hci::OpCode::READ_PAGE_SCAN_ACTIVITY: + case hci::OpCode::WRITE_PAGE_SCAN_ACTIVITY: + case hci::OpCode::READ_PAGE_SCAN_TYPE: + case hci::OpCode::WRITE_PAGE_SCAN_TYPE: + case hci::OpCode::READ_SIMPLE_PAIRING_MODE: + case hci::OpCode::WRITE_SIMPLE_PAIRING_MODE: + case hci::OpCode::READ_SCAN_ENABLE: + case hci::OpCode::LE_CREATE_CONNECTION_CANCEL: + case hci::OpCode::LE_READ_CONNECT_LIST_SIZE: + case hci::OpCode::LE_CLEAR_CONNECT_LIST: + case hci::OpCode::SEND_KEYPRESS_NOTIFICATION: + case hci::OpCode::LE_CLEAR_RESOLVING_LIST: + case hci::OpCode::LE_READ_RESOLVING_LIST_SIZE: + case hci::OpCode::LE_SET_HOST_CHANNEL_CLASSIFICATION: + classification = {.activity = Activity::CONNECT, .connection_handle_pos = 0, .address_pos = 0}; + break; + + case hci::OpCode::DISCONNECT: + case hci::OpCode::CHANGE_CONNECTION_PACKET_TYPE: + case hci::OpCode::AUTHENTICATION_REQUESTED: + case hci::OpCode::SET_CONNECTION_ENCRYPTION: + case hci::OpCode::CHANGE_CONNECTION_LINK_KEY: + case hci::OpCode::READ_REMOTE_SUPPORTED_FEATURES: + case hci::OpCode::READ_REMOTE_EXTENDED_FEATURES: + case hci::OpCode::READ_REMOTE_VERSION_INFORMATION: + case hci::OpCode::READ_CLOCK_OFFSET: + case hci::OpCode::READ_LMP_HANDLE: + case hci::OpCode::SETUP_SYNCHRONOUS_CONNECTION: + case hci::OpCode::ENHANCED_SETUP_SYNCHRONOUS_CONNECTION: + case hci::OpCode::HOLD_MODE: + case hci::OpCode::SNIFF_MODE: + case hci::OpCode::EXIT_SNIFF_MODE: + case hci::OpCode::QOS_SETUP: + case hci::OpCode::ROLE_DISCOVERY: + case hci::OpCode::READ_LINK_POLICY_SETTINGS: + case hci::OpCode::WRITE_LINK_POLICY_SETTINGS: + case hci::OpCode::FLOW_SPECIFICATION: + case hci::OpCode::SNIFF_SUBRATING: + case hci::OpCode::FLUSH: + case hci::OpCode::READ_AUTOMATIC_FLUSH_TIMEOUT: + case hci::OpCode::WRITE_AUTOMATIC_FLUSH_TIMEOUT: + case hci::OpCode::READ_LINK_SUPERVISION_TIMEOUT: + case hci::OpCode::WRITE_LINK_SUPERVISION_TIMEOUT: + case hci::OpCode::REFRESH_ENCRYPTION_KEY: + case hci::OpCode::READ_FAILED_CONTACT_COUNTER: + case hci::OpCode::RESET_FAILED_CONTACT_COUNTER: + case hci::OpCode::READ_LINK_QUALITY: + case hci::OpCode::READ_RSSI: + case hci::OpCode::READ_AFH_CHANNEL_MAP: + case hci::OpCode::READ_CLOCK: + case hci::OpCode::READ_ENCRYPTION_KEY_SIZE: + // READ_LOOPBACK_MODE = 0x1801, + // WRITE_LOOPBACK_MODE = 0x1802, + // ENABLE_DEVICE_UNDER_TEST_MODE = 0x1803, + // WRITE_SIMPLE_PAIRING_DEBUG_MODE = 0x1804, + // WRITE_SECURE_CONNECTIONS_TEST_MODE = 0x180a, + case hci::OpCode::ENHANCED_FLUSH: + case hci::OpCode::LE_CONNECTION_UPDATE: + case hci::OpCode::LE_START_ENCRYPTION: + case hci::OpCode::LE_LONG_TERM_KEY_REQUEST_REPLY: + case hci::OpCode::LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY: + case hci::OpCode::LE_READ_PHY: + case hci::OpCode::LE_SET_PHY: + case hci::OpCode::LE_READ_REMOTE_FEATURES: + case hci::OpCode::LE_REMOTE_CONNECTION_PARAMETER_REQUEST_REPLY: + case hci::OpCode::LE_REMOTE_CONNECTION_PARAMETER_REQUEST_NEGATIVE_REPLY: + case hci::OpCode::LE_SET_DATA_LENGTH: + classification = {.activity = Activity::CONNECT, .connection_handle_pos = 3, .address_pos = 0}; + break; + + case hci::OpCode::SET_EVENT_MASK: + case hci::OpCode::RESET: + case hci::OpCode::SET_EVENT_FILTER: + case hci::OpCode::READ_PIN_TYPE: + case hci::OpCode::WRITE_PIN_TYPE: + case hci::OpCode::WRITE_LOCAL_NAME: + case hci::OpCode::READ_LOCAL_NAME: + case hci::OpCode::READ_CONNECTION_ACCEPT_TIMEOUT: + case hci::OpCode::WRITE_CONNECTION_ACCEPT_TIMEOUT: + case hci::OpCode::READ_PAGE_TIMEOUT: + case hci::OpCode::WRITE_PAGE_TIMEOUT: + case hci::OpCode::READ_AUTHENTICATION_ENABLE: + case hci::OpCode::WRITE_AUTHENTICATION_ENABLE: + case hci::OpCode::READ_CLASS_OF_DEVICE: + case hci::OpCode::WRITE_CLASS_OF_DEVICE: + case hci::OpCode::READ_VOICE_SETTING: + case hci::OpCode::WRITE_VOICE_SETTING: + case hci::OpCode::READ_NUM_BROADCAST_RETRANSMITS: + case hci::OpCode::WRITE_NUM_BROADCAST_RETRANSMITS: + case hci::OpCode::READ_HOLD_MODE_ACTIVITY: + case hci::OpCode::WRITE_HOLD_MODE_ACTIVITY: + case hci::OpCode::READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE: + case hci::OpCode::WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE: + case hci::OpCode::SET_CONTROLLER_TO_HOST_FLOW_CONTROL: + case hci::OpCode::HOST_BUFFER_SIZE: + case hci::OpCode::HOST_NUM_COMPLETED_PACKETS: + case hci::OpCode::READ_NUMBER_OF_SUPPORTED_IAC: + case hci::OpCode::READ_CURRENT_IAC_LAP: + case hci::OpCode::WRITE_CURRENT_IAC_LAP: + case hci::OpCode::SET_AFH_HOST_CHANNEL_CLASSIFICATION: + case hci::OpCode::READ_AFH_CHANNEL_ASSESSMENT_MODE: + case hci::OpCode::WRITE_AFH_CHANNEL_ASSESSMENT_MODE: + case hci::OpCode::READ_LE_HOST_SUPPORT: + case hci::OpCode::WRITE_LE_HOST_SUPPORT: + case hci::OpCode::READ_SECURE_CONNECTIONS_HOST_SUPPORT: + case hci::OpCode::WRITE_SECURE_CONNECTIONS_HOST_SUPPORT: + case hci::OpCode::READ_LOCAL_OOB_EXTENDED_DATA: + case hci::OpCode::SET_ECOSYSTEM_BASE_INTERVAL: + case hci::OpCode::CONFIGURE_DATA_PATH: + case hci::OpCode::READ_LOCAL_VERSION_INFORMATION: + case hci::OpCode::READ_LOCAL_SUPPORTED_COMMANDS: + case hci::OpCode::READ_LOCAL_SUPPORTED_FEATURES: + case hci::OpCode::READ_LOCAL_EXTENDED_FEATURES: + case hci::OpCode::READ_BUFFER_SIZE: + case hci::OpCode::READ_BD_ADDR: + case hci::OpCode::READ_DATA_BLOCK_SIZE: + case hci::OpCode::READ_LOCAL_SUPPORTED_CODECS_V1: + case hci::OpCode::READ_LOCAL_SUPPORTED_CODECS_V2: + case hci::OpCode::READ_LOCAL_SUPPORTED_CODEC_CAPABILITIES: + case hci::OpCode::READ_LOCAL_SUPPORTED_CONTROLLER_DELAY: + case hci::OpCode::READ_LOCAL_OOB_DATA: + case hci::OpCode::LE_GENERATE_DHKEY_COMMAND: + case hci::OpCode::LE_MODIFY_SLEEP_CLOCK_ACCURACY: + case hci::OpCode::LE_READ_BUFFER_SIZE_V2: + case hci::OpCode::LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH: + case hci::OpCode::LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH: + case hci::OpCode::LE_READ_LOCAL_P_256_PUBLIC_KEY_COMMAND: + case hci::OpCode::LE_GENERATE_DHKEY_COMMAND_V1: + case hci::OpCode::LE_SET_EVENT_MASK: + case hci::OpCode::LE_READ_BUFFER_SIZE_V1: + case hci::OpCode::LE_READ_LOCAL_SUPPORTED_FEATURES: + case hci::OpCode::LE_SET_RANDOM_ADDRESS: + case hci::OpCode::LE_READ_TRANSMIT_POWER: + case hci::OpCode::LE_READ_RF_PATH_COMPENSATION_POWER: + case hci::OpCode::LE_WRITE_RF_PATH_COMPENSATION_POWER: + case hci::OpCode::LE_SET_DEFAULT_PHY: + case hci::OpCode::LE_ENCRYPT: + case hci::OpCode::LE_RAND: + case hci::OpCode::LE_SET_ADDRESS_RESOLUTION_ENABLE: + case hci::OpCode::LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT: + case hci::OpCode::LE_READ_MAXIMUM_DATA_LENGTH: + case hci::OpCode::LE_READ_SUPPORTED_STATES: + classification = {.activity = Activity::CONTROL, .connection_handle_pos = 0, .address_pos = 0}; + break; + + case hci::OpCode::DELETE_STORED_LINK_KEY: + classification = {.activity = Activity::CONTROL, .connection_handle_pos = 0, .address_pos = 3}; + break; + case hci::OpCode::READ_TRANSMIT_POWER_LEVEL: + classification = {.activity = Activity::CONTROL, .connection_handle_pos = 3, .address_pos = 0}; + break; + + case hci::OpCode::READ_INQUIRY_SCAN_ACTIVITY: + case hci::OpCode::WRITE_INQUIRY_SCAN_ACTIVITY: + case hci::OpCode::READ_INQUIRY_SCAN_TYPE: + case hci::OpCode::WRITE_INQUIRY_SCAN_TYPE: + case hci::OpCode::READ_INQUIRY_MODE: + case hci::OpCode::WRITE_INQUIRY_MODE: + case hci::OpCode::READ_EXTENDED_INQUIRY_RESPONSE: + case hci::OpCode::WRITE_EXTENDED_INQUIRY_RESPONSE: + case hci::OpCode::LE_SET_CIG_PARAMETERS: + case hci::OpCode::LE_CREATE_CIS: + case hci::OpCode::LE_REMOVE_CIG: + case hci::OpCode::LE_ACCEPT_CIS_REQUEST: + case hci::OpCode::LE_REJECT_CIS_REQUEST: + case hci::OpCode::LE_CREATE_BIG: + case hci::OpCode::LE_TERMINATE_BIG: + case hci::OpCode::LE_BIG_CREATE_SYNC: + case hci::OpCode::LE_BIG_TERMINATE_SYNC: + case hci::OpCode::LE_REQUEST_PEER_SCA: + case hci::OpCode::LE_SETUP_ISO_DATA_PATH: + case hci::OpCode::LE_REMOVE_ISO_DATA_PATH: + case hci::OpCode::LE_SET_HOST_FEATURE: + case hci::OpCode::LE_READ_ISO_LINK_QUALITY: + case hci::OpCode::LE_ENHANCED_READ_TRANSMIT_POWER_LEVEL: + case hci::OpCode::LE_READ_REMOTE_TRANSMIT_POWER_LEVEL: + case hci::OpCode::LE_SET_PATH_LOSS_REPORTING_PARAMETERS: + case hci::OpCode::LE_SET_PATH_LOSS_REPORTING_ENABLE: + case hci::OpCode::LE_SET_TRANSMIT_POWER_REPORTING_ENABLE: + case hci::OpCode::LE_GET_VENDOR_CAPABILITIES: + case hci::OpCode::LE_MULTI_ADVT: + case hci::OpCode::LE_BATCH_SCAN: + case hci::OpCode::LE_ADV_FILTER: + case hci::OpCode::LE_ENERGY_INFO: + case hci::OpCode::LE_EXTENDED_SCAN_PARAMS: + case hci::OpCode::CONTROLLER_DEBUG_INFO: + case hci::OpCode::CONTROLLER_A2DP_OPCODE: + case hci::OpCode::CONTROLLER_BQR: + case hci::OpCode::READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL: + case hci::OpCode::WRITE_INQUIRY_TRANSMIT_POWER_LEVEL: + case hci::OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS: + case hci::OpCode::LE_SET_EXTENDED_SCAN_ENABLE: + case hci::OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL: + case hci::OpCode::LE_SET_SCAN_PARAMETERS: + case hci::OpCode::LE_SET_SCAN_ENABLE: + case hci::OpCode::LE_SET_DEFAULT_PERIODIC_ADVERTISING_SYNC_TRANSFER_PARAMETERS: + case hci::OpCode::LE_SET_PERIODIC_ADVERTISING_RECEIVE_ENABLE: + case hci::OpCode::LE_CLEAR_PERIODIC_ADVERTISING_LIST: + case hci::OpCode::LE_READ_PERIODIC_ADVERTISING_LIST_SIZE: + case hci::OpCode::LE_PERIODIC_ADVERTISING_TERMINATE_SYNC: + classification = {.activity = Activity::SCAN, .connection_handle_pos = 0, .address_pos = 0}; + break; + + case hci::OpCode::LE_READ_ADVERTISING_PHYSICAL_CHANNEL_TX_POWER: + case hci::OpCode::LE_SET_ADVERTISING_DATA: + case hci::OpCode::LE_SET_SCAN_RESPONSE_DATA: + case hci::OpCode::LE_SET_ADVERTISING_ENABLE: + case hci::OpCode::LE_SET_EXTENDED_ADVERTISING_DATA: + case hci::OpCode::LE_SET_EXTENDED_ADVERTISING_SCAN_RESPONSE: + case hci::OpCode::LE_SET_EXTENDED_ADVERTISING_ENABLE: + case hci::OpCode::LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH: + case hci::OpCode::LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS: + case hci::OpCode::LE_REMOVE_ADVERTISING_SET: + case hci::OpCode::LE_CLEAR_ADVERTISING_SETS: + case hci::OpCode::LE_SET_PERIODIC_ADVERTISING_PARAM: + case hci::OpCode::LE_SET_PERIODIC_ADVERTISING_DATA: + case hci::OpCode::LE_SET_PERIODIC_ADVERTISING_ENABLE: + case hci::OpCode::LE_SET_EXTENDED_ADVERTISING_RANDOM_ADDRESS: + classification = {.activity = Activity::ADVERTISE, .connection_handle_pos = 0, .address_pos = 0}; + break; + + case hci::OpCode::LE_SET_ADVERTISING_PARAMETERS: + classification = {.activity = Activity::SCAN, .connection_handle_pos = 0, .address_pos = 10}; + break; + case hci::OpCode::LE_CREATE_CONNECTION: + classification = {.activity = Activity::CONNECT, .connection_handle_pos = 0, .address_pos = 9}; + break; + case hci::OpCode::LE_ADD_DEVICE_TO_CONNECT_LIST: + case hci::OpCode::LE_READ_CHANNEL_MAP: + classification = {.activity = Activity::CONNECT, .connection_handle_pos = 4, .address_pos = 0}; + break; + + case hci::OpCode::LE_REMOVE_DEVICE_FROM_CONNECT_LIST: + case hci::OpCode::LE_ADD_DEVICE_TO_RESOLVING_LIST: + case hci::OpCode::LE_REMOVE_DEVICE_FROM_RESOLVING_LIST: + case hci::OpCode::LE_READ_PEER_RESOLVABLE_ADDRESS: + case hci::OpCode::LE_READ_LOCAL_RESOLVABLE_ADDRESS: + case hci::OpCode::LE_SET_PRIVACY_MODE: + classification = {.activity = Activity::CONNECT, .connection_handle_pos = 0, .address_pos = 4}; + break; + + case hci::OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS: + classification = {.activity = Activity::ADVERTISE, .connection_handle_pos = 0, .address_pos = 15}; + break; + case hci::OpCode::LE_EXTENDED_CREATE_CONNECTION: + classification = {.activity = Activity::CONNECT, .connection_handle_pos = 0, .address_pos = 6}; + break; + case hci::OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC: + classification = {.activity = Activity::SCAN, .connection_handle_pos = 0, .address_pos = 6}; + break; + case hci::OpCode::LE_ADD_DEVICE_TO_PERIODIC_ADVERTISING_LIST: + case hci::OpCode::LE_REMOVE_DEVICE_FROM_PERIODIC_ADVERTISING_LIST: + classification = {.activity = Activity::SCAN, .connection_handle_pos = 0, .address_pos = 4}; + break; + case hci::OpCode::LE_PERIODIC_ADVERTISING_SYNC_TRANSFER: + case hci::OpCode::LE_PERIODIC_ADVERTISING_SET_INFO_TRANSFER: + case hci::OpCode::LE_SET_PERIODIC_ADVERTISING_SYNC_TRANSFER_PARAMETERS: + classification = {.activity = Activity::SCAN, .connection_handle_pos = 3, .address_pos = 0}; + break; + + default: + classification = {.activity = Activity::UNKNOWN, .connection_handle_pos = 0, .address_pos = 0}; + break; + } + return classification; +} + +} // namespace activity_attribution +} // namespace bluetooth diff --git a/gd/btaa/linux_generic/hci_processor.cc b/gd/btaa/linux_generic/hci_processor.cc new file mode 100644 index 0000000000..077d269f45 --- /dev/null +++ b/gd/btaa/linux_generic/hci_processor.cc @@ -0,0 +1,93 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "btaa/hci_processor.h" + +#include "btaa/cmd_evt_classification.h" +#include "os/log.h" + +namespace bluetooth { +namespace activity_attribution { + +class DeviceParser { + public: + void match_handle_with_address(uint16_t connection_handle, hci::Address& address) { + if (connection_handle && !address.IsEmpty()) { + connection_lookup_table[connection_handle] = address; + } else if (connection_handle) { + if (connection_lookup_table.find(connection_handle) != connection_lookup_table.end()) { + address = connection_lookup_table[connection_handle]; + } + } + } + + private: + std::map connection_lookup_table; +}; + +static DeviceParser device_parser; +static std::pair pending_command; + +static void process_command( + std::vector& btaa_hci_packets, + packet::PacketView& packet_view, + uint16_t byte_count) { + hci::CommandView command = hci::CommandView::Create(packet_view); + if (!command.IsValid()) { + return; + } + + uint16_t connection_handle_value = 0; + hci::Address address_value; + auto opcode = command.GetOpCode(); + auto cmd_info = lookup_cmd(opcode); + + if (cmd_info.connection_handle_pos) { + auto connection_handle_it = command.begin() + cmd_info.connection_handle_pos; + connection_handle_value = connection_handle_it.extract(); + } + if (cmd_info.address_pos) { + auto address_value_it = command.begin() + cmd_info.address_pos; + address_value = address_value_it.extract(); + } + device_parser.match_handle_with_address(connection_handle_value, address_value); + pending_command.second = BtaaHciPacket(cmd_info.activity, address_value, byte_count); + + pending_command.first = opcode; +} + +std::vector HciProcessor::OnHciPacket( + hal::HciPacket packet, hal::SnoopLogger::PacketType type, uint16_t length) { + std::vector btaa_hci_packets; + auto packet_view = packet::PacketView(std::make_shared>(packet)); + switch (type) { + case hal::SnoopLogger::PacketType::CMD: + process_command(btaa_hci_packets, packet_view, length); + break; + case hal::SnoopLogger::PacketType::EVT: + break; + case hal::SnoopLogger::PacketType::ACL: + break; + case hal::SnoopLogger::PacketType::SCO: + break; + case hal::SnoopLogger::PacketType::ISO: + break; + } + return btaa_hci_packets; +} + +} // namespace activity_attribution +} // namespace bluetooth From 1962f0be5cf4a5b5994b3adfb88600238da387dc Mon Sep 17 00:00:00 2001 From: Michael Sun Date: Wed, 6 Jan 2021 00:13:11 +0000 Subject: [PATCH 4/9] btaa: HCI classic event process Introduce BTAA HCI event processing. This change only handles simple (event that contains only one device information and do not require additional processing )classic events. Command status and command complete events will be associated with previous parsed HCI command. The lookup table is a skelton implementation that does not contain 100% correct information. Tag: #feature Bug: 177230507 Test: verified locally BTAA can partially process HCI events. BYPASS_LONG_LINES_REASON: consist with gd format Change-Id: Idd26318200cfd1f94596dd69083452dba5dff478 --- gd/btaa/cmd_evt_classification.h | 1 + .../linux_generic/cmd_evt_classification.cc | 70 ++++++++++++++++++ gd/btaa/linux_generic/hci_processor.cc | 71 ++++++++++++++++++- 3 files changed, 139 insertions(+), 3 deletions(-) diff --git a/gd/btaa/cmd_evt_classification.h b/gd/btaa/cmd_evt_classification.h index f7e21da9c0..5a2d2cdbea 100644 --- a/gd/btaa/cmd_evt_classification.h +++ b/gd/btaa/cmd_evt_classification.h @@ -29,6 +29,7 @@ struct CmdEvtActivityClassification { }; CmdEvtActivityClassification lookup_cmd(hci::OpCode opcode); +CmdEvtActivityClassification lookup_event(hci::EventCode event_code); } // namespace activity_attribution } // namespace bluetooth diff --git a/gd/btaa/linux_generic/cmd_evt_classification.cc b/gd/btaa/linux_generic/cmd_evt_classification.cc index 57421de4f7..81274da632 100644 --- a/gd/btaa/linux_generic/cmd_evt_classification.cc +++ b/gd/btaa/linux_generic/cmd_evt_classification.cc @@ -327,5 +327,75 @@ CmdEvtActivityClassification lookup_cmd(hci::OpCode opcode) { return classification; } +CmdEvtActivityClassification lookup_event(hci::EventCode event_code) { + CmdEvtActivityClassification classification = {}; + switch (event_code) { + case hci::EventCode::INQUIRY_COMPLETE: + classification = {.activity = Activity::SCAN, .connection_handle_pos = 0, .address_pos = 0}; + break; + case hci::EventCode::CONNECTION_COMPLETE: + case hci::EventCode::SYNCHRONOUS_CONNECTION_COMPLETE: + classification = {.activity = Activity::CONNECT, .connection_handle_pos = 3, .address_pos = 5}; + break; + + case hci::EventCode::CONNECTION_REQUEST: + case hci::EventCode::PIN_CODE_REQUEST: + case hci::EventCode::LINK_KEY_REQUEST: + case hci::EventCode::LINK_KEY_NOTIFICATION: + case hci::EventCode::USER_PASSKEY_NOTIFICATION: + case hci::EventCode::KEYPRESS_NOTIFICATION: + case hci::EventCode::REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION: + case hci::EventCode::IO_CAPABILITY_REQUEST: + case hci::EventCode::IO_CAPABILITY_RESPONSE: + case hci::EventCode::USER_CONFIRMATION_REQUEST: + case hci::EventCode::USER_PASSKEY_REQUEST: + case hci::EventCode::REMOTE_OOB_DATA_REQUEST: + classification = {.activity = Activity::CONNECT, .connection_handle_pos = 0, .address_pos = 2}; + break; + + case hci::EventCode::DISCONNECTION_COMPLETE: + case hci::EventCode::AUTHENTICATION_COMPLETE: + case hci::EventCode::ENCRYPTION_CHANGE: + case hci::EventCode::ENCRYPTION_KEY_REFRESH_COMPLETE: + case hci::EventCode::LINK_SUPERVISION_TIMEOUT_CHANGED: + case hci::EventCode::CHANGE_CONNECTION_LINK_KEY_COMPLETE: + case hci::EventCode::CENTRAL_LINK_KEY_COMPLETE: + case hci::EventCode::READ_REMOTE_SUPPORTED_FEATURES_COMPLETE: + case hci::EventCode::READ_REMOTE_VERSION_INFORMATION_COMPLETE: + case hci::EventCode::QOS_SETUP_COMPLETE: + case hci::EventCode::MODE_CHANGE: + case hci::EventCode::READ_CLOCK_OFFSET_COMPLETE: + case hci::EventCode::CONNECTION_PACKET_TYPE_CHANGED: + case hci::EventCode::FLOW_SPECIFICATION_COMPLETE: + case hci::EventCode::READ_REMOTE_EXTENDED_FEATURES_COMPLETE: + case hci::EventCode::SYNCHRONOUS_CONNECTION_CHANGED: + case hci::EventCode::SNIFF_SUBRATING: + classification = {.activity = Activity::CONNECT, .connection_handle_pos = 3, .address_pos = 0}; + break; + + case hci::EventCode::REMOTE_NAME_REQUEST_COMPLETE: + case hci::EventCode::EXTENDED_INQUIRY_RESULT: + classification = {.activity = Activity::SCAN, .connection_handle_pos = 0, .address_pos = 3}; + break; + case hci::EventCode::FLUSH_OCCURRED: + case hci::EventCode::MAX_SLOTS_CHANGE: + case hci::EventCode::QOS_VIOLATION: + case hci::EventCode::ENHANCED_FLUSH_COMPLETE: + classification = {.activity = Activity::CONNECT, .connection_handle_pos = 2, .address_pos = 0}; + break; + case hci::EventCode::ROLE_CHANGE: + case hci::EventCode::SIMPLE_PAIRING_COMPLETE: + classification = {.activity = Activity::CONNECT, .connection_handle_pos = 0, .address_pos = 3}; + break; + case hci::EventCode::PAGE_SCAN_REPETITION_MODE_CHANGE: + classification = {.activity = Activity::SCAN, .connection_handle_pos = 0, .address_pos = 2}; + break; + + default: + classification = {.activity = Activity::UNKNOWN, .connection_handle_pos = 0, .address_pos = 0}; + } + return classification; +} + } // namespace activity_attribution } // namespace bluetooth diff --git a/gd/btaa/linux_generic/hci_processor.cc b/gd/btaa/linux_generic/hci_processor.cc index 077d269f45..6967fe9c0a 100644 --- a/gd/btaa/linux_generic/hci_processor.cc +++ b/gd/btaa/linux_generic/hci_processor.cc @@ -38,8 +38,13 @@ class DeviceParser { std::map connection_lookup_table; }; +struct PendingCommand { + hci::OpCode opcode; + BtaaHciPacket btaa_hci_packet; +}; + static DeviceParser device_parser; -static std::pair pending_command; +static PendingCommand pending_command; static void process_command( std::vector& btaa_hci_packets, @@ -64,9 +69,68 @@ static void process_command( address_value = address_value_it.extract(); } device_parser.match_handle_with_address(connection_handle_value, address_value); - pending_command.second = BtaaHciPacket(cmd_info.activity, address_value, byte_count); + pending_command.btaa_hci_packet = BtaaHciPacket(cmd_info.activity, address_value, byte_count); + + pending_command.opcode = opcode; +} + +static void process_event( + std::vector& btaa_hci_packets, + packet::PacketView& packet_view, + uint16_t byte_count) { + hci::EventView event = hci::EventView::Create(packet_view); + if (!event.IsValid()) { + return; + } - pending_command.first = opcode; + uint16_t connection_handle_value = 0; + hci::Address address_value; + auto event_code = event.GetEventCode(); + auto event_info = lookup_event(event_code); + + if (event_info.activity != Activity::UNKNOWN) { + // lookup_event returns all simple classic event which does not require additional processing. + if (event_info.connection_handle_pos) { + auto connection_handle_it = event.begin() + event_info.connection_handle_pos; + connection_handle_value = connection_handle_it.extract(); + } + if (event_info.address_pos) { + auto address_value_it = event.begin() + event_info.address_pos; + address_value = address_value_it.extract(); + } + device_parser.match_handle_with_address(connection_handle_value, address_value); + btaa_hci_packets.push_back(BtaaHciPacket(event_info.activity, address_value, byte_count)); + } else { + // The event requires additional processing. + switch (event_code) { + case hci::EventCode::COMMAND_COMPLETE: { + auto packet_view = hci::CommandCompleteView::Create(event); + if (packet_view.IsValid() && packet_view.GetCommandOpCode() == pending_command.opcode) { + pending_command.btaa_hci_packet.byte_count += byte_count; + btaa_hci_packets.push_back(std::move(pending_command.btaa_hci_packet)); + } else { + btaa_hci_packets.push_back(BtaaHciPacket(Activity::UNKNOWN, address_value, byte_count)); + } + } break; + case hci::EventCode::COMMAND_STATUS: { + auto packet_view = hci::CommandStatusView::Create(event); + if (packet_view.IsValid() && packet_view.GetCommandOpCode() == pending_command.opcode) { + pending_command.btaa_hci_packet.byte_count += byte_count; + btaa_hci_packets.push_back(std::move(pending_command.btaa_hci_packet)); + } else { + btaa_hci_packets.push_back(BtaaHciPacket(Activity::UNKNOWN, address_value, byte_count)); + } + break; + } + case hci::EventCode::LE_META_EVENT: + break; + case hci::EventCode::VENDOR_SPECIFIC: + btaa_hci_packets.push_back(BtaaHciPacket(Activity::VENDOR, address_value, byte_count)); + break; + default: + break; + } + } } std::vector HciProcessor::OnHciPacket( @@ -78,6 +142,7 @@ std::vector HciProcessor::OnHciPacket( process_command(btaa_hci_packets, packet_view, length); break; case hal::SnoopLogger::PacketType::EVT: + process_event(btaa_hci_packets, packet_view, length); break; case hal::SnoopLogger::PacketType::ACL: break; From 85237eb5ce733eb15ba4ebcdae833b821c680121 Mon Sep 17 00:00:00 2001 From: Michael Sun Date: Wed, 6 Jan 2021 00:14:36 +0000 Subject: [PATCH 5/9] btaa: HCI LE and special event process Implementation the HCI process for LE and special (events that contains more than one device information) events. Tag: #feature Bug: 177230507 Test: verified locally BTAA can process LE and special events. BYPASS_LONG_LINES_REASON: consist with gd format Change-Id: If30069673bd6164b22af926ca17ea9830f891a8a --- gd/btaa/cmd_evt_classification.h | 1 + .../linux_generic/cmd_evt_classification.cc | 64 +++++++++++++++ gd/btaa/linux_generic/hci_processor.cc | 82 +++++++++++++++++++ 3 files changed, 147 insertions(+) diff --git a/gd/btaa/cmd_evt_classification.h b/gd/btaa/cmd_evt_classification.h index 5a2d2cdbea..1aae6c2244 100644 --- a/gd/btaa/cmd_evt_classification.h +++ b/gd/btaa/cmd_evt_classification.h @@ -30,6 +30,7 @@ struct CmdEvtActivityClassification { CmdEvtActivityClassification lookup_cmd(hci::OpCode opcode); CmdEvtActivityClassification lookup_event(hci::EventCode event_code); +CmdEvtActivityClassification lookup_le_event(hci::SubeventCode subevent_code); } // namespace activity_attribution } // namespace bluetooth diff --git a/gd/btaa/linux_generic/cmd_evt_classification.cc b/gd/btaa/linux_generic/cmd_evt_classification.cc index 81274da632..a8b6151e61 100644 --- a/gd/btaa/linux_generic/cmd_evt_classification.cc +++ b/gd/btaa/linux_generic/cmd_evt_classification.cc @@ -397,5 +397,69 @@ CmdEvtActivityClassification lookup_event(hci::EventCode event_code) { return classification; } +CmdEvtActivityClassification lookup_le_event(hci::SubeventCode subevent_code) { + CmdEvtActivityClassification classification = {}; + switch (subevent_code) { + case hci::SubeventCode::CONNECTION_COMPLETE: + case hci::SubeventCode::ENHANCED_CONNECTION_COMPLETE: + classification = {.activity = Activity::CONNECT, .connection_handle_pos = 4, .address_pos = 7}; + break; + + case hci::SubeventCode::CONNECTION_UPDATE_COMPLETE: + case hci::SubeventCode::READ_REMOTE_FEATURES_COMPLETE: + case hci::SubeventCode::PHY_UPDATE_COMPLETE: + case hci::SubeventCode::CTE_REQUEST_FAILED: + case hci::SubeventCode::TRANSMIT_POWER_REPORTING: + classification = {.activity = Activity::CONNECT, .connection_handle_pos = 4, .address_pos = 0}; + break; + + case hci::SubeventCode::LONG_TERM_KEY_REQUEST: + case hci::SubeventCode::REMOTE_CONNECTION_PARAMETER_REQUEST: + case hci::SubeventCode::DATA_LENGTH_CHANGE: + case hci::SubeventCode::CHANNEL_SELECTION_ALGORITHM: + case hci::SubeventCode::CONNECTION_IQ_REPORT: + case hci::SubeventCode::PATH_LOSS_THRESHOLD: + classification = {.activity = Activity::CONNECT, .connection_handle_pos = 3, .address_pos = 0}; + break; + + case hci::SubeventCode::READ_LOCAL_P256_PUBLIC_KEY_COMPLETE: + case hci::SubeventCode::GENERATE_DHKEY_COMPLETE: + classification = {.activity = Activity::CONTROL, .connection_handle_pos = 0, .address_pos = 0}; + break; + + case hci::SubeventCode::PERIODIC_ADVERTISING_SYNC_ESTABLISHED: + case hci::SubeventCode::PERIODIC_ADVERTISING_REPORT: + case hci::SubeventCode::PERIODIC_ADVERTISING_SYNC_LOST: + case hci::SubeventCode::ADVERTISING_SET_TERMINATED: + classification = {.activity = Activity::ADVERTISE, .connection_handle_pos = 0, .address_pos = 0}; + break; + + case hci::SubeventCode::SCAN_TIMEOUT: + case hci::SubeventCode::BIG_INFO_ADVERTISING_REPORT: + case hci::SubeventCode::CONNECTIONLESS_IQ_REPORT: + case hci::SubeventCode::CREATE_BIG_COMPLETE: + case hci::SubeventCode::TERMINATE_BIG_COMPLETE: + case hci::SubeventCode::BIG_SYNC_ESTABLISHED: + case hci::SubeventCode::BIG_SYNC_LOST: + case hci::SubeventCode::REQUEST_PEER_SCA_COMPLETE: + classification = {.activity = Activity::SCAN, .connection_handle_pos = 0, .address_pos = 0}; + break; + + case hci::SubeventCode::SCAN_REQUEST_RECEIVED: + classification = {.activity = Activity::ADVERTISE, .connection_handle_pos = 0, .address_pos = 5}; + break; + + case hci::SubeventCode::PERIODIC_ADVERTISING_SYNC_TRANSFER_RECEIVED: + case hci::SubeventCode::CIS_ESTABLISHED: + case hci::SubeventCode::CIS_REQUEST: + classification = {.activity = Activity::SCAN, .connection_handle_pos = 4, .address_pos = 0}; + break; + + default: + classification = {.activity = Activity::UNKNOWN, .connection_handle_pos = 0, .address_pos = 0}; + } + return classification; +} + } // namespace activity_attribution } // namespace bluetooth diff --git a/gd/btaa/linux_generic/hci_processor.cc b/gd/btaa/linux_generic/hci_processor.cc index 6967fe9c0a..b97667df83 100644 --- a/gd/btaa/linux_generic/hci_processor.cc +++ b/gd/btaa/linux_generic/hci_processor.cc @@ -46,6 +46,86 @@ struct PendingCommand { static DeviceParser device_parser; static PendingCommand pending_command; +static void process_le_event(std::vector& btaa_hci_packets, int16_t byte_count, hci::EventView& event) { + uint16_t connection_handle_value = 0; + hci::Address address_value; + + auto le_packet_view = hci::LeMetaEventView::Create(event); + if (!le_packet_view.IsValid()) { + return; + } + + auto subevent_code = le_packet_view.GetSubeventCode(); + auto le_event_info = lookup_le_event(subevent_code); + + if (le_event_info.activity != Activity::UNKNOWN) { + // lookup_le_event returns all simple classic event which does not require additional processing. + if (le_event_info.connection_handle_pos) { + auto connection_handle_it = event.begin() + le_event_info.connection_handle_pos; + connection_handle_value = connection_handle_it.extract(); + } + if (le_event_info.address_pos) { + auto address_value_it = event.begin() + le_event_info.address_pos; + address_value = address_value_it.extract(); + } + device_parser.match_handle_with_address(connection_handle_value, address_value); + btaa_hci_packets.push_back(BtaaHciPacket(le_event_info.activity, address_value, byte_count)); + } +} + +static void process_special_event( + std::vector& btaa_hci_packets, + hci::EventCode event_code, + uint16_t byte_count, + hci::EventView& event) { + uint16_t avg_byte_count; + hci::Address address_value; + + switch (event_code) { + case hci::EventCode::INQUIRY_RESULT: + case hci::EventCode::INQUIRY_RESULT_WITH_RSSI: { + auto packet_view = hci::InquiryResultView::Create(event); + if (!packet_view.IsValid()) { + return; + } + auto inquiry_results = packet_view.GetInquiryResults(); + avg_byte_count = byte_count / inquiry_results.size(); + for (auto& inquiry_result : inquiry_results) { + btaa_hci_packets.push_back(BtaaHciPacket(Activity::SCAN, inquiry_result.bd_addr_, avg_byte_count)); + } + } break; + + case hci::EventCode::NUMBER_OF_COMPLETED_PACKETS: { + auto packet_view = hci::NumberOfCompletedPacketsView::Create(event); + if (!packet_view.IsValid()) { + return; + } + auto completed_packets = packet_view.GetCompletedPackets(); + avg_byte_count = byte_count / completed_packets.size(); + for (auto& completed_packet : completed_packets) { + device_parser.match_handle_with_address(completed_packet.connection_handle_, address_value); + btaa_hci_packets.push_back(BtaaHciPacket(Activity::CONNECT, address_value, avg_byte_count)); + } + } break; + + case hci::EventCode::RETURN_LINK_KEYS: { + auto packet_view = hci::ReturnLinkKeysView::Create(event); + if (!packet_view.IsValid()) { + return; + } + auto keys_and_addresses = packet_view.GetKeys(); + avg_byte_count = byte_count / keys_and_addresses.size(); + for (auto& key_and_address : keys_and_addresses) { + btaa_hci_packets.push_back(BtaaHciPacket(Activity::CONNECT, key_and_address.address_, avg_byte_count)); + } + } break; + + default: { + btaa_hci_packets.push_back(BtaaHciPacket(Activity::UNKNOWN, address_value, byte_count)); + } break; + } +} + static void process_command( std::vector& btaa_hci_packets, packet::PacketView& packet_view, @@ -123,11 +203,13 @@ static void process_event( break; } case hci::EventCode::LE_META_EVENT: + process_le_event(btaa_hci_packets, byte_count, event); break; case hci::EventCode::VENDOR_SPECIFIC: btaa_hci_packets.push_back(BtaaHciPacket(Activity::VENDOR, address_value, byte_count)); break; default: + process_special_event(btaa_hci_packets, event_code, byte_count, event); break; } } From 613fa2d81b358d3ef008ab45b3dc07d8ae64f71a Mon Sep 17 00:00:00 2001 From: Michael Sun Date: Wed, 6 Jan 2021 00:15:02 +0000 Subject: [PATCH 6/9] btaa: attribute wakeup and wakelock duration over processed HCI buckets Attach recorded BT wakeup to the first post-wakeup parsed HCI packet. Distribute wakelock duration over bucketed HCI info based on transmitted byte counts. Tag: #feature Bug: 177232907 BUG: 177228387 Test: verified locally BTAA aggregator updated with BT activities BYPASS_LONG_LINES_REASON: consist with gd format Change-Id: Idf93afcf13af9e76b4bc6f6ef30cf8424d8b4982 --- gd/btaa/android/activity_attribution.cc | 6 ++- gd/btaa/attribution_processor.h | 23 ++++++++++ .../linux_generic/attribution_processor.cc | 45 ++++++++++++++++++- 3 files changed, 72 insertions(+), 2 deletions(-) diff --git a/gd/btaa/android/activity_attribution.cc b/gd/btaa/android/activity_attribution.cc index f673215a4f..2c19e52028 100644 --- a/gd/btaa/android/activity_attribution.cc +++ b/gd/btaa/android/activity_attribution.cc @@ -24,6 +24,7 @@ #include #include "btaa/attribution_processor.h" +#include "btaa/hci_processor.h" #include "btaa/wakelock_processor.h" #include "module.h" #include "os/log.h" @@ -100,7 +101,9 @@ struct ActivityAttribution::impl { } } - void on_hci_packet(hal::HciPacket packet, hal::SnoopLogger::PacketType type, uint16_t length) {} + void on_hci_packet(hal::HciPacket packet, hal::SnoopLogger::PacketType type, uint16_t length) { + attribution_processor_.OnBtaaPackets(std::move(hci_processor_.OnHciPacket(std::move(packet), type, length))); + } void on_wakelock_acquired() { wakelock_processor_.OnWakelockAcquired(); @@ -125,6 +128,7 @@ struct ActivityAttribution::impl { ActivityAttributionCallback* callback_; AttributionProcessor attribution_processor_; + HciProcessor hci_processor_; WakelockProcessor wakelock_processor_; }; diff --git a/gd/btaa/attribution_processor.h b/gd/btaa/attribution_processor.h index 98bfa6e717..2a01013fbf 100644 --- a/gd/btaa/attribution_processor.h +++ b/gd/btaa/attribution_processor.h @@ -17,17 +17,40 @@ #pragma once #include +#include + +#include "hci_processor.h" namespace bluetooth { namespace activity_attribution { +struct AddressActivityKey { + hci::Address address; + Activity activity; + + bool operator==(const AddressActivityKey& other) const { + return (address == other.address && activity == other.activity); + } +}; + +struct AddressActivityKeyHasher { + std::size_t operator()(const AddressActivityKey& key) const { + return ( + (std::hash()(key.address.ToString()) ^ + (std::hash()(static_cast(key.activity))))); + } +}; + class AttributionProcessor { public: + void OnBtaaPackets(std::vector btaa_packets); void OnWakelockReleased(uint32_t duration_ms); void OnWakeup(); private: bool wakeup_ = false; + std::unordered_map btaa_aggregator_; + std::unordered_map wakelock_duration_aggregator_; }; } // namespace activity_attribution diff --git a/gd/btaa/linux_generic/attribution_processor.cc b/gd/btaa/linux_generic/attribution_processor.cc index 5130825953..56c1c32d1d 100644 --- a/gd/btaa/linux_generic/attribution_processor.cc +++ b/gd/btaa/linux_generic/attribution_processor.cc @@ -21,7 +21,50 @@ namespace bluetooth { namespace activity_attribution { -void AttributionProcessor::OnWakelockReleased(uint32_t duration_ms) {} +void AttributionProcessor::OnBtaaPackets(std::vector btaa_packets) { + AddressActivityKey key; + + for (auto& btaa_packet : btaa_packets) { + key.address = btaa_packet.address; + key.activity = btaa_packet.activity; + + if (wakelock_duration_aggregator_.find(key) == wakelock_duration_aggregator_.end()) { + wakelock_duration_aggregator_[key] = {}; + } + wakelock_duration_aggregator_[key].byte_count += btaa_packet.byte_count; + + if (wakeup_) { + wakelock_duration_aggregator_[key].wakeup_count += 1; + } + } + wakeup_ = false; +} + +void AttributionProcessor::OnWakelockReleased(uint32_t duration_ms) { + uint32_t total_byte_count = 0; + uint32_t ms_per_byte = 0; + + for (auto& it : wakelock_duration_aggregator_) { + total_byte_count += it.second.byte_count; + } + + if (total_byte_count == 0) { + return; + } + + ms_per_byte = duration_ms / total_byte_count; + for (auto& it : wakelock_duration_aggregator_) { + it.second.wakelock_duration = ms_per_byte * it.second.byte_count; + if (btaa_aggregator_.find(it.first) == btaa_aggregator_.end()) { + btaa_aggregator_[it.first] = {}; + } + + btaa_aggregator_[it.first].wakeup_count += it.second.wakeup_count; + btaa_aggregator_[it.first].byte_count += it.second.byte_count; + btaa_aggregator_[it.first].wakelock_duration += it.second.wakelock_duration; + } + wakelock_duration_aggregator_.clear(); +} void AttributionProcessor::OnWakeup() { if (wakeup_) { From 13225eb8131c0311302d17ca31745c843e3659e6 Mon Sep 17 00:00:00 2001 From: Mingguang Xu Date: Wed, 14 Apr 2021 22:24:30 -0700 Subject: [PATCH 7/9] btaa: gd: Add wakeup reason dumpsys data Create a circular buffer for wakeup history and plumb wakeup history to dumpsys. Tag: #feature Bug: 185037337 Bug: 170315554 Test: mmma -j system/bt Test: manual BYPASS_LONG_LINES_REASON: consist with gd format Change-Id: I468ac585ed0cd3415176b5d9a373e9332efe4d99 --- gd/Android.bp | 4 +++ gd/btaa/activity_attribution.fbs | 36 +++++++++++++++++++ gd/btaa/activity_attribution.h | 2 ++ gd/btaa/android/activity_attribution.cc | 20 +++++++++++ gd/btaa/attribution_processor.h | 13 +++++++ gd/btaa/host/activity_attribution.cc | 4 +++ .../linux_generic/attribution_processor.cc | 31 ++++++++++++++++ gd/dumpsys_data.fbs | 2 ++ 8 files changed, 112 insertions(+) create mode 100644 gd/btaa/activity_attribution.fbs diff --git a/gd/Android.bp b/gd/Android.bp index 21ba08c3e2..f1444c73f5 100644 --- a/gd/Android.bp +++ b/gd/Android.bp @@ -575,6 +575,7 @@ genrule { ], cmd: "$(location flatc) -I system/bt/gd -b --schema -o $(genDir) $(in) ", srcs: [ + "btaa/activity_attribution.fbs", "common/init_flags.fbs", "dumpsys_data.fbs", "hci/hci_acl_manager.fbs", @@ -582,6 +583,7 @@ genrule { "shim/dumpsys.fbs", ], out: [ + "activity_attribution.bfbs", "init_flags.bfbs", "dumpsys.bfbs", "dumpsys_data.bfbs", @@ -597,6 +599,7 @@ genrule { ], cmd: "$(location flatc) -I system/bt/gd -o $(genDir) --cpp $(in) ", srcs: [ + "btaa/activity_attribution.fbs", "common/init_flags.fbs", "dumpsys_data.fbs", "hci/hci_acl_manager.fbs", @@ -604,6 +607,7 @@ genrule { "shim/dumpsys.fbs", ], out: [ + "activity_attribution_generated.h", "dumpsys_data_generated.h", "dumpsys_generated.h", "hci_acl_manager_generated.h", diff --git a/gd/btaa/activity_attribution.fbs b/gd/btaa/activity_attribution.fbs new file mode 100644 index 0000000000..ba49b61b9a --- /dev/null +++ b/gd/btaa/activity_attribution.fbs @@ -0,0 +1,36 @@ +namespace bluetooth.activity_attribution; + +attribute "privacy"; + +table WakeupEntry { + wakeup_time:string; + activity:string; + address:string; +} + +table WakeupAttributionData { + title:string; + num_wakeup:int; + wakeup_attribution:[WakeupEntry]; +} + +table DeviceActivityAggregationEntry { + address:string; + activity:string; + wakeup_count:int; + byte_count:int; + wakelock_duration:int; +} + +table DeviceActivityAggregationData { + title:string; + device_activity_aggregation:[DeviceActivityAggregationEntry]; +} + +table ActivityAttributionData { + title:string (privacy:"Any"); + wakeup_attribution_data:WakeupAttributionData (privacy:"Any"); + device_activity_aggregation_data:DeviceActivityAggregationData (privacy:"Any"); +} + +root_type ActivityAttributionData; \ No newline at end of file diff --git a/gd/btaa/activity_attribution.h b/gd/btaa/activity_attribution.h index 2f0ae26af9..b6f45b0363 100644 --- a/gd/btaa/activity_attribution.h +++ b/gd/btaa/activity_attribution.h @@ -24,6 +24,7 @@ namespace bluetooth { namespace activity_attribution { enum class Activity : uint8_t { UNKNOWN = 0, ADVERTISE, CONNECT, CONTROL, SCAN, HFP, VENDOR }; +#define CONVERT_ACTIVITY_TO_STR(Activity) std::string(#Activity) struct BtaaAggregationEntry { hci::Address address; @@ -62,6 +63,7 @@ class ActivityAttribution : public bluetooth::Module { void ListDependencies(ModuleList* list) override; void Start() override; void Stop() override; + DumpsysDataFinisher GetDumpsysData(flatbuffers::FlatBufferBuilder* builder) const override; // Module private: struct impl; diff --git a/gd/btaa/android/activity_attribution.cc b/gd/btaa/android/activity_attribution.cc index 2c19e52028..7936623599 100644 --- a/gd/btaa/android/activity_attribution.cc +++ b/gd/btaa/android/activity_attribution.cc @@ -17,6 +17,7 @@ #define LOG_TAG "btaa" #include "btaa/activity_attribution.h" +#include "activity_attribution_generated.h" #include #include @@ -126,6 +127,11 @@ struct ActivityAttribution::impl { callback_ = callback; } + void Dump( + std::promise> promise, flatbuffers::FlatBufferBuilder* fb_builder) { + attribution_processor_.Dump(std::move(promise), fb_builder); + } + ActivityAttributionCallback* callback_; AttributionProcessor attribution_processor_; HciProcessor hci_processor_; @@ -186,5 +192,19 @@ void ActivityAttribution::Stop() { pimpl_.reset(); } +DumpsysDataFinisher ActivityAttribution::GetDumpsysData(flatbuffers::FlatBufferBuilder* fb_builder) const { + ASSERT(fb_builder != nullptr); + + std::promise> promise; + auto future = promise.get_future(); + pimpl_->Dump(std::move(promise), fb_builder); + + auto dumpsys_data = future.get(); + + return [dumpsys_data](DumpsysDataBuilder* dumpsys_builder) { + dumpsys_builder->add_activity_attribution_dumpsys_data(dumpsys_data); + }; +} + } // namespace activity_attribution } // namespace bluetooth diff --git a/gd/btaa/attribution_processor.h b/gd/btaa/attribution_processor.h index 2a01013fbf..7515fbb1ac 100644 --- a/gd/btaa/attribution_processor.h +++ b/gd/btaa/attribution_processor.h @@ -24,6 +24,8 @@ namespace bluetooth { namespace activity_attribution { +static constexpr size_t kWakeupAggregatorSize = 200; + struct AddressActivityKey { hci::Address address; Activity activity; @@ -41,16 +43,27 @@ struct AddressActivityKeyHasher { } }; +struct WakeupDescriptor { + Activity activity_; + const hci::Address address_; + WakeupDescriptor(Activity activity, const hci::Address address) : activity_(activity), address_(address) {} + virtual ~WakeupDescriptor() {} +}; + class AttributionProcessor { public: void OnBtaaPackets(std::vector btaa_packets); void OnWakelockReleased(uint32_t duration_ms); void OnWakeup(); + void Dump( + std::promise> promise, flatbuffers::FlatBufferBuilder* fb_builder); private: bool wakeup_ = false; std::unordered_map btaa_aggregator_; std::unordered_map wakelock_duration_aggregator_; + common::TimestampedCircularBuffer wakeup_aggregator_ = + common::TimestampedCircularBuffer(kWakeupAggregatorSize); }; } // namespace activity_attribution diff --git a/gd/btaa/host/activity_attribution.cc b/gd/btaa/host/activity_attribution.cc index 2d9462a533..a2f7d70a9c 100644 --- a/gd/btaa/host/activity_attribution.cc +++ b/gd/btaa/host/activity_attribution.cc @@ -43,5 +43,9 @@ void ActivityAttribution::Stop() {} const ModuleFactory ActivityAttribution::Factory = ModuleFactory([]() { return new ActivityAttribution(); }); +DumpsysDataFinisher EmptyDumpsysDataFinisher = [](DumpsysDataBuilder* dumpsys_data_builder) {}; +DumpsysDataFinisher ActivityAttribution::GetDumpsysData(flatbuffers::FlatBufferBuilder* builder) const { + return EmptyDumpsysDataFinisher; +} } // namespace activity_attribution } // namespace bluetooth diff --git a/gd/btaa/linux_generic/attribution_processor.cc b/gd/btaa/linux_generic/attribution_processor.cc index 56c1c32d1d..d1a5ef8e91 100644 --- a/gd/btaa/linux_generic/attribution_processor.cc +++ b/gd/btaa/linux_generic/attribution_processor.cc @@ -35,6 +35,7 @@ void AttributionProcessor::OnBtaaPackets(std::vector btaa_packets if (wakeup_) { wakelock_duration_aggregator_[key].wakeup_count += 1; + wakeup_aggregator_.Push(std::move(WakeupDescriptor(btaa_packet.activity, btaa_packet.address))); } } wakeup_ = false; @@ -73,5 +74,35 @@ void AttributionProcessor::OnWakeup() { wakeup_ = true; } +void AttributionProcessor::Dump( + std::promise> promise, flatbuffers::FlatBufferBuilder* fb_builder) { + auto title = fb_builder->CreateString("----- BTAA Dumpsys -----"); + ActivityAttributionDataBuilder builder(*fb_builder); + builder.add_title(title); + + WakeupAttributionDataBuilder wakeup_attribution_builder(*fb_builder); + auto wakeup_title = fb_builder->CreateString("----- Wakeup Attribution Dumpsys -----"); + wakeup_attribution_builder.add_title(wakeup_title); + + std::vector> wakeup_aggregator = wakeup_aggregator_.Pull(); + wakeup_attribution_builder.add_num_wakeup(wakeup_aggregator.size()); + + std::vector> wakeup_entry_offsets; + for (auto wakeup : wakeup_aggregator) { + WakeupEntryBuilder wakeup_entry_builder(*fb_builder); + wakeup_entry_builder.add_wakeup_time(wakeup.timestamp); + wakeup_entry_builder.add_activity(fb_builder->CreateString((CONVERT_ACTIVITY_TO_STR(wakeup.entry.activity_)))); + wakeup_entry_builder.add_address(fb_builder->CreateString(wakeup.entry.address_.ToString())); + wakeup_entry_offsets.push_back(wakeup_entry_builder.Finish()); + } + auto wakeup_entries = fb_builder->CreateVector(wakeup_entry_offsets); + wakeup_attribution_builder.add_wakeup_attribution(wakeup_entries); + + builder.add_wakeup_attribution_data(wakeup_attribution_builder.Finish()); + + flatbuffers::Offset dumpsys_data = builder.Finish(); + promise.set_value(dumpsys_data); +} + } // namespace activity_attribution } // namespace bluetooth diff --git a/gd/dumpsys_data.fbs b/gd/dumpsys_data.fbs index 5c3c76b0d5..48284549e3 100644 --- a/gd/dumpsys_data.fbs +++ b/gd/dumpsys_data.fbs @@ -1,4 +1,5 @@ // Top level module dumpsys data schema +include "btaa/activity_attribution.fbs"; include "common/init_flags.fbs"; include "l2cap/classic/l2cap_classic_module.fbs"; include "hci/hci_acl_manager.fbs"; @@ -16,6 +17,7 @@ table DumpsysData { l2cap_classic_dumpsys_data:bluetooth.l2cap.classic.L2capClassicModuleData (privacy:"Any"); hci_acl_manager_dumpsys_data:bluetooth.hci.AclManagerData (privacy:"Any"); module_unittest_data:bluetooth.ModuleUnitTestData; // private + activity_attribution_dumpsys_data:bluetooth.activity_attribution.ActivityAttributionData (privacy:"Any"); } root_type DumpsysData; From 8c0b4614b44f80c94cef9518fbe6f43516329df7 Mon Sep 17 00:00:00 2001 From: Mingguang Xu Date: Fri, 16 Apr 2021 13:31:46 -0700 Subject: [PATCH 8/9] btaa: HCI ACL/SCO/ISO data packets process Parse ACL/SCO/ISO packets to get connection handle, match to device address, and attribute them to device-based activities. Tag: #feature Bug: 185596854 Bug: 170315554 Test: mmma -j system/bt Test: manual BYPASS_LONG_LINES_REASON: consist with gd format Change-Id: Icb879814ee34700afa35ace1cdca8ff1e8f55fe4 --- gd/btaa/activity_attribution.h | 2 +- gd/btaa/android/activity_attribution.cc | 3 +- gd/btaa/linux_generic/hci_processor.cc | 42 ++++++++++++++++++++++ include/hardware/bt_activity_attribution.h | 6 ++-- 4 files changed, 49 insertions(+), 4 deletions(-) diff --git a/gd/btaa/activity_attribution.h b/gd/btaa/activity_attribution.h index b6f45b0363..8b7ca03d6b 100644 --- a/gd/btaa/activity_attribution.h +++ b/gd/btaa/activity_attribution.h @@ -23,7 +23,7 @@ namespace bluetooth { namespace activity_attribution { -enum class Activity : uint8_t { UNKNOWN = 0, ADVERTISE, CONNECT, CONTROL, SCAN, HFP, VENDOR }; +enum class Activity : uint8_t { UNKNOWN = 0, ACL, ADVERTISE, CONNECT, CONTROL, HFP, ISO, SCAN, VENDOR }; #define CONVERT_ACTIVITY_TO_STR(Activity) std::string(#Activity) struct BtaaAggregationEntry { diff --git a/gd/btaa/android/activity_attribution.cc b/gd/btaa/android/activity_attribution.cc index 7936623599..3b72feb3ae 100644 --- a/gd/btaa/android/activity_attribution.cc +++ b/gd/btaa/android/activity_attribution.cc @@ -44,6 +44,7 @@ const ModuleFactory ActivityAttribution::Factory = ModuleFactory([]() { return n static const std::string kBtWakelockName("hal_bluetooth_lock"); static const std::string kBtWakeupReason("hs_uart_wakeup"); +static const size_t kHciAclHeaderSize = 4; struct wakelock_callback : public BnWakelockCallback { wakelock_callback(ActivityAttribution* module) : module_(module) {} @@ -150,7 +151,7 @@ void ActivityAttribution::Capture(const hal::HciPacket& packet, hal::SnoopLogger case hal::SnoopLogger::PacketType::ACL: case hal::SnoopLogger::PacketType::SCO: case hal::SnoopLogger::PacketType::ISO: - truncate_length = 0; + truncate_length = kHciAclHeaderSize; break; } diff --git a/gd/btaa/linux_generic/hci_processor.cc b/gd/btaa/linux_generic/hci_processor.cc index b97667df83..f1962c2dca 100644 --- a/gd/btaa/linux_generic/hci_processor.cc +++ b/gd/btaa/linux_generic/hci_processor.cc @@ -215,6 +215,45 @@ static void process_event( } } +static void process_acl( + std::vector& btaa_hci_packets, + packet::PacketView& packet_view, + uint16_t byte_count) { + hci::AclView acl = hci::AclView::Create(packet_view); + auto connection_handle = acl.begin(); + // Connection handle is extracted from the 12 least significant bit. + uint16_t connection_handle_value = connection_handle.extract() & 0xfff; + hci::Address address_value; + device_parser.match_handle_with_address(connection_handle_value, address_value); + btaa_hci_packets.push_back(BtaaHciPacket(Activity::ACL, address_value, byte_count)); +} + +static void process_sco( + std::vector& btaa_hci_packets, + packet::PacketView& packet_view, + uint16_t byte_count) { + hci::ScoView sco = hci::ScoView::Create(packet_view); + auto connection_handle = sco.begin(); + // Connection handle is extracted from the 12 least significant bit. + uint16_t connection_handle_value = connection_handle.extract() & 0xfff; + hci::Address address_value; + device_parser.match_handle_with_address(connection_handle_value, address_value); + btaa_hci_packets.push_back(BtaaHciPacket(Activity::HFP, address_value, byte_count)); +} + +static void process_iso( + std::vector& btaa_hci_packets, + packet::PacketView& packet_view, + uint16_t byte_count) { + hci::IsoView iso = hci::IsoView::Create(packet_view); + auto connection_handle = iso.begin(); + // Connection handle is extracted from the 12 least significant bit. + uint16_t connection_handle_value = connection_handle.extract() & 0xfff; + hci::Address address_value; + device_parser.match_handle_with_address(connection_handle_value, address_value); + btaa_hci_packets.push_back(BtaaHciPacket(Activity::ISO, address_value, byte_count)); +} + std::vector HciProcessor::OnHciPacket( hal::HciPacket packet, hal::SnoopLogger::PacketType type, uint16_t length) { std::vector btaa_hci_packets; @@ -227,10 +266,13 @@ std::vector HciProcessor::OnHciPacket( process_event(btaa_hci_packets, packet_view, length); break; case hal::SnoopLogger::PacketType::ACL: + process_acl(btaa_hci_packets, packet_view, length); break; case hal::SnoopLogger::PacketType::SCO: + process_sco(btaa_hci_packets, packet_view, length); break; case hal::SnoopLogger::PacketType::ISO: + process_iso(btaa_hci_packets, packet_view, length); break; } return btaa_hci_packets; diff --git a/include/hardware/bt_activity_attribution.h b/include/hardware/bt_activity_attribution.h index 74e44045d7..069e7d0dcc 100644 --- a/include/hardware/bt_activity_attribution.h +++ b/include/hardware/bt_activity_attribution.h @@ -26,12 +26,14 @@ class ActivityAttributionCallbacks { public: enum class Activity : uint8_t { UNKNOWN = 0, + ACL, ADVERTISE, CONNECT, CONTROL, - SCAN, HFP, - VENDOR + ISO, + SCAN, + VENDOR, }; struct BtaaAggregationEntry { From 73925660685d29df2781660860ab31ea4aa6b037 Mon Sep 17 00:00:00 2001 From: Mingguang Xu Date: Mon, 19 Apr 2021 13:27:19 -0700 Subject: [PATCH 9/9] btaa: Add device-activity aggregation dumpsys data 1. Add create time into each aggregation entry; aggregation entry expires after one day. 2. Add device-activity into dumpsys data; Trim down transient aggregation entries to avoid the unordered map overgrows. Tag: #feature Bug: 185819535 Bug: 170315554 Test: mmma -j system/bt Test: manually capture a bugreport and make sure btaa aggregation data show up BYPASS_LONG_LINES_REASON: consist with gd format Change-Id: I02cc2057796661fa3625492eaf1a429e20da4951 --- gd/btaa/activity_attribution.fbs | 23 ++-- gd/btaa/activity_attribution.h | 6 +- gd/btaa/attribution_processor.h | 1 + .../linux_generic/attribution_processor.cc | 109 +++++++++++++++--- main/shim/activity_attribution.cc | 2 +- 5 files changed, 105 insertions(+), 36 deletions(-) diff --git a/gd/btaa/activity_attribution.fbs b/gd/btaa/activity_attribution.fbs index ba49b61b9a..9ff18cd3a8 100644 --- a/gd/btaa/activity_attribution.fbs +++ b/gd/btaa/activity_attribution.fbs @@ -8,29 +8,22 @@ table WakeupEntry { address:string; } -table WakeupAttributionData { - title:string; - num_wakeup:int; - wakeup_attribution:[WakeupEntry]; -} - table DeviceActivityAggregationEntry { address:string; activity:string; wakeup_count:int; byte_count:int; - wakelock_duration:int; -} - -table DeviceActivityAggregationData { - title:string; - device_activity_aggregation:[DeviceActivityAggregationEntry]; + wakelock_duration_ms:int; + creation_time:string; } table ActivityAttributionData { - title:string (privacy:"Any"); - wakeup_attribution_data:WakeupAttributionData (privacy:"Any"); - device_activity_aggregation_data:DeviceActivityAggregationData (privacy:"Any"); + title_wakeup:string; + num_wakeup:int; + wakeup_attribution:[WakeupEntry]; + title_activity:string; + num_device_activity:int; + device_activity_aggregation:[DeviceActivityAggregationEntry]; } root_type ActivityAttributionData; \ No newline at end of file diff --git a/gd/btaa/activity_attribution.h b/gd/btaa/activity_attribution.h index 8b7ca03d6b..9bba347fe5 100644 --- a/gd/btaa/activity_attribution.h +++ b/gd/btaa/activity_attribution.h @@ -24,14 +24,16 @@ namespace bluetooth { namespace activity_attribution { enum class Activity : uint8_t { UNKNOWN = 0, ACL, ADVERTISE, CONNECT, CONTROL, HFP, ISO, SCAN, VENDOR }; -#define CONVERT_ACTIVITY_TO_STR(Activity) std::string(#Activity) + +using CreationTime = std::chrono::time_point; struct BtaaAggregationEntry { hci::Address address; Activity activity; uint16_t wakeup_count; uint32_t byte_count; - uint32_t wakelock_duration; + uint32_t wakelock_duration_ms; + CreationTime creation_time; }; class ActivityAttributionCallback { diff --git a/gd/btaa/attribution_processor.h b/gd/btaa/attribution_processor.h index 7515fbb1ac..11bbc9cc47 100644 --- a/gd/btaa/attribution_processor.h +++ b/gd/btaa/attribution_processor.h @@ -64,6 +64,7 @@ class AttributionProcessor { std::unordered_map wakelock_duration_aggregator_; common::TimestampedCircularBuffer wakeup_aggregator_ = common::TimestampedCircularBuffer(kWakeupAggregatorSize); + const char* ActivityToString(Activity activity); }; } // namespace activity_attribution diff --git a/gd/btaa/linux_generic/attribution_processor.cc b/gd/btaa/linux_generic/attribution_processor.cc index d1a5ef8e91..a55243a060 100644 --- a/gd/btaa/linux_generic/attribution_processor.cc +++ b/gd/btaa/linux_generic/attribution_processor.cc @@ -15,12 +15,22 @@ */ #include "btaa/attribution_processor.h" +#include "common/strings.h" #include "os/log.h" namespace bluetooth { namespace activity_attribution { +constexpr char kActivityAttributionTimeFormat[] = "%Y-%m-%d %H:%M:%S"; +// A device-activity aggregation entry expires after two days (172800 seconds) +static const int kDurationToKeepDeviceActivityEntrySecs = 172800; +// A transient device-activity aggregation entry is defined as an entry with very few Byte count +// (200 Bytes, this is about the size of 5 advertising packets) over a period of time (15 minutes) +static const int kByteCountTransientDeviceActivityEntry = 200; +static const int kDurationTransientDeviceActivityEntrySecs = 900; +static const int kMapSizeTrimDownAggregationEntry = 200; + void AttributionProcessor::OnBtaaPackets(std::vector btaa_packets) { AddressActivityKey key; @@ -54,17 +64,41 @@ void AttributionProcessor::OnWakelockReleased(uint32_t duration_ms) { } ms_per_byte = duration_ms / total_byte_count; + auto cur_time = std::chrono::system_clock::now(); for (auto& it : wakelock_duration_aggregator_) { - it.second.wakelock_duration = ms_per_byte * it.second.byte_count; + it.second.wakelock_duration_ms = ms_per_byte * it.second.byte_count; if (btaa_aggregator_.find(it.first) == btaa_aggregator_.end()) { btaa_aggregator_[it.first] = {}; + btaa_aggregator_[it.first].creation_time = cur_time; + } + + auto elapsed_time_sec = + std::chrono::duration_cast(cur_time - btaa_aggregator_[it.first].creation_time).count(); + if (elapsed_time_sec > kDurationToKeepDeviceActivityEntrySecs) { + btaa_aggregator_[it.first].wakeup_count = 0; + btaa_aggregator_[it.first].byte_count = 0; + btaa_aggregator_[it.first].wakelock_duration_ms = 0; + btaa_aggregator_[it.first].creation_time = cur_time; } btaa_aggregator_[it.first].wakeup_count += it.second.wakeup_count; btaa_aggregator_[it.first].byte_count += it.second.byte_count; - btaa_aggregator_[it.first].wakelock_duration += it.second.wakelock_duration; + btaa_aggregator_[it.first].wakelock_duration_ms += it.second.wakelock_duration_ms; } wakelock_duration_aggregator_.clear(); + + if (btaa_aggregator_.size() < kMapSizeTrimDownAggregationEntry) { + return; + } + // Trim down the transient entries in the aggregator to avoid that it overgrows + for (auto& it : btaa_aggregator_) { + auto elapsed_time_sec = + std::chrono::duration_cast(cur_time - it.second.creation_time).count(); + if (elapsed_time_sec > kDurationTransientDeviceActivityEntrySecs && + it.second.byte_count < kByteCountTransientDeviceActivityEntry) { + btaa_aggregator_.erase(it.first); + } + } } void AttributionProcessor::OnWakeup() { @@ -76,33 +110,72 @@ void AttributionProcessor::OnWakeup() { void AttributionProcessor::Dump( std::promise> promise, flatbuffers::FlatBufferBuilder* fb_builder) { - auto title = fb_builder->CreateString("----- BTAA Dumpsys -----"); - ActivityAttributionDataBuilder builder(*fb_builder); - builder.add_title(title); - - WakeupAttributionDataBuilder wakeup_attribution_builder(*fb_builder); - auto wakeup_title = fb_builder->CreateString("----- Wakeup Attribution Dumpsys -----"); - wakeup_attribution_builder.add_title(wakeup_title); - + // Dump wakeup attribution data + auto title_wakeup = fb_builder->CreateString("----- Wakeup Attribution Dumpsys -----"); std::vector> wakeup_aggregator = wakeup_aggregator_.Pull(); - wakeup_attribution_builder.add_num_wakeup(wakeup_aggregator.size()); - std::vector> wakeup_entry_offsets; - for (auto wakeup : wakeup_aggregator) { + for (auto& it : wakeup_aggregator) { WakeupEntryBuilder wakeup_entry_builder(*fb_builder); - wakeup_entry_builder.add_wakeup_time(wakeup.timestamp); - wakeup_entry_builder.add_activity(fb_builder->CreateString((CONVERT_ACTIVITY_TO_STR(wakeup.entry.activity_)))); - wakeup_entry_builder.add_address(fb_builder->CreateString(wakeup.entry.address_.ToString())); + std::chrono::milliseconds duration(it.timestamp); + std::chrono::time_point wakeup_time(duration); + wakeup_entry_builder.add_wakeup_time(fb_builder->CreateString( + bluetooth::common::StringFormatTimeWithMilliseconds(kActivityAttributionTimeFormat, wakeup_time).c_str())); + wakeup_entry_builder.add_activity(fb_builder->CreateString((ActivityToString(it.entry.activity_)))); + wakeup_entry_builder.add_address(fb_builder->CreateString(it.entry.address_.ToString())); wakeup_entry_offsets.push_back(wakeup_entry_builder.Finish()); } auto wakeup_entries = fb_builder->CreateVector(wakeup_entry_offsets); - wakeup_attribution_builder.add_wakeup_attribution(wakeup_entries); - builder.add_wakeup_attribution_data(wakeup_attribution_builder.Finish()); + // Dump device-based activity aggregation data + auto title_device_activity = fb_builder->CreateString("----- Device-based Activity Attribution Dumpsys -----"); + std::vector> aggregation_entry_offsets; + for (auto& it : btaa_aggregator_) { + DeviceActivityAggregationEntryBuilder device_entry_builder(*fb_builder); + device_entry_builder.add_address(fb_builder->CreateString(it.first.address.ToString())); + device_entry_builder.add_activity(fb_builder->CreateString((ActivityToString(it.first.activity)))); + device_entry_builder.add_wakeup_count(it.second.wakeup_count); + device_entry_builder.add_byte_count(it.second.byte_count); + device_entry_builder.add_wakelock_duration_ms(it.second.wakelock_duration_ms); + device_entry_builder.add_creation_time(fb_builder->CreateString( + bluetooth::common::StringFormatTimeWithMilliseconds(kActivityAttributionTimeFormat, it.second.creation_time) + .c_str())); + aggregation_entry_offsets.push_back(device_entry_builder.Finish()); + } + auto aggregation_entries = fb_builder->CreateVector(aggregation_entry_offsets); + + ActivityAttributionDataBuilder builder(*fb_builder); + builder.add_title_wakeup(title_wakeup); + builder.add_num_wakeup(wakeup_aggregator.size()); + builder.add_wakeup_attribution(wakeup_entries); + builder.add_title_activity(title_device_activity); + builder.add_num_device_activity(btaa_aggregator_.size()); + builder.add_device_activity_aggregation(aggregation_entries); + btaa_aggregator_.clear(); flatbuffers::Offset dumpsys_data = builder.Finish(); promise.set_value(dumpsys_data); } +#ifndef CASE_RETURN_TEXT +#define CASE_RETURN_TEXT(code) \ + case code: \ + return #code +#endif + +const char* AttributionProcessor::ActivityToString(Activity activity) { + switch (activity) { + CASE_RETURN_TEXT(Activity::ACL); + CASE_RETURN_TEXT(Activity::ADVERTISE); + CASE_RETURN_TEXT(Activity::CONNECT); + CASE_RETURN_TEXT(Activity::CONTROL); + CASE_RETURN_TEXT(Activity::HFP); + CASE_RETURN_TEXT(Activity::ISO); + CASE_RETURN_TEXT(Activity::SCAN); + CASE_RETURN_TEXT(Activity::VENDOR); + default: + return "UNKNOWN"; + } +} + } // namespace activity_attribution } // namespace bluetooth diff --git a/main/shim/activity_attribution.cc b/main/shim/activity_attribution.cc index 3b07196420..5b51fa9632 100644 --- a/main/shim/activity_attribution.cc +++ b/main/shim/activity_attribution.cc @@ -62,7 +62,7 @@ class ActivityAttributionInterfaceImpl ActivityAttributionCallbacks::BtaaAggregationEntry entry{ bluetooth::ToRawAddress(it.address), (ActivityAttributionCallbacks::Activity)it.activity, it.wakeup_count, - it.byte_count, it.wakelock_duration}; + it.byte_count, it.wakelock_duration_ms}; callback_logs.push_back(entry); } do_in_jni_thread(