1 #include "location/lbs/contexthub/nanoapps/nearby/filter_extension.h"
2
3 #include <inttypes.h>
4 #include <pb_decode.h>
5 #include <pb_encode.h>
6
7 #include <cstddef>
8 #include <cstdint>
9 #include <utility>
10
11 #include "chre_api/chre.h"
12 #include "location/lbs/contexthub/nanoapps/nearby/nearby_extension.h"
13 #include "location/lbs/contexthub/nanoapps/nearby/proto/nearby_extension.nanopb.h"
14 #include "third_party/contexthub/chre/util/include/chre/util/nanoapp/log.h"
15
16 #define LOG_TAG "[NEARBY][FILTER_EXTENSION]"
17
18 namespace nearby {
19
20 const size_t kChreBleGenericFilterDataSize = 29;
21
22 constexpr nearby_extension_FilterResult kEmptyFilterResult =
23 nearby_extension_FilterResult_init_zero;
24
Update(const chreHostEndpointInfo & host_info,const nearby_extension_ExtConfigRequest_FilterConfig & filter_config,chre::DynamicVector<chreBleGenericFilter> * generic_filters,nearby_extension_ExtConfigResponse * config_response)25 void FilterExtension::Update(
26 const chreHostEndpointInfo &host_info,
27 const nearby_extension_ExtConfigRequest_FilterConfig &filter_config,
28 chre::DynamicVector<chreBleGenericFilter> *generic_filters,
29 nearby_extension_ExtConfigResponse *config_response) {
30 LOGD("Update extension filter");
31 const int32_t host_index = FindOrCreateHostIndex(host_info);
32 if (host_index < 0) {
33 LOGE("Failed to find or create the host.");
34 return;
35 }
36 HostEndpointInfo &host = host_list_[static_cast<size_t>(host_index)];
37 config_response->has_result = true;
38 config_response->has_vendor_status = true;
39
40 // Returns hardware filters.
41 for (int i = 0; i < filter_config.hardware_filter_count; i++) {
42 const nearby_extension_ChreBleGenericFilter &hw_filter =
43 filter_config.hardware_filter[i];
44 chreBleGenericFilter generic_filter;
45 generic_filter.type = hw_filter.type;
46 generic_filter.len = static_cast<uint8_t>(hw_filter.len);
47 memcpy(generic_filter.data, hw_filter.data, kChreBleGenericFilterDataSize);
48 memcpy(generic_filter.dataMask, hw_filter.data_mask,
49 kChreBleGenericFilterDataSize);
50 generic_filters->push_back(generic_filter);
51 }
52 chreBleScanFilter scan_filter;
53 scan_filter.rssiThreshold = CHRE_BLE_RSSI_THRESHOLD_NONE;
54 scan_filter.scanFilterCount = static_cast<uint8_t>(generic_filters->size());
55 scan_filter.scanFilters = generic_filters->data();
56
57 chrexNearbyExtendedFilterConfig config;
58 config.data = filter_config.oem_filter;
59 config.data_length = filter_config.oem_filter_length;
60 host.cache_expire_ms = filter_config.cache_expire_ms;
61
62 config_response->result = static_cast<int32_t>(
63 chrexNearbySetExtendedFilterConfig(&host.host_info, &scan_filter, &config,
64 &config_response->vendor_status));
65 if (config_response->result != CHREX_NEARBY_RESULT_OK) {
66 LOGE("Failed to config filters, result %" PRId32, config_response->result);
67 host_list_.erase(static_cast<size_t>(host_index));
68 return;
69 }
70 // Removes the host if both hardware and oem filters are empty.
71 if (filter_config.hardware_filter_count == 0 &&
72 filter_config.oem_filter_length == 0) {
73 LOGD("Remove host: id (%d), package name (%s)",
74 host.host_info.hostEndpointId,
75 host.host_info.isNameValid ? host.host_info.packageName : "unknown");
76 host_list_.erase(static_cast<size_t>(host_index));
77 }
78 }
79
ConfigureService(const chreHostEndpointInfo & host_info,const nearby_extension_ExtConfigRequest_ServiceConfig & service_config,nearby_extension_ExtConfigResponse * config_response)80 void FilterExtension::ConfigureService(
81 const chreHostEndpointInfo &host_info,
82 const nearby_extension_ExtConfigRequest_ServiceConfig &service_config,
83 nearby_extension_ExtConfigResponse *config_response) {
84 LOGD("Configure extension service");
85 config_response->has_result = true;
86 config_response->has_vendor_status = true;
87
88 chrexNearbyExtendedServiceConfig config;
89 config.data = service_config.data;
90 config.data_length = service_config.data_length;
91
92 config_response->result =
93 static_cast<int32_t>(chrexNearbySetExtendedServiceConfig(
94 &host_info, &config, &config_response->vendor_status));
95 }
96
FindOrCreateHostIndex(const chreHostEndpointInfo & host_info)97 int32_t FilterExtension::FindOrCreateHostIndex(
98 const chreHostEndpointInfo &host_info) {
99 for (size_t index = 0; index < host_list_.size(); index++) {
100 if (host_info.hostEndpointId ==
101 host_list_[index].host_info.hostEndpointId) {
102 return static_cast<int32_t>(index);
103 }
104 }
105 if (!host_list_.push_back(HostEndpointInfo(host_info))) {
106 LOGE("Failed to add new host info.");
107 return -1;
108 }
109 return static_cast<int32_t>(host_list_.size() - 1);
110 }
111
112 /* Adds a FilterExtensionResult (initialized by endpoint_id) to filter_results
113 * if it has not been included in filter_results.
114 * Returns the index of the entry.
115 */
AddToFilterResults(const HostEndpointInfo & host,chre::DynamicVector<FilterExtensionResult> * filter_results)116 size_t AddToFilterResults(
117 const HostEndpointInfo &host,
118 chre::DynamicVector<FilterExtensionResult> *filter_results) {
119 FilterExtensionResult result(host.host_info.hostEndpointId,
120 host.cache_expire_ms);
121 size_t idx = filter_results->find(result);
122 if (filter_results->size() == idx) {
123 filter_results->push_back(std::move(result));
124 }
125 return idx;
126 }
127
Match(const chre::DynamicVector<chreBleAdvertisingReport> & ble_adv_list,chre::DynamicVector<FilterExtensionResult> * filter_results,chre::DynamicVector<FilterExtensionResult> * screen_on_filter_results)128 void FilterExtension::Match(
129 const chre::DynamicVector<chreBleAdvertisingReport> &ble_adv_list,
130 chre::DynamicVector<FilterExtensionResult> *filter_results,
131 chre::DynamicVector<FilterExtensionResult> *screen_on_filter_results) {
132 for (const HostEndpointInfo &host : host_list_) {
133 size_t idx = AddToFilterResults(host, filter_results);
134 size_t screen_on_idx = AddToFilterResults(host, screen_on_filter_results);
135 for (const auto &ble_adv_report : ble_adv_list) {
136 switch (
137 chrexNearbyMatchExtendedFilter(&host.host_info, &ble_adv_report)) {
138 case CHREX_NEARBY_FILTER_ACTION_IGNORE:
139 continue;
140 case CHREX_NEARBY_FILTER_ACTION_DELIVER_ON_WAKE:
141 LOGD("Include BLE report to screen on list.");
142 (*screen_on_filter_results)[screen_on_idx].reports.Push(
143 ble_adv_report);
144 continue;
145 case CHREX_NEARBY_FILTER_ACTION_DELIVER_IMMEDIATELY:
146 LOGD("Include BLE report to immediate delivery list.");
147 (*filter_results)[idx].reports.Push(ble_adv_report);
148 continue;
149 }
150 }
151 }
152 }
153
EncodeConfigResponse(const nearby_extension_ExtConfigResponse & config_response,ByteArray data_buf,size_t * encoded_size)154 bool FilterExtension::EncodeConfigResponse(
155 const nearby_extension_ExtConfigResponse &config_response,
156 ByteArray data_buf, size_t *encoded_size) {
157 if (!pb_get_encoded_size(encoded_size,
158 nearby_extension_ExtConfigResponse_fields,
159 &config_response)) {
160 LOGE("Failed to get extended config response size.");
161 return false;
162 }
163 pb_ostream_t ostream = pb_ostream_from_buffer(data_buf.data, data_buf.length);
164
165 if (!pb_encode(&ostream, nearby_extension_ExtConfigResponse_fields,
166 &config_response)) {
167 LOGE("Unable to encode protobuf for ExtConfigResponse, error %s",
168 PB_GET_ERROR(&ostream));
169 return false;
170 }
171 return true;
172 }
173
Encode(const chre::DynamicVector<chreBleAdvertisingReport> & reports,ByteArray data_buf,size_t * encoded_size)174 bool FilterExtension::Encode(
175 const chre::DynamicVector<chreBleAdvertisingReport> &reports,
176 ByteArray data_buf, size_t *encoded_size) {
177 nearby_extension_FilterResult filter_result = kEmptyFilterResult;
178 size_t idx = 0;
179 for (const auto &report : reports) {
180 nearby_extension_ChreBleAdvertisingReport &report_proto =
181 filter_result.report[idx];
182 report_proto.has_timestamp = true;
183 report_proto.timestamp = report.timestamp;
184 report_proto.has_event_type_and_data_status = true;
185 report_proto.event_type_and_data_status = report.eventTypeAndDataStatus;
186 report_proto.has_address_type = true;
187 report_proto.address_type =
188 static_cast<nearby_extension_ChreBleAdvertisingReport_AddressType>(
189 report.addressType);
190 report_proto.has_address = true;
191 for (size_t i = 0; i < 6; i++) {
192 report_proto.address[i] = report.address[i];
193 }
194 report_proto.has_tx_power = true;
195 report_proto.tx_power = report.txPower;
196 report_proto.has_rssi = true;
197 report_proto.rssi = report.rssi;
198 report_proto.has_data_length = true;
199 report_proto.data_length = report.dataLength;
200 if (report.dataLength > 0) {
201 report_proto.has_data = true;
202 }
203 for (size_t i = 0; i < report.dataLength; i++) {
204 report_proto.data[i] = report.data[i];
205 }
206 idx++;
207 }
208 filter_result.report_count = static_cast<pb_size_t>(idx);
209 filter_result.has_error_code = true;
210 filter_result.error_code = nearby_extension_FilterResult_ErrorCode_SUCCESS;
211
212 if (!pb_get_encoded_size(encoded_size, nearby_extension_FilterResult_fields,
213 &filter_result)) {
214 LOGE("Failed to get filter extension result size.");
215 return false;
216 }
217 pb_ostream_t ostream = pb_ostream_from_buffer(data_buf.data, data_buf.length);
218
219 if (!pb_encode(&ostream, nearby_extension_FilterResult_fields,
220 &filter_result)) {
221 LOGE("Unable to encode protobuf for FilterExtensionResults, error %s",
222 PB_GET_ERROR(&ostream));
223 return false;
224 }
225 return true;
226 }
227
EncodeAdvReport(chreBleAdvertisingReport & report,ByteArray data_buf,size_t * encoded_size)228 bool FilterExtension::EncodeAdvReport(chreBleAdvertisingReport &report,
229 ByteArray data_buf,
230 size_t *encoded_size) {
231 nearby_extension_FilterResult filter_result = kEmptyFilterResult;
232 nearby_extension_ChreBleAdvertisingReport &report_proto =
233 filter_result.report[0];
234 report_proto.has_timestamp = true;
235 report_proto.timestamp =
236 report.timestamp +
237 static_cast<uint64_t>(chreGetEstimatedHostTimeOffset());
238 report_proto.has_event_type_and_data_status = true;
239 report_proto.event_type_and_data_status = report.eventTypeAndDataStatus;
240 report_proto.has_address_type = true;
241 report_proto.address_type =
242 static_cast<nearby_extension_ChreBleAdvertisingReport_AddressType>(
243 report.addressType);
244 report_proto.has_address = true;
245 for (size_t i = 0; i < 6; i++) {
246 report_proto.address[i] = report.address[i];
247 }
248 report_proto.has_tx_power = true;
249 report_proto.tx_power = report.txPower;
250 report_proto.has_rssi = true;
251 report_proto.rssi = report.rssi;
252 report_proto.has_data_length = true;
253 report_proto.data_length = report.dataLength;
254 if (report.dataLength > 0) {
255 report_proto.has_data = true;
256 }
257 for (size_t i = 0; i < report.dataLength; i++) {
258 report_proto.data[i] = report.data[i];
259 }
260 filter_result.report_count = 1;
261 filter_result.has_error_code = true;
262 filter_result.error_code = nearby_extension_FilterResult_ErrorCode_SUCCESS;
263
264 if (!pb_get_encoded_size(encoded_size, nearby_extension_FilterResult_fields,
265 &filter_result)) {
266 LOGE("Failed to get filter extension result size.");
267 return false;
268 }
269 pb_ostream_t ostream = pb_ostream_from_buffer(data_buf.data, data_buf.length);
270
271 if (!pb_encode(&ostream, nearby_extension_FilterResult_fields,
272 &filter_result)) {
273 LOGE("Unable to encode protobuf for FilterExtensionResults, error %s",
274 PB_GET_ERROR(&ostream));
275 return false;
276 }
277 return true;
278 }
279
280 } // namespace nearby
281