• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 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 #include "btaa/attribution_processor.h"
18 #include "common/strings.h"
19 
20 #include "os/log.h"
21 
22 namespace bluetooth {
23 namespace activity_attribution {
24 
25 constexpr char kActivityAttributionTimeFormat[] = "%Y-%m-%d %H:%M:%S";
26 // A device-activity aggregation entry expires after two days (172800 seconds)
27 static const int kDurationToKeepDeviceActivityEntrySecs = 172800;
28 // A transient device-activity aggregation entry is defined as an entry with very few Byte count
29 // (200 Bytes, this is about the size of 5 advertising packets) over a period of time (15 minutes)
30 static const int kByteCountTransientDeviceActivityEntry = 200;
31 static const int kDurationTransientDeviceActivityEntrySecs = 900;
32 static const int kMapSizeTrimDownAggregationEntry = 200;
33 
OnBtaaPackets(std::vector<BtaaHciPacket> btaa_packets)34 void AttributionProcessor::OnBtaaPackets(std::vector<BtaaHciPacket> btaa_packets) {
35   AddressActivityKey key;
36 
37   for (auto& btaa_packet : btaa_packets) {
38     key.address = btaa_packet.address;
39     key.activity = btaa_packet.activity;
40 
41     if (wakelock_duration_aggregator_.find(key) == wakelock_duration_aggregator_.end()) {
42       wakelock_duration_aggregator_[key] = {};
43     }
44     wakelock_duration_aggregator_[key].byte_count += btaa_packet.byte_count;
45 
46     if (wakeup_) {
47       wakelock_duration_aggregator_[key].wakeup_count += 1;
48       wakeup_aggregator_.Push(std::move(WakeupDescriptor(btaa_packet.activity, btaa_packet.address)));
49     }
50   }
51   wakeup_ = false;
52 }
53 
OnWakelockReleased(uint32_t duration_ms)54 void AttributionProcessor::OnWakelockReleased(uint32_t duration_ms) {
55   uint32_t total_byte_count = 0;
56   uint32_t ms_per_byte = 0;
57 
58   for (auto& it : wakelock_duration_aggregator_) {
59     total_byte_count += it.second.byte_count;
60   }
61 
62   if (total_byte_count == 0) {
63     return;
64   }
65 
66   ms_per_byte = duration_ms / total_byte_count;
67   auto cur_time = std::chrono::system_clock::now();
68   for (auto& it : wakelock_duration_aggregator_) {
69     it.second.wakelock_duration_ms = ms_per_byte * it.second.byte_count;
70     if (btaa_aggregator_.find(it.first) == btaa_aggregator_.end()) {
71       btaa_aggregator_[it.first] = {};
72       btaa_aggregator_[it.first].creation_time = cur_time;
73     }
74 
75     auto elapsed_time_sec =
76         std::chrono::duration_cast<std::chrono::seconds>(cur_time - btaa_aggregator_[it.first].creation_time).count();
77     if (elapsed_time_sec > kDurationToKeepDeviceActivityEntrySecs) {
78       btaa_aggregator_[it.first].wakeup_count = 0;
79       btaa_aggregator_[it.first].byte_count = 0;
80       btaa_aggregator_[it.first].wakelock_duration_ms = 0;
81       btaa_aggregator_[it.first].creation_time = cur_time;
82     }
83 
84     btaa_aggregator_[it.first].wakeup_count += it.second.wakeup_count;
85     btaa_aggregator_[it.first].byte_count += it.second.byte_count;
86     btaa_aggregator_[it.first].wakelock_duration_ms += it.second.wakelock_duration_ms;
87   }
88   wakelock_duration_aggregator_.clear();
89 
90   if (btaa_aggregator_.size() < kMapSizeTrimDownAggregationEntry) {
91     return;
92   }
93   // Trim down the transient entries in the aggregator to avoid that it overgrows
94   for (auto& it : btaa_aggregator_) {
95     auto elapsed_time_sec =
96         std::chrono::duration_cast<std::chrono::seconds>(cur_time - it.second.creation_time).count();
97     if (elapsed_time_sec > kDurationTransientDeviceActivityEntrySecs &&
98         it.second.byte_count < kByteCountTransientDeviceActivityEntry) {
99       btaa_aggregator_.erase(it.first);
100     }
101   }
102 }
103 
OnWakeup()104 void AttributionProcessor::OnWakeup() {
105   if (wakeup_) {
106     LOG_INFO("Previous wakeup notification is not consumed.");
107   }
108   wakeup_ = true;
109 }
110 
Dump(std::promise<flatbuffers::Offset<ActivityAttributionData>> promise,flatbuffers::FlatBufferBuilder * fb_builder)111 void AttributionProcessor::Dump(
112     std::promise<flatbuffers::Offset<ActivityAttributionData>> promise, flatbuffers::FlatBufferBuilder* fb_builder) {
113   // Dump wakeup attribution data
114   auto title_wakeup = fb_builder->CreateString("----- Wakeup Attribution Dumpsys -----");
115   std::vector<common::TimestampedEntry<WakeupDescriptor>> wakeup_aggregator = wakeup_aggregator_.Pull();
116   std::vector<flatbuffers::Offset<WakeupEntry>> wakeup_entry_offsets;
117   for (auto& it : wakeup_aggregator) {
118     WakeupEntryBuilder wakeup_entry_builder(*fb_builder);
119     std::chrono::milliseconds duration(it.timestamp);
120     std::chrono::time_point<std::chrono::system_clock> wakeup_time(duration);
121     wakeup_entry_builder.add_wakeup_time(fb_builder->CreateString(
122         bluetooth::common::StringFormatTimeWithMilliseconds(kActivityAttributionTimeFormat, wakeup_time).c_str()));
123     wakeup_entry_builder.add_activity(fb_builder->CreateString((ActivityToString(it.entry.activity_))));
124     wakeup_entry_builder.add_address(fb_builder->CreateString(it.entry.address_.ToString()));
125     wakeup_entry_offsets.push_back(wakeup_entry_builder.Finish());
126   }
127   auto wakeup_entries = fb_builder->CreateVector(wakeup_entry_offsets);
128 
129   // Dump device-based activity aggregation data
130   auto title_device_activity = fb_builder->CreateString("----- Device-based Activity Attribution Dumpsys -----");
131   std::vector<flatbuffers::Offset<DeviceActivityAggregationEntry>> aggregation_entry_offsets;
132   for (auto& it : btaa_aggregator_) {
133     DeviceActivityAggregationEntryBuilder device_entry_builder(*fb_builder);
134     device_entry_builder.add_address(fb_builder->CreateString(it.first.address.ToString()));
135     device_entry_builder.add_activity(fb_builder->CreateString((ActivityToString(it.first.activity))));
136     device_entry_builder.add_wakeup_count(it.second.wakeup_count);
137     device_entry_builder.add_byte_count(it.second.byte_count);
138     device_entry_builder.add_wakelock_duration_ms(it.second.wakelock_duration_ms);
139     device_entry_builder.add_creation_time(fb_builder->CreateString(
140         bluetooth::common::StringFormatTimeWithMilliseconds(kActivityAttributionTimeFormat, it.second.creation_time)
141             .c_str()));
142     aggregation_entry_offsets.push_back(device_entry_builder.Finish());
143   }
144   auto aggregation_entries = fb_builder->CreateVector(aggregation_entry_offsets);
145 
146   ActivityAttributionDataBuilder builder(*fb_builder);
147   builder.add_title_wakeup(title_wakeup);
148   builder.add_num_wakeup(wakeup_aggregator.size());
149   builder.add_wakeup_attribution(wakeup_entries);
150   builder.add_title_activity(title_device_activity);
151   builder.add_num_device_activity(btaa_aggregator_.size());
152   builder.add_device_activity_aggregation(aggregation_entries);
153   btaa_aggregator_.clear();
154 
155   flatbuffers::Offset<ActivityAttributionData> dumpsys_data = builder.Finish();
156   promise.set_value(dumpsys_data);
157 }
158 
159 #ifndef CASE_RETURN_TEXT
160 #define CASE_RETURN_TEXT(code) \
161   case code:                   \
162     return #code
163 #endif
164 
ActivityToString(Activity activity)165 const char* AttributionProcessor::ActivityToString(Activity activity) {
166   switch (activity) {
167     CASE_RETURN_TEXT(Activity::ACL);
168     CASE_RETURN_TEXT(Activity::ADVERTISE);
169     CASE_RETURN_TEXT(Activity::CONNECT);
170     CASE_RETURN_TEXT(Activity::CONTROL);
171     CASE_RETURN_TEXT(Activity::HFP);
172     CASE_RETURN_TEXT(Activity::ISO);
173     CASE_RETURN_TEXT(Activity::SCAN);
174     CASE_RETURN_TEXT(Activity::VENDOR);
175     default:
176       return "UNKNOWN";
177   }
178 }
179 
180 }  // namespace activity_attribution
181 }  // namespace bluetooth
182