diff options
Diffstat (limited to 'gnss/1.0-legacy/AGnss.cpp')
-rw-r--r-- | gnss/1.0-legacy/AGnss.cpp | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/gnss/1.0-legacy/AGnss.cpp b/gnss/1.0-legacy/AGnss.cpp new file mode 100644 index 0000000..29c6ddd --- /dev/null +++ b/gnss/1.0-legacy/AGnss.cpp @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "GnssHAL_AGnssInterface" + +#include "AGnss.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace V1_0 { +namespace implementation { + +std::vector<std::unique_ptr<ThreadFuncArgs>> AGnss::sThreadFuncArgsList; +sp<IAGnssCallback> AGnss::sAGnssCbIface = nullptr; +bool AGnss::sInterfaceExists = false; + +AGpsCallbacks AGnss::sAGnssCb = { + .status_cb = statusCb, + .create_thread_cb = createThreadCb +}; + +AGnss::AGnss(const AGpsInterface* aGpsIface) : mAGnssIface(aGpsIface) { + /* Error out if an instance of the interface already exists. */ + LOG_ALWAYS_FATAL_IF(sInterfaceExists); + sInterfaceExists = true; +} + +AGnss::~AGnss() { + sThreadFuncArgsList.clear(); + sInterfaceExists = false; +} + +void AGnss::statusCb(AGpsStatus* status) { + if (sAGnssCbIface == nullptr) { + ALOGE("%s: AGNSS Callback Interface configured incorrectly", __func__); + return; + } + + if (status == nullptr) { + ALOGE("AGNSS status is invalid"); + return; + } + + /* + * Logic based on AGnssStatus processing by GnssLocationProvider. Size of + * AGpsStatus is checked for backward compatibility since some devices may + * be sending out an older version of AGpsStatus that only supports IPv4. + */ + size_t statusSize = status->size; + if (status->size == sizeof(AGpsStatus)) { + switch (status->addr.ss_family) + { + case AF_INET: + { + /* + * ss_family indicates IPv4. + */ + struct sockaddr_in* in = reinterpret_cast<struct sockaddr_in*>(&(status->addr)); + IAGnssCallback::AGnssStatusIpV4 aGnssStatusIpV4 = { + .type = static_cast<IAGnssCallback::AGnssType>(status->type), + .status = static_cast<IAGnssCallback::AGnssStatusValue>(status->status), + .ipV4Addr = in->sin_addr.s_addr, + }; + + /* + * Callback to client with agnssStatusIpV4Cb. + */ + auto ret = sAGnssCbIface->agnssStatusIpV4Cb(aGnssStatusIpV4); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } + break; + } + case AF_INET6: + { + /* + * ss_family indicates IPv6. Callback to client with agnssStatusIpV6Cb. + */ + IAGnssCallback::AGnssStatusIpV6 aGnssStatusIpV6; + + aGnssStatusIpV6.type = static_cast<IAGnssCallback::AGnssType>(status->type); + aGnssStatusIpV6.status = static_cast<IAGnssCallback::AGnssStatusValue>( + status->status); + + struct sockaddr_in6* in6 = reinterpret_cast<struct sockaddr_in6 *>( + &(status->addr)); + memcpy(&(aGnssStatusIpV6.ipV6Addr[0]), in6->sin6_addr.s6_addr, + aGnssStatusIpV6.ipV6Addr.size()); + auto ret = sAGnssCbIface->agnssStatusIpV6Cb(aGnssStatusIpV6); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } + break; + } + default: + ALOGE("Invalid ss_family found: %d", status->addr.ss_family); + } + } else if (statusSize >= sizeof(AGpsStatus_v2)) { + AGpsStatus_v2* statusV2 = reinterpret_cast<AGpsStatus_v2*>(status); + uint32_t ipV4Addr = statusV2->ipaddr; + IAGnssCallback::AGnssStatusIpV4 aGnssStatusIpV4 = { + .type = static_cast<IAGnssCallback::AGnssType>(AF_INET), + .status = static_cast<IAGnssCallback::AGnssStatusValue>(status->status), + /* + * For older versions of AGpsStatus, change IP addr to net order. This + * was earlier being done in GnssLocationProvider. + */ + .ipV4Addr = htonl(ipV4Addr) + }; + /* + * Callback to client with agnssStatusIpV4Cb. + */ + auto ret = sAGnssCbIface->agnssStatusIpV4Cb(aGnssStatusIpV4); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } + } else { + ALOGE("%s: Invalid size for AGPS Status", __func__); + } +} + +pthread_t AGnss::createThreadCb(const char* name, void (*start)(void*), void* arg) { + return createPthread(name, start, arg, &sThreadFuncArgsList); +} + +/* + * Implementation of methods from ::android::hardware::gnss::V1_0::IAGnss follow. + */ +Return<void> AGnss::setCallback(const sp<IAGnssCallback>& callback) { + if (mAGnssIface == nullptr) { + ALOGE("%s: AGnss interface is unavailable", __func__); + return Void(); + } + + sAGnssCbIface = callback; + + mAGnssIface->init(&sAGnssCb); + return Void(); +} + +Return<bool> AGnss::dataConnClosed() { + if (mAGnssIface == nullptr) { + ALOGE("%s: AGnss interface is unavailable", __func__); + return false; + } + + return (mAGnssIface->data_conn_closed() == 0); +} + +Return<bool> AGnss::dataConnFailed() { + if (mAGnssIface == nullptr) { + ALOGE("%s: AGnss interface is unavailable", __func__); + return false; + } + + return (mAGnssIface->data_conn_failed() == 0); +} + +Return<bool> AGnss::setServer(IAGnssCallback::AGnssType type, + const hidl_string& hostname, + int32_t port) { + if (mAGnssIface == nullptr) { + ALOGE("%s: AGnss interface is unavailable", __func__); + return false; + } + + return (mAGnssIface->set_server(static_cast<AGpsType>(type), hostname.c_str(), port) == 0); +} + +Return<bool> AGnss::dataConnOpen(const hidl_string& apn, IAGnss::ApnIpType apnIpType) { + if (mAGnssIface == nullptr) { + ALOGE("%s: AGnss interface is unavailable", __func__); + return false; + } + + return (mAGnssIface->data_conn_open_with_apn_ip_type(apn.c_str(), + static_cast<uint16_t>(apnIpType)) == 0); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace gnss +} // namespace hardware +} // namespace android |