xref: /aosp_15_r20/system/chre/apps/nearby/location/lbs/contexthub/nanoapps/nearby/tracker_storage.cc (revision 84e339476a462649f82315436d70fd732297a399)
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