From cb8474d7b6693f2d8f5194fd25df30394f1e2c91 Mon Sep 17 00:00:00 2001 From: Yuchen He Date: Thu, 10 Jun 2021 17:10:15 -0700 Subject: [PATCH 1/2] Refactor and reuse some read device file logic Add skeleton on HAL for Gnss raw measurement injection Bug: 190757198 Test: manual test Merged-In: I9b58043d5ed321aa71ff4f23031df251ae89c407 Change-Id: I9b58043d5ed321aa71ff4f23031df251ae89c407 --- .../aidl/default/GnssMeasurementInterface.cpp | 21 ++++- gnss/common/utils/default/Android.bp | 1 + gnss/common/utils/default/GnssReplayUtils.cpp | 88 +++++++++++++++++++ gnss/common/utils/default/include/Constants.h | 12 +++ .../utils/default/include/GnssReplayUtils.h | 54 ++++++++++++ .../utils/default/include/NmeaFixInfo.h | 7 -- .../utils/default/include/v2_1/GnssTemplate.h | 42 ++------- 7 files changed, 178 insertions(+), 47 deletions(-) create mode 100644 gnss/common/utils/default/GnssReplayUtils.cpp create mode 100644 gnss/common/utils/default/include/GnssReplayUtils.h diff --git a/gnss/aidl/default/GnssMeasurementInterface.cpp b/gnss/aidl/default/GnssMeasurementInterface.cpp index fcc1f986cc..0e489c59e4 100644 --- a/gnss/aidl/default/GnssMeasurementInterface.cpp +++ b/gnss/aidl/default/GnssMeasurementInterface.cpp @@ -19,11 +19,13 @@ #include "GnssMeasurementInterface.h" #include #include +#include "GnssReplayUtils.h" #include "Utils.h" namespace aidl::android::hardware::gnss { using Utils = ::android::hardware::gnss::common::Utils; +using ReplayUtils = ::android::hardware::gnss::common::ReplayUtils; std::shared_ptr GnssMeasurementInterface::sCallback = nullptr; @@ -63,9 +65,22 @@ void GnssMeasurementInterface::start(const bool enableCorrVecOutputs) { mIsActive = true; mThread = std::thread([this, enableCorrVecOutputs]() { while (mIsActive == true) { - auto measurement = Utils::getMockMeasurement(enableCorrVecOutputs); - this->reportMeasurement(measurement); - + std::string rawMeasurementStr = ""; + if (ReplayUtils::hasGnssDeviceFile() && + ReplayUtils::isGnssRawMeasurement( + rawMeasurementStr = ReplayUtils::getDataFromDeviceFile( + std::string( + ::android::hardware::gnss::common::CMD_GET_RAWMEASUREMENT), + mMinIntervalMillis))) { + // TODO: implement rawMeasurementStr parser and report measurement. + ALOGD("rawMeasurementStr(size: %zu) from device file: %s", rawMeasurementStr.size(), + rawMeasurementStr.c_str()); + auto measurement = Utils::getMockMeasurement(enableCorrVecOutputs); + this->reportMeasurement(measurement); + } else { + auto measurement = Utils::getMockMeasurement(enableCorrVecOutputs); + this->reportMeasurement(measurement); + } std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis)); } }); diff --git a/gnss/common/utils/default/Android.bp b/gnss/common/utils/default/Android.bp index 43db8739d1..f9225c24d0 100644 --- a/gnss/common/utils/default/Android.bp +++ b/gnss/common/utils/default/Android.bp @@ -41,6 +41,7 @@ cc_library_static { "MockLocation.cpp", "Utils.cpp", "NmeaFixInfo.cpp", + "GnssReplayUtils.cpp", ], export_include_dirs: ["include"], shared_libs: [ diff --git a/gnss/common/utils/default/GnssReplayUtils.cpp b/gnss/common/utils/default/GnssReplayUtils.cpp new file mode 100644 index 0000000000..6dcf6ea252 --- /dev/null +++ b/gnss/common/utils/default/GnssReplayUtils.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2021 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. + */ + +#include "GnssReplayUtils.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +const char* ReplayUtils::getGnssPath() { + const char* gnss_dev_path = GNSS_PATH; + char devname_value[PROPERTY_VALUE_MAX] = ""; + if (property_get("debug.location.gnss.devname", devname_value, NULL) > 0) { + gnss_dev_path = devname_value; + } + return gnss_dev_path; +} + +bool ReplayUtils::hasGnssDeviceFile() { + struct stat sb; + return stat(getGnssPath(), &sb) != -1; +} + +bool ReplayUtils::isGnssRawMeasurement(const std::string& inputStr) { + // TODO: add more logic check to by pass invalid data. + return !inputStr.empty() && (inputStr.find("Raw") != std::string::npos); +} + +bool ReplayUtils::isNMEA(const std::string& inputStr) { + return !inputStr.empty() && + (inputStr.rfind("$GPRMC,", 0) == 0 || inputStr.rfind("$GPRMA,", 0) == 0); +} + +std::string ReplayUtils::getDataFromDeviceFile(const std::string& command, int mMinIntervalMs) { + char inputBuffer[INPUT_BUFFER_SIZE]; + int mGnssFd = open(getGnssPath(), O_RDWR | O_NONBLOCK); + + if (mGnssFd == -1) { + return ""; + } + + int bytes_write = write(mGnssFd, command.c_str(), command.size()); + if (bytes_write <= 0) { + return ""; + } + + struct epoll_event ev, events[1]; + ev.data.fd = mGnssFd; + ev.events = EPOLLIN; + int epoll_fd = epoll_create1(0); + epoll_ctl(epoll_fd, EPOLL_CTL_ADD, mGnssFd, &ev); + int bytes_read = -1; + std::string inputStr = ""; + int epoll_ret = epoll_wait(epoll_fd, events, 1, mMinIntervalMs); + + if (epoll_ret == -1) { + return ""; + } + while (true) { + memset(inputBuffer, 0, INPUT_BUFFER_SIZE); + bytes_read = read(mGnssFd, &inputBuffer, INPUT_BUFFER_SIZE); + if (bytes_read <= 0) { + break; + } + inputStr += std::string(inputBuffer, bytes_read); + } + + return inputStr; +} + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/common/utils/default/include/Constants.h b/gnss/common/utils/default/include/Constants.h index 22afee1ad1..f205ba603c 100644 --- a/gnss/common/utils/default/include/Constants.h +++ b/gnss/common/utils/default/include/Constants.h @@ -34,6 +34,18 @@ const float kGpsL5FreqHz = 1176.45 * 1e6; const float kGloG1FreqHz = 1602.0 * 1e6; const float kIrnssL5FreqHz = 1176.45 * 1e6; +// Location replay constants +constexpr char GNSS_PATH[] = "/dev/gnss0"; +constexpr int INPUT_BUFFER_SIZE = 256; +constexpr char CMD_GET_LOCATION[] = "CMD_GET_LOCATION"; +constexpr char CMD_GET_RAWMEASUREMENT[] = "CMD_GET_RAWMEASUREMENT"; +constexpr char LINE_SEPARATOR = '\n'; +constexpr char COMMA_SEPARATOR = ','; +constexpr char GPGA_RECORD_TAG[] = "$GPGGA"; +constexpr char GPRMC_RECORD_TAG[] = "$GPRMC"; +constexpr double TIMESTAMP_EPSILON = 0.001; +constexpr int MIN_COL_NUM = 13; + } // namespace common } // namespace gnss } // namespace hardware diff --git a/gnss/common/utils/default/include/GnssReplayUtils.h b/gnss/common/utils/default/include/GnssReplayUtils.h new file mode 100644 index 0000000000..d7530f741a --- /dev/null +++ b/gnss/common/utils/default/include/GnssReplayUtils.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2021 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. + */ + +#ifndef android_hardware_gnss_common_GnssReplayUtils_H_ +#define android_hardware_gnss_common_GnssReplayUtils_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Constants.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +struct ReplayUtils { + static const char* getGnssPath(); + + static std::string getDataFromDeviceFile(const std::string& command, int mMinIntervalMs); + + static bool hasGnssDeviceFile(); + + static bool isGnssRawMeasurement(const std::string& inputStr); + + static bool isNMEA(const std::string& inputStr); +}; + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_common_GnssReplayUtils_H_ diff --git a/gnss/common/utils/default/include/NmeaFixInfo.h b/gnss/common/utils/default/include/NmeaFixInfo.h index c96eecea00..5c27045316 100644 --- a/gnss/common/utils/default/include/NmeaFixInfo.h +++ b/gnss/common/utils/default/include/NmeaFixInfo.h @@ -27,13 +27,6 @@ namespace hardware { namespace gnss { namespace common { -constexpr char GPGA_RECORD_TAG[] = "$GPGGA"; -constexpr char GPRMC_RECORD_TAG[] = "$GPRMC"; -constexpr char LINE_SEPARATOR = '\n'; -constexpr char COMMA_SEPARATOR = ','; -constexpr double TIMESTAMP_EPSILON = 0.001; -constexpr int MIN_COL_NUM = 13; - /** Helper class to parse and store the GNSS fix details information. */ class NmeaFixInfo { private: diff --git a/gnss/common/utils/default/include/v2_1/GnssTemplate.h b/gnss/common/utils/default/include/v2_1/GnssTemplate.h index 131af24fbe..66c23d4719 100644 --- a/gnss/common/utils/default/include/v2_1/GnssTemplate.h +++ b/gnss/common/utils/default/include/v2_1/GnssTemplate.h @@ -35,6 +35,7 @@ #include "GnssDebug.h" #include "GnssMeasurement.h" #include "GnssMeasurementCorrections.h" +#include "GnssReplayUtils.h" #include "MockLocation.h" #include "NmeaFixInfo.h" #include "Utils.h" @@ -159,15 +160,9 @@ GnssTemplate::~GnssTemplate() { template std::unique_ptr GnssTemplate::getLocationFromHW() { - char inputBuffer[INPUT_BUFFER_SIZE]; if (!mHardwareModeChecked) { - // default using gnss0 - const char * gnss_dev_path = GNSS_PATH; - char devname_value[PROPERTY_VALUE_MAX] = ""; - if (property_get("debug.location.gnss.devname", devname_value, NULL) > 0) { - gnss_dev_path = devname_value; - ALOGD("using %s instead of the default %s", gnss_dev_path, GNSS_PATH); - } + // default using /dev/gnss0 + const char* gnss_dev_path = ReplayUtils::getGnssPath(); mGnssFd = open(gnss_dev_path, O_RDWR | O_NONBLOCK); if (mGnssFd == -1) { @@ -176,35 +171,8 @@ std::unique_ptr GnssTemplate::getLocationFromHW() { mHardwareModeChecked = true; } - if (mGnssFd == -1) { - return nullptr; - } - - int bytes_write = write(mGnssFd, CMD_GET_LOCATION, strlen(CMD_GET_LOCATION)); - if (bytes_write <= 0) { - return nullptr; - } - - struct epoll_event ev, events[1]; - ev.data.fd = mGnssFd; - ev.events = EPOLLIN; - int epoll_fd = epoll_create1(0); - epoll_ctl(epoll_fd, EPOLL_CTL_ADD, mGnssFd, &ev); - int bytes_read = -1; - std::string inputStr = ""; - int epoll_ret = epoll_wait(epoll_fd, events, 1, mMinIntervalMs); - - if (epoll_ret == -1) { - return nullptr; - } - while (true) { - memset(inputBuffer, 0, INPUT_BUFFER_SIZE); - bytes_read = read(mGnssFd, &inputBuffer, INPUT_BUFFER_SIZE); - if (bytes_read <= 0) { - break; - } - inputStr += std::string(inputBuffer, bytes_read); - } + std::string inputStr = ::android::hardware::gnss::common::ReplayUtils::getDataFromDeviceFile( + CMD_GET_LOCATION, mMinIntervalMs); return NmeaFixInfo::getLocationFromInputStr(inputStr); } From 3f467bd10f520cc9d939098b5bf13058e4cdbaaa Mon Sep 17 00:00:00 2001 From: George Burgess IV Date: Wed, 7 Jul 2021 09:59:32 -0700 Subject: [PATCH 2/2] fix potential use-after-frees of stack memory `devname_value` is a local variable; if `property_get` succeeds, we'll return a pointer to it. Returning a `std::string` instead sidesteps this problem. Bug: 190757198 Test: TreeHugger Change-Id: If9ca733dd21128706f2a9f62e8460b1286631aa5 Merged-In: If9ca733dd21128706f2a9f62e8460b1286631aa5 --- gnss/common/utils/default/GnssReplayUtils.cpp | 11 +++++------ gnss/common/utils/default/include/GnssReplayUtils.h | 2 +- gnss/common/utils/default/include/v2_1/GnssTemplate.h | 6 +++--- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/gnss/common/utils/default/GnssReplayUtils.cpp b/gnss/common/utils/default/GnssReplayUtils.cpp index 6dcf6ea252..fc4c477ae8 100644 --- a/gnss/common/utils/default/GnssReplayUtils.cpp +++ b/gnss/common/utils/default/GnssReplayUtils.cpp @@ -21,18 +21,17 @@ namespace hardware { namespace gnss { namespace common { -const char* ReplayUtils::getGnssPath() { - const char* gnss_dev_path = GNSS_PATH; +std::string ReplayUtils::getGnssPath() { char devname_value[PROPERTY_VALUE_MAX] = ""; if (property_get("debug.location.gnss.devname", devname_value, NULL) > 0) { - gnss_dev_path = devname_value; + return devname_value; } - return gnss_dev_path; + return GNSS_PATH; } bool ReplayUtils::hasGnssDeviceFile() { struct stat sb; - return stat(getGnssPath(), &sb) != -1; + return stat(getGnssPath().c_str(), &sb) != -1; } bool ReplayUtils::isGnssRawMeasurement(const std::string& inputStr) { @@ -47,7 +46,7 @@ bool ReplayUtils::isNMEA(const std::string& inputStr) { std::string ReplayUtils::getDataFromDeviceFile(const std::string& command, int mMinIntervalMs) { char inputBuffer[INPUT_BUFFER_SIZE]; - int mGnssFd = open(getGnssPath(), O_RDWR | O_NONBLOCK); + int mGnssFd = open(getGnssPath().c_str(), O_RDWR | O_NONBLOCK); if (mGnssFd == -1) { return ""; diff --git a/gnss/common/utils/default/include/GnssReplayUtils.h b/gnss/common/utils/default/include/GnssReplayUtils.h index d7530f741a..32c0e58c0c 100644 --- a/gnss/common/utils/default/include/GnssReplayUtils.h +++ b/gnss/common/utils/default/include/GnssReplayUtils.h @@ -35,7 +35,7 @@ namespace gnss { namespace common { struct ReplayUtils { - static const char* getGnssPath(); + static std::string getGnssPath(); static std::string getDataFromDeviceFile(const std::string& command, int mMinIntervalMs); diff --git a/gnss/common/utils/default/include/v2_1/GnssTemplate.h b/gnss/common/utils/default/include/v2_1/GnssTemplate.h index 66c23d4719..4e07af9853 100644 --- a/gnss/common/utils/default/include/v2_1/GnssTemplate.h +++ b/gnss/common/utils/default/include/v2_1/GnssTemplate.h @@ -162,11 +162,11 @@ template std::unique_ptr GnssTemplate::getLocationFromHW() { if (!mHardwareModeChecked) { // default using /dev/gnss0 - const char* gnss_dev_path = ReplayUtils::getGnssPath(); + std::string gnss_dev_path = ReplayUtils::getGnssPath(); - mGnssFd = open(gnss_dev_path, O_RDWR | O_NONBLOCK); + mGnssFd = open(gnss_dev_path.c_str(), O_RDWR | O_NONBLOCK); if (mGnssFd == -1) { - ALOGW("Failed to open %s errno: %d", gnss_dev_path, errno); + ALOGW("Failed to open %s errno: %d", gnss_dev_path.c_str(), errno); } mHardwareModeChecked = true; }