1 /*
2 * Copyright (C) 2016 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 <android-base/logging.h>
18
19 #include "hidl_return_util.h"
20 #include "hidl_struct_util.h"
21 #include "wifi_rtt_controller.h"
22 #include "wifi_status_util.h"
23
24 namespace android {
25 namespace hardware {
26 namespace wifi {
27 namespace V1_6 {
28 namespace implementation {
29 using hidl_return_util::validateAndCall;
30
WifiRttController(const std::string & iface_name,const sp<IWifiIface> & bound_iface,const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)31 WifiRttController::WifiRttController(const std::string& iface_name,
32 const sp<IWifiIface>& bound_iface,
33 const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
34 : ifname_(iface_name), bound_iface_(bound_iface), legacy_hal_(legacy_hal), is_valid_(true) {}
35
invalidate()36 void WifiRttController::invalidate() {
37 legacy_hal_.reset();
38 event_callbacks_.clear();
39 is_valid_ = false;
40 }
41
isValid()42 bool WifiRttController::isValid() {
43 return is_valid_;
44 }
45
getEventCallbacks()46 std::vector<sp<V1_6::IWifiRttControllerEventCallback>> WifiRttController::getEventCallbacks() {
47 return event_callbacks_;
48 }
49
getIfaceName()50 std::string WifiRttController::getIfaceName() {
51 return ifname_;
52 }
53
getBoundIface(getBoundIface_cb hidl_status_cb)54 Return<void> WifiRttController::getBoundIface(getBoundIface_cb hidl_status_cb) {
55 return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
56 &WifiRttController::getBoundIfaceInternal, hidl_status_cb);
57 }
58
registerEventCallback(const sp<V1_0::IWifiRttControllerEventCallback> & callback,registerEventCallback_cb hidl_status_cb)59 Return<void> WifiRttController::registerEventCallback(
60 const sp<V1_0::IWifiRttControllerEventCallback>& callback,
61 registerEventCallback_cb hidl_status_cb) {
62 return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
63 &WifiRttController::registerEventCallbackInternal, hidl_status_cb,
64 callback);
65 }
66
rangeRequest(uint32_t cmd_id,const hidl_vec<V1_0::RttConfig> & rtt_configs,rangeRequest_cb hidl_status_cb)67 Return<void> WifiRttController::rangeRequest(uint32_t cmd_id,
68 const hidl_vec<V1_0::RttConfig>& rtt_configs,
69 rangeRequest_cb hidl_status_cb) {
70 return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
71 &WifiRttController::rangeRequestInternal, hidl_status_cb, cmd_id,
72 rtt_configs);
73 }
74
rangeCancel(uint32_t cmd_id,const hidl_vec<hidl_array<uint8_t,6>> & addrs,rangeCancel_cb hidl_status_cb)75 Return<void> WifiRttController::rangeCancel(uint32_t cmd_id,
76 const hidl_vec<hidl_array<uint8_t, 6>>& addrs,
77 rangeCancel_cb hidl_status_cb) {
78 return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
79 &WifiRttController::rangeCancelInternal, hidl_status_cb, cmd_id, addrs);
80 }
81
getCapabilities(getCapabilities_cb hidl_status_cb)82 Return<void> WifiRttController::getCapabilities(getCapabilities_cb hidl_status_cb) {
83 return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
84 &WifiRttController::getCapabilitiesInternal, hidl_status_cb);
85 }
86
setLci(uint32_t cmd_id,const RttLciInformation & lci,setLci_cb hidl_status_cb)87 Return<void> WifiRttController::setLci(uint32_t cmd_id, const RttLciInformation& lci,
88 setLci_cb hidl_status_cb) {
89 return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
90 &WifiRttController::setLciInternal, hidl_status_cb, cmd_id, lci);
91 }
92
setLcr(uint32_t cmd_id,const RttLcrInformation & lcr,setLcr_cb hidl_status_cb)93 Return<void> WifiRttController::setLcr(uint32_t cmd_id, const RttLcrInformation& lcr,
94 setLcr_cb hidl_status_cb) {
95 return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
96 &WifiRttController::setLcrInternal, hidl_status_cb, cmd_id, lcr);
97 }
98
getResponderInfo(getResponderInfo_cb hidl_status_cb)99 Return<void> WifiRttController::getResponderInfo(getResponderInfo_cb hidl_status_cb) {
100 return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
101 &WifiRttController::getResponderInfoInternal, hidl_status_cb);
102 }
103
enableResponder(uint32_t cmd_id,const V1_0::WifiChannelInfo & channel_hint,uint32_t max_duration_seconds,const V1_0::RttResponder & info,enableResponder_cb hidl_status_cb)104 Return<void> WifiRttController::enableResponder(uint32_t cmd_id,
105 const V1_0::WifiChannelInfo& channel_hint,
106 uint32_t max_duration_seconds,
107 const V1_0::RttResponder& info,
108 enableResponder_cb hidl_status_cb) {
109 return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
110 &WifiRttController::enableResponderInternal, hidl_status_cb, cmd_id,
111 channel_hint, max_duration_seconds, info);
112 }
113
disableResponder(uint32_t cmd_id,disableResponder_cb hidl_status_cb)114 Return<void> WifiRttController::disableResponder(uint32_t cmd_id,
115 disableResponder_cb hidl_status_cb) {
116 return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
117 &WifiRttController::disableResponderInternal, hidl_status_cb, cmd_id);
118 }
119
registerEventCallback_1_4(const sp<V1_4::IWifiRttControllerEventCallback> & callback,registerEventCallback_1_4_cb hidl_status_cb)120 Return<void> WifiRttController::registerEventCallback_1_4(
121 const sp<V1_4::IWifiRttControllerEventCallback>& callback,
122 registerEventCallback_1_4_cb hidl_status_cb) {
123 return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
124 &WifiRttController::registerEventCallbackInternal_1_4, hidl_status_cb,
125 callback);
126 }
127
rangeRequest_1_4(uint32_t cmd_id,const hidl_vec<V1_4::RttConfig> & rtt_configs,rangeRequest_1_4_cb hidl_status_cb)128 Return<void> WifiRttController::rangeRequest_1_4(uint32_t cmd_id,
129 const hidl_vec<V1_4::RttConfig>& rtt_configs,
130 rangeRequest_1_4_cb hidl_status_cb) {
131 return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
132 &WifiRttController::rangeRequestInternal_1_4, hidl_status_cb, cmd_id,
133 rtt_configs);
134 }
135
getCapabilities_1_4(getCapabilities_1_4_cb hidl_status_cb)136 Return<void> WifiRttController::getCapabilities_1_4(getCapabilities_1_4_cb hidl_status_cb) {
137 return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
138 &WifiRttController::getCapabilitiesInternal_1_4, hidl_status_cb);
139 }
140
getResponderInfo_1_4(getResponderInfo_1_4_cb hidl_status_cb)141 Return<void> WifiRttController::getResponderInfo_1_4(getResponderInfo_1_4_cb hidl_status_cb) {
142 return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
143 &WifiRttController::getResponderInfoInternal_1_4, hidl_status_cb);
144 }
145
enableResponder_1_4(uint32_t cmd_id,const V1_0::WifiChannelInfo & channel_hint,uint32_t max_duration_seconds,const V1_4::RttResponder & info,enableResponder_1_4_cb hidl_status_cb)146 Return<void> WifiRttController::enableResponder_1_4(uint32_t cmd_id,
147 const V1_0::WifiChannelInfo& channel_hint,
148 uint32_t max_duration_seconds,
149 const V1_4::RttResponder& info,
150 enableResponder_1_4_cb hidl_status_cb) {
151 return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
152 &WifiRttController::enableResponderInternal_1_4, hidl_status_cb, cmd_id,
153 channel_hint, max_duration_seconds, info);
154 }
155
registerEventCallback_1_6(const sp<V1_6::IWifiRttControllerEventCallback> & callback,registerEventCallback_1_6_cb hidl_status_cb)156 Return<void> WifiRttController::registerEventCallback_1_6(
157 const sp<V1_6::IWifiRttControllerEventCallback>& callback,
158 registerEventCallback_1_6_cb hidl_status_cb) {
159 return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
160 &WifiRttController::registerEventCallbackInternal_1_6, hidl_status_cb,
161 callback);
162 }
163
rangeRequest_1_6(uint32_t cmd_id,const hidl_vec<V1_6::RttConfig> & rtt_configs,rangeRequest_1_6_cb hidl_status_cb)164 Return<void> WifiRttController::rangeRequest_1_6(uint32_t cmd_id,
165 const hidl_vec<V1_6::RttConfig>& rtt_configs,
166 rangeRequest_1_6_cb hidl_status_cb) {
167 return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
168 &WifiRttController::rangeRequestInternal_1_6, hidl_status_cb, cmd_id,
169 rtt_configs);
170 }
171
getCapabilities_1_6(getCapabilities_1_6_cb hidl_status_cb)172 Return<void> WifiRttController::getCapabilities_1_6(getCapabilities_1_6_cb hidl_status_cb) {
173 return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
174 &WifiRttController::getCapabilitiesInternal_1_6, hidl_status_cb);
175 }
176
getResponderInfo_1_6(getResponderInfo_1_6_cb hidl_status_cb)177 Return<void> WifiRttController::getResponderInfo_1_6(getResponderInfo_1_6_cb hidl_status_cb) {
178 return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
179 &WifiRttController::getResponderInfoInternal_1_6, hidl_status_cb);
180 }
181
enableResponder_1_6(uint32_t cmd_id,const V1_6::WifiChannelInfo & channel_hint,uint32_t max_duration_seconds,const V1_6::RttResponder & info,enableResponder_1_6_cb hidl_status_cb)182 Return<void> WifiRttController::enableResponder_1_6(uint32_t cmd_id,
183 const V1_6::WifiChannelInfo& channel_hint,
184 uint32_t max_duration_seconds,
185 const V1_6::RttResponder& info,
186 enableResponder_1_6_cb hidl_status_cb) {
187 return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
188 &WifiRttController::enableResponderInternal_1_6, hidl_status_cb, cmd_id,
189 channel_hint, max_duration_seconds, info);
190 }
191
getBoundIfaceInternal()192 std::pair<WifiStatus, sp<IWifiIface>> WifiRttController::getBoundIfaceInternal() {
193 return {createWifiStatus(WifiStatusCode::SUCCESS), bound_iface_};
194 }
195
registerEventCallbackInternal(const sp<V1_0::IWifiRttControllerEventCallback> &)196 WifiStatus WifiRttController::registerEventCallbackInternal(
197 const sp<V1_0::IWifiRttControllerEventCallback>& /* callback */) {
198 // Deprecated support for this api
199 return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
200 }
201
rangeRequestInternal(uint32_t,const std::vector<V1_0::RttConfig> &)202 WifiStatus WifiRttController::rangeRequestInternal(
203 uint32_t /* cmd_id */, const std::vector<V1_0::RttConfig>& /* rtt_configs */) {
204 // Deprecated support for this api
205 return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
206 }
207
rangeCancelInternal(uint32_t cmd_id,const std::vector<hidl_array<uint8_t,6>> & addrs)208 WifiStatus WifiRttController::rangeCancelInternal(
209 uint32_t cmd_id, const std::vector<hidl_array<uint8_t, 6>>& addrs) {
210 std::vector<std::array<uint8_t, 6>> legacy_addrs;
211 for (const auto& addr : addrs) {
212 legacy_addrs.push_back(addr);
213 }
214 legacy_hal::wifi_error legacy_status =
215 legacy_hal_.lock()->cancelRttRangeRequest(ifname_, cmd_id, legacy_addrs);
216 return createWifiStatusFromLegacyError(legacy_status);
217 }
218
getCapabilitiesInternal()219 std::pair<WifiStatus, V1_0::RttCapabilities> WifiRttController::getCapabilitiesInternal() {
220 // Deprecated support for this api
221 return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
222 }
223
setLciInternal(uint32_t cmd_id,const RttLciInformation & lci)224 WifiStatus WifiRttController::setLciInternal(uint32_t cmd_id, const RttLciInformation& lci) {
225 legacy_hal::wifi_lci_information legacy_lci;
226 if (!hidl_struct_util::convertHidlRttLciInformationToLegacy(lci, &legacy_lci)) {
227 return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
228 }
229 legacy_hal::wifi_error legacy_status =
230 legacy_hal_.lock()->setRttLci(ifname_, cmd_id, legacy_lci);
231 return createWifiStatusFromLegacyError(legacy_status);
232 }
233
setLcrInternal(uint32_t cmd_id,const RttLcrInformation & lcr)234 WifiStatus WifiRttController::setLcrInternal(uint32_t cmd_id, const RttLcrInformation& lcr) {
235 legacy_hal::wifi_lcr_information legacy_lcr;
236 if (!hidl_struct_util::convertHidlRttLcrInformationToLegacy(lcr, &legacy_lcr)) {
237 return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
238 }
239 legacy_hal::wifi_error legacy_status =
240 legacy_hal_.lock()->setRttLcr(ifname_, cmd_id, legacy_lcr);
241 return createWifiStatusFromLegacyError(legacy_status);
242 }
243
getResponderInfoInternal()244 std::pair<WifiStatus, V1_0::RttResponder> WifiRttController::getResponderInfoInternal() {
245 // Deprecated support for this api
246 return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
247 }
248
enableResponderInternal(uint32_t,const V1_0::WifiChannelInfo &,uint32_t,const V1_0::RttResponder &)249 WifiStatus WifiRttController::enableResponderInternal(
250 uint32_t /* cmd_id */, const V1_0::WifiChannelInfo& /* channel_hint */,
251 uint32_t /* max_duration_seconds */, const V1_0::RttResponder& /* info */) {
252 // Deprecated support for this api
253 return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED)};
254 }
255
disableResponderInternal(uint32_t cmd_id)256 WifiStatus WifiRttController::disableResponderInternal(uint32_t cmd_id) {
257 legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->disableRttResponder(ifname_, cmd_id);
258 return createWifiStatusFromLegacyError(legacy_status);
259 }
260
registerEventCallbackInternal_1_4(const sp<V1_4::IWifiRttControllerEventCallback> &)261 WifiStatus WifiRttController::registerEventCallbackInternal_1_4(
262 const sp<V1_4::IWifiRttControllerEventCallback>& /* callback */) {
263 // Deprecated support for this api
264 return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
265 }
266
rangeRequestInternal_1_4(uint32_t,const std::vector<V1_4::RttConfig> &)267 WifiStatus WifiRttController::rangeRequestInternal_1_4(
268 uint32_t /* cmd_id */, const std::vector<V1_4::RttConfig>& /* rtt_configs */) {
269 // Deprecated support for this api
270 return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
271 }
272
getCapabilitiesInternal_1_4()273 std::pair<WifiStatus, V1_4::RttCapabilities> WifiRttController::getCapabilitiesInternal_1_4() {
274 // Deprecated support for this api
275 return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
276 }
277
getResponderInfoInternal_1_4()278 std::pair<WifiStatus, V1_4::RttResponder> WifiRttController::getResponderInfoInternal_1_4() {
279 // Deprecated support for this api
280 return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
281 }
282
enableResponderInternal_1_4(uint32_t,const V1_0::WifiChannelInfo &,uint32_t,const V1_4::RttResponder &)283 WifiStatus WifiRttController::enableResponderInternal_1_4(
284 uint32_t /* cmd_id */, const V1_0::WifiChannelInfo& /* channel_hint */,
285 uint32_t /* max_duration_seconds */, const V1_4::RttResponder& /* info */) {
286 // Deprecated support for this api
287 return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED)};
288 }
289
registerEventCallbackInternal_1_6(const sp<V1_6::IWifiRttControllerEventCallback> & callback)290 WifiStatus WifiRttController::registerEventCallbackInternal_1_6(
291 const sp<V1_6::IWifiRttControllerEventCallback>& callback) {
292 // TODO(b/31632518): remove the callback when the client is destroyed
293 event_callbacks_.emplace_back(callback);
294 return createWifiStatus(WifiStatusCode::SUCCESS);
295 }
296
rangeRequestInternal_1_6(uint32_t cmd_id,const std::vector<V1_6::RttConfig> & rtt_configs)297 WifiStatus WifiRttController::rangeRequestInternal_1_6(
298 uint32_t cmd_id, const std::vector<V1_6::RttConfig>& rtt_configs) {
299 std::vector<legacy_hal::wifi_rtt_config> legacy_configs;
300 if (!hidl_struct_util::convertHidlVectorOfRttConfigToLegacy(rtt_configs, &legacy_configs)) {
301 return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
302 }
303 android::wp<WifiRttController> weak_ptr_this(this);
304 const auto& on_results_callback =
305 [weak_ptr_this](legacy_hal::wifi_request_id id,
306 const std::vector<const legacy_hal::wifi_rtt_result*>& results) {
307 const auto shared_ptr_this = weak_ptr_this.promote();
308 if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
309 LOG(ERROR) << "Callback invoked on an invalid object";
310 return;
311 }
312 std::vector<V1_6::RttResult> hidl_results;
313 if (!hidl_struct_util::convertLegacyVectorOfRttResultToHidl(results,
314 &hidl_results)) {
315 LOG(ERROR) << "Failed to convert rtt results to HIDL structs";
316 return;
317 }
318 for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
319 if (!callback->onResults_1_6(id, hidl_results).isOk()) {
320 LOG(ERROR) << "Failed to invoke the callback";
321 }
322 }
323 };
324 legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startRttRangeRequest(
325 ifname_, cmd_id, legacy_configs, on_results_callback);
326 return createWifiStatusFromLegacyError(legacy_status);
327 }
328
getCapabilitiesInternal_1_6()329 std::pair<WifiStatus, V1_6::RttCapabilities> WifiRttController::getCapabilitiesInternal_1_6() {
330 legacy_hal::wifi_error legacy_status;
331 legacy_hal::wifi_rtt_capabilities legacy_caps;
332 std::tie(legacy_status, legacy_caps) = legacy_hal_.lock()->getRttCapabilities(ifname_);
333 if (legacy_status != legacy_hal::WIFI_SUCCESS) {
334 return {createWifiStatusFromLegacyError(legacy_status), {}};
335 }
336 V1_6::RttCapabilities hidl_caps;
337 if (!hidl_struct_util::convertLegacyRttCapabilitiesToHidl(legacy_caps, &hidl_caps)) {
338 return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
339 }
340 return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
341 }
342
getResponderInfoInternal_1_6()343 std::pair<WifiStatus, V1_6::RttResponder> WifiRttController::getResponderInfoInternal_1_6() {
344 legacy_hal::wifi_error legacy_status;
345 legacy_hal::wifi_rtt_responder legacy_responder;
346 std::tie(legacy_status, legacy_responder) = legacy_hal_.lock()->getRttResponderInfo(ifname_);
347 if (legacy_status != legacy_hal::WIFI_SUCCESS) {
348 return {createWifiStatusFromLegacyError(legacy_status), {}};
349 }
350 V1_6::RttResponder hidl_responder;
351 if (!hidl_struct_util::convertLegacyRttResponderToHidl(legacy_responder, &hidl_responder)) {
352 return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
353 }
354 return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_responder};
355 }
356
enableResponderInternal_1_6(uint32_t cmd_id,const V1_6::WifiChannelInfo & channel_hint,uint32_t max_duration_seconds,const V1_6::RttResponder & info)357 WifiStatus WifiRttController::enableResponderInternal_1_6(uint32_t cmd_id,
358 const V1_6::WifiChannelInfo& channel_hint,
359 uint32_t max_duration_seconds,
360 const V1_6::RttResponder& info) {
361 legacy_hal::wifi_channel_info legacy_channel_info;
362 if (!hidl_struct_util::convertHidlWifiChannelInfoToLegacy(channel_hint, &legacy_channel_info)) {
363 return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
364 }
365 legacy_hal::wifi_rtt_responder legacy_responder;
366 if (!hidl_struct_util::convertHidlRttResponderToLegacy(info, &legacy_responder)) {
367 return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
368 }
369 legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->enableRttResponder(
370 ifname_, cmd_id, legacy_channel_info, max_duration_seconds, legacy_responder);
371 return createWifiStatusFromLegacyError(legacy_status);
372 }
373 } // namespace implementation
374 } // namespace V1_6
375 } // namespace wifi
376 } // namespace hardware
377 } // namespace android
378