/* * 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