1 #include "location/lbs/contexthub/nanoapps/nearby/tracker_storage.h"
2
3 #include <inttypes.h>
4
5 #include <cstdint>
6 #include <cstring>
7 #include <utility>
8
9 #include "chre_api/chre.h"
10 #include "third_party/contexthub/chre/util/include/chre/util/nanoapp/log.h"
11 #include "third_party/contexthub/chre/util/include/chre/util/time.h"
12 #include "third_party/contexthub/chre/util/include/chre/util/unique_ptr.h"
13
14 #define LOG_TAG "[NEARBY][TRACKER_STORAGE]"
15
16 namespace nearby {
17
Push(const chreBleAdvertisingReport & report,const TrackerBatchConfig & config)18 void TrackerStorage::Push(const chreBleAdvertisingReport &report,
19 const TrackerBatchConfig &config) {
20 for (auto &tracker_report : tracker_reports_) {
21 if (IsEqualAddress(tracker_report, report)) {
22 UpdateTrackerReport(tracker_report, config, report);
23 return;
24 }
25 }
26 AddTrackerReport(report, config);
27 }
28
Refresh(const TrackerBatchConfig & config)29 void TrackerStorage::Refresh(const TrackerBatchConfig &config) {
30 uint32_t current_time_ms = GetCurrentTimeMs();
31 if (config.lost_timeout_ms == 0) {
32 return;
33 }
34 for (auto &tracker_report : tracker_reports_) {
35 if (tracker_report.historian.empty()) {
36 LOGW("Empty tracker history found in tracker report");
37 continue;
38 }
39 TrackerHistory &back = tracker_report.historian.back();
40 if (back.state != TrackerState::kPresent) {
41 continue;
42 }
43 if (current_time_ms >=
44 back.last_radio_discovery_time_ms + config.lost_timeout_ms) {
45 back.state = TrackerState::kAbsent;
46 back.lost_time_ms = current_time_ms;
47 }
48 }
49 }
50
UpdateTrackerReport(TrackerReport & tracker_report,const TrackerBatchConfig & config,const chreBleAdvertisingReport & report)51 void TrackerStorage::UpdateTrackerReport(
52 TrackerReport &tracker_report, const TrackerBatchConfig &config,
53 const chreBleAdvertisingReport &report) {
54 LOGD_SENSITIVE_INFO(
55 "Received tracker report, tracker address: %02X:%02X:%02X:%02X:%02X:%02X",
56 tracker_report.header.address[0], tracker_report.header.address[1],
57 tracker_report.header.address[2], tracker_report.header.address[3],
58 tracker_report.header.address[4], tracker_report.header.address[5]);
59 uint32_t current_time_ms = GetCurrentTimeMs();
60 if (tracker_report.historian.empty() ||
61 tracker_report.historian.back().state != TrackerState::kPresent) {
62 // Adds a new history.
63 tracker_report.historian.emplace_back(TrackerHistory(current_time_ms));
64 } else {
65 // Updates the history every sampling interval.
66 if (current_time_ms >= tracker_report.historian.back().last_found_time_ms +
67 config.sample_interval_ms) {
68 tracker_report.historian.back().found_count++;
69 tracker_report.historian.back().last_found_time_ms = current_time_ms;
70 }
71 // Updates the last radio discovery time in the history without sampling.
72 tracker_report.historian.back().last_radio_discovery_time_ms =
73 current_time_ms;
74 }
75 // Updates the advertising data if it is different from the previous one.
76 AddOrUpdateAdvertisingData(tracker_report, report);
77 if (tracker_report.historian.size() > config.max_history_count) {
78 LOGW(
79 "Discarding old tracker history. Tracker history count %zu max history "
80 "count %" PRId32,
81 tracker_report.historian.size(), config.max_history_count);
82 // Discards the oldest history. It is important to keep the order because
83 // the history at the end is always updated.
84 // TODO(b/341757839): Optimize tracker storage memory by refreshing and
85 // merging the tracker reports and histories.
86 tracker_report.historian.erase(0);
87 }
88 }
89
AddTrackerReport(const chreBleAdvertisingReport & report,const TrackerBatchConfig & config)90 void TrackerStorage::AddTrackerReport(const chreBleAdvertisingReport &report,
91 const TrackerBatchConfig &config) {
92 // Doesn't add a new tracker report if the max count has already been
93 // reached. Instead, it reports the storage full event to host when the
94 // notification level has been reached so that it can flush the tracker batch
95 // reports in advance.
96 size_t tracker_count = tracker_reports_.size();
97 if (tracker_count >= config.notify_threshold_tracker_count) {
98 if (callback_ != nullptr) {
99 callback_->OnTrackerStorageFullEvent();
100 }
101 if (tracker_count >= config.max_tracker_count) {
102 LOGW("There are too many trackers. Tracker count %zu max count %" PRId32,
103 tracker_reports_.size(), config.max_tracker_count);
104 return;
105 }
106 }
107 // Creates a new key report and copies header.
108 TrackerReport new_report;
109 // Adds the advertising data to the new tracker report.
110 AddOrUpdateAdvertisingData(new_report, report);
111 // For the new report, add a tracker history.
112 new_report.historian.reserve(kDefaultTrackerHistorySize);
113 new_report.historian.emplace_back(TrackerHistory(GetCurrentTimeMs()));
114 if (!tracker_reports_.push_back(std::move(new_report))) {
115 LOGE("Pushes a new tracker report failed!");
116 }
117 LOGD("Tracker count %zu notify count %" PRId32 " max count %" PRId32,
118 tracker_reports_.size(), config.notify_threshold_tracker_count,
119 config.max_tracker_count);
120 }
121
AddOrUpdateAdvertisingData(TrackerReport & tracker_report,const chreBleAdvertisingReport & report)122 void TrackerStorage::AddOrUpdateAdvertisingData(
123 TrackerReport &tracker_report, const chreBleAdvertisingReport &report) {
124 uint16_t dataLength = report.dataLength;
125 if (dataLength <= 0) {
126 LOGW("Empty advertising data found in advertising report");
127 return;
128 }
129 if (tracker_report.data == nullptr ||
130 tracker_report.header.dataLength != dataLength) {
131 tracker_report.header = report;
132 // Allocates advertise data and copy it as well.
133 chre::UniquePtr<uint8_t[]> data =
134 chre::MakeUniqueArray<uint8_t[]>(dataLength);
135 if (data == nullptr) {
136 LOGE("Memory allocation failed!");
137 return;
138 }
139 memcpy(data.get(), report.data, dataLength);
140 tracker_report.data = std::move(data);
141 tracker_report.header.data = tracker_report.data.get();
142 } else if (tracker_report.header.dataLength == dataLength &&
143 memcmp(tracker_report.data.get(), report.data,
144 tracker_report.header.dataLength) != 0) {
145 tracker_report.header = report;
146 memcpy(tracker_report.data.get(), report.data,
147 tracker_report.header.dataLength);
148 tracker_report.header.data = tracker_report.data.get();
149 }
150 }
151
IsEqualAddress(const TrackerReport & tracker_report,const chreBleAdvertisingReport & report) const152 bool TrackerStorage::IsEqualAddress(
153 const TrackerReport &tracker_report,
154 const chreBleAdvertisingReport &report) const {
155 return (tracker_report.header.addressType == report.addressType &&
156 memcmp(tracker_report.header.address, report.address,
157 CHRE_BLE_ADDRESS_LEN) == 0);
158 }
159
GetCurrentTimeMs() const160 uint32_t TrackerStorage::GetCurrentTimeMs() const {
161 return static_cast<uint32_t>(
162 (chreGetTime() +
163 static_cast<uint64_t>(chreGetEstimatedHostTimeOffset())) /
164 chre::kOneMillisecondInNanoseconds);
165 }
166
167 } // namespace nearby
168