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,bool set_timeout=true)116 size_t AddToFilterResults(
117 const HostEndpointInfo &host,
118 chre::DynamicVector<FilterExtensionResult> *filter_results,
119 bool set_timeout = true) {
120 FilterExtensionResult result(host.host_info.hostEndpointId,
121 host.cache_expire_ms, set_timeout);
122 size_t idx = filter_results->find(result);
123 if (filter_results->size() == idx) {
124 filter_results->push_back(std::move(result));
125 }
126 return idx;
127 }
128
Match(const chre::DynamicVector<chreBleAdvertisingReport> & ble_adv_list,chre::DynamicVector<FilterExtensionResult> * filter_results,chre::DynamicVector<FilterExtensionResult> * screen_on_filter_results)129 void FilterExtension::Match(
130 const chre::DynamicVector<chreBleAdvertisingReport> &ble_adv_list,
131 chre::DynamicVector<FilterExtensionResult> *filter_results,
132 chre::DynamicVector<FilterExtensionResult> *screen_on_filter_results) {
133 for (const HostEndpointInfo &host : host_list_) {
134 // Get the index of the FilterExtensionResult to deliver immediately.
135 // The FilterExtensionResult is initialized without timeout so that it
136 // won't be expired.
137 size_t immediate_idx =
138 AddToFilterResults(host, filter_results, /*set_timeout=*/false);
139 // Get the index of the FilterExtensionResult to deliver on wake.
140 size_t screen_on_idx = AddToFilterResults(host, screen_on_filter_results);
141 for (const auto &ble_adv_report : ble_adv_list) {
142 switch (
143 chrexNearbyMatchExtendedFilter(&host.host_info, &ble_adv_report)) {
144 case CHREX_NEARBY_FILTER_ACTION_IGNORE:
145 continue;
146 case CHREX_NEARBY_FILTER_ACTION_DELIVER_ON_WAKE:
147 LOGD("Include BLE report to screen on list.");
148 (*screen_on_filter_results)[screen_on_idx].reports.Push(
149 ble_adv_report);
150 continue;
151 case CHREX_NEARBY_FILTER_ACTION_DELIVER_IMMEDIATELY:
152 LOGD("Include BLE report to immediate delivery list.");
153 (*filter_results)[immediate_idx].reports.Push(ble_adv_report);
154 continue;
155 }
156 }
157 }
158 }
159
EncodeConfigResponse(const nearby_extension_ExtConfigResponse & config_response,ByteArray data_buf,size_t * encoded_size)160 bool FilterExtension::EncodeConfigResponse(
161 const nearby_extension_ExtConfigResponse &config_response,
162 ByteArray data_buf, size_t *encoded_size) {
163 if (!pb_get_encoded_size(encoded_size,
164 nearby_extension_ExtConfigResponse_fields,
165 &config_response)) {
166 LOGE("Failed to get extended config response size.");
167 return false;
168 }
169 pb_ostream_t ostream = pb_ostream_from_buffer(data_buf.data, data_buf.length);
170
171 if (!pb_encode(&ostream, nearby_extension_ExtConfigResponse_fields,
172 &config_response)) {
173 LOGE("Unable to encode protobuf for ExtConfigResponse, error %s",
174 PB_GET_ERROR(&ostream));
175 return false;
176 }
177 return true;
178 }
179
EncodeAdvReport(chreBleAdvertisingReport & report,ByteArray data_buf,size_t * encoded_size)180 bool FilterExtension::EncodeAdvReport(chreBleAdvertisingReport &report,
181 ByteArray data_buf,
182 size_t *encoded_size) {
183 nearby_extension_FilterResult filter_result = kEmptyFilterResult;
184 nearby_extension_ChreBleAdvertisingReport &report_proto =
185 filter_result.report[0];
186 report_proto.has_timestamp = true;
187 report_proto.timestamp =
188 report.timestamp +
189 static_cast<uint64_t>(chreGetEstimatedHostTimeOffset());
190 report_proto.has_event_type_and_data_status = true;
191 report_proto.event_type_and_data_status = report.eventTypeAndDataStatus;
192 report_proto.has_address_type = true;
193 report_proto.address_type =
194 static_cast<nearby_extension_ChreBleAdvertisingReport_AddressType>(
195 report.addressType);
196 report_proto.has_address = true;
197 for (size_t i = 0; i < 6; i++) {
198 report_proto.address[i] = report.address[i];
199 }
200 report_proto.has_tx_power = true;
201 report_proto.tx_power = report.txPower;
202 report_proto.has_rssi = true;
203 report_proto.rssi = report.rssi;
204 report_proto.has_data_length = true;
205 report_proto.data_length = report.dataLength;
206 if (report.dataLength > 0) {
207 report_proto.has_data = true;
208 }
209 for (size_t i = 0; i < report.dataLength; i++) {
210 report_proto.data[i] = report.data[i];
211 }
212 filter_result.report_count = 1;
213 filter_result.has_error_code = true;
214 filter_result.error_code = nearby_extension_FilterResult_ErrorCode_SUCCESS;
215
216 if (!pb_get_encoded_size(encoded_size, nearby_extension_FilterResult_fields,
217 &filter_result)) {
218 LOGE("Failed to get filter extension result size.");
219 return false;
220 }
221 pb_ostream_t ostream = pb_ostream_from_buffer(data_buf.data, data_buf.length);
222
223 if (!pb_encode(&ostream, nearby_extension_FilterResult_fields,
224 &filter_result)) {
225 LOGE("Unable to encode protobuf for FilterExtensionResults, error %s",
226 PB_GET_ERROR(&ostream));
227 return false;
228 }
229 return true;
230 }
231
232 } // namespace nearby
233