Read GNSS measurement from device file when available

Test: atest CtsLocationGnssTestCases GtsLocationTestCases on CF
Bug: 190757198
Change-Id: Ic03d56a5df6b99f7b20c5840e7091ead138316b1
diff --git a/gnss/aidl/default/GnssMeasurementInterface.cpp b/gnss/aidl/default/GnssMeasurementInterface.cpp
index 0e489c5..9e4f7c7 100644
--- a/gnss/aidl/default/GnssMeasurementInterface.cpp
+++ b/gnss/aidl/default/GnssMeasurementInterface.cpp
@@ -19,6 +19,8 @@
 #include "GnssMeasurementInterface.h"
 #include <aidl/android/hardware/gnss/BnGnss.h>
 #include <log/log.h>
+#include "DeviceFileReader.h"
+#include "GnssRawMeasurementParser.h"
 #include "GnssReplayUtils.h"
 #include "Utils.h"
 
@@ -26,6 +28,8 @@
 
 using Utils = ::android::hardware::gnss::common::Utils;
 using ReplayUtils = ::android::hardware::gnss::common::ReplayUtils;
+using GnssRawMeasurementParser = ::android::hardware::gnss::common::GnssRawMeasurementParser;
+using DeviceFileReader = ::android::hardware::gnss::common::DeviceFileReader;
 
 std::shared_ptr<IGnssMeasurementCallback> GnssMeasurementInterface::sCallback = nullptr;
 
@@ -68,15 +72,15 @@
             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.
+                        rawMeasurementStr =
+                                DeviceFileReader::Instance().getGnssRawMeasurementData())) {
                 ALOGD("rawMeasurementStr(size: %zu) from device file: %s", rawMeasurementStr.size(),
                       rawMeasurementStr.c_str());
-                auto measurement = Utils::getMockMeasurement(enableCorrVecOutputs);
-                this->reportMeasurement(measurement);
+                auto measurement =
+                        GnssRawMeasurementParser::getMeasurementFromStrs(rawMeasurementStr);
+                if (measurement != nullptr) {
+                    this->reportMeasurement(*measurement);
+                }
             } else {
                 auto measurement = Utils::getMockMeasurement(enableCorrVecOutputs);
                 this->reportMeasurement(measurement);
diff --git a/gnss/common/utils/default/Android.bp b/gnss/common/utils/default/Android.bp
index fd3d939..5294409 100644
--- a/gnss/common/utils/default/Android.bp
+++ b/gnss/common/utils/default/Android.bp
@@ -38,12 +38,13 @@
         "v2_1/GnssDebug.cpp",
         "v2_1/GnssMeasurement.cpp",
         "v2_1/GnssMeasurementCorrections.cpp",
-        "MockLocation.cpp",
-        "Utils.cpp",
-        "NmeaFixInfo.cpp",
-        "GnssReplayUtils.cpp",
-        "ParseUtils.cpp",
+        "DeviceFileReader.cpp",
         "GnssRawMeasurementParser.cpp",
+        "GnssReplayUtils.cpp",
+        "MockLocation.cpp",
+        "NmeaFixInfo.cpp",
+        "ParseUtils.cpp",
+        "Utils.cpp",
     ],
     export_include_dirs: ["include"],
     shared_libs: [
diff --git a/gnss/common/utils/default/DeviceFileReader.cpp b/gnss/common/utils/default/DeviceFileReader.cpp
new file mode 100644
index 0000000..7d4fb04
--- /dev/null
+++ b/gnss/common/utils/default/DeviceFileReader.cpp
@@ -0,0 +1,97 @@
+/*
+ * 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 "DeviceFileReader.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace common {
+
+void DeviceFileReader::getDataFromDeviceFile(const std::string& command, int mMinIntervalMs) {
+    char inputBuffer[INPUT_BUFFER_SIZE];
+    int mGnssFd = open(ReplayUtils::getGnssPath().c_str(),
+                       O_RDWR | O_NONBLOCK);
+
+    if (mGnssFd == -1) {
+        return;
+    }
+
+    int bytes_write = write(mGnssFd, command.c_str(), command.size());
+    if (bytes_write <= 0) {
+        close(mGnssFd);
+        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) {
+        close(mGnssFd);
+        return;
+    }
+    while (true) {
+        memset(inputBuffer, 0, INPUT_BUFFER_SIZE);
+        bytes_read = read(mGnssFd, &inputBuffer, INPUT_BUFFER_SIZE);
+        if (bytes_read <= 0) {
+            break;
+        }
+        s_buffer_ += std::string(inputBuffer, bytes_read);
+    }
+    close(mGnssFd);
+
+    // Trim end of file mark(\n\n\n\n).
+    auto pos = s_buffer_.find("\n\n\n\n");
+    if (pos != std::string::npos) {
+        inputStr = s_buffer_.substr(0, pos);
+        s_buffer_ = s_buffer_.substr(pos + 4);
+    } else {
+        return;
+    }
+
+    // Cache the injected data.
+    if (ReplayUtils::isGnssRawMeasurement(inputStr)) {
+        data_[CMD_GET_RAWMEASUREMENT] = inputStr;
+    } else if (ReplayUtils::isNMEA(inputStr)) {
+        data_[CMD_GET_LOCATION] = inputStr;
+    }
+}
+
+std::string DeviceFileReader::getLocationData() {
+    std::unique_lock<std::mutex> lock(mMutex);
+    getDataFromDeviceFile(CMD_GET_LOCATION, 20);
+    return data_[CMD_GET_LOCATION];
+}
+
+std::string DeviceFileReader::getGnssRawMeasurementData() {
+    std::unique_lock<std::mutex> lock(mMutex);
+    getDataFromDeviceFile(CMD_GET_RAWMEASUREMENT, 20);
+    return data_[CMD_GET_RAWMEASUREMENT];
+}
+
+DeviceFileReader::DeviceFileReader() {}
+
+DeviceFileReader::~DeviceFileReader() {}
+
+}  // namespace common
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gnss/common/utils/default/GnssReplayUtils.cpp b/gnss/common/utils/default/GnssReplayUtils.cpp
index fc4c477..e3f4ff8 100644
--- a/gnss/common/utils/default/GnssReplayUtils.cpp
+++ b/gnss/common/utils/default/GnssReplayUtils.cpp
@@ -40,45 +40,8 @@
 }
 
 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().c_str(), 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;
+    return !inputStr.empty() && (inputStr.find("$GPRMC,", 0) != std::string::npos ||
+                                 inputStr.find("$GPRMA,", 0) != std::string::npos);
 }
 
 }  // namespace common
diff --git a/gnss/common/utils/default/include/DeviceFileReader.h b/gnss/common/utils/default/include/DeviceFileReader.h
new file mode 100644
index 0000000..c2a5c5f
--- /dev/null
+++ b/gnss/common/utils/default/include/DeviceFileReader.h
@@ -0,0 +1,53 @@
+
+/*
+ * 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_default_DeviceFileReader_H_
+#define android_hardware_gnss_common_default_DeviceFileReader_H_
+
+#include <log/log.h>
+#include <mutex>
+#include <string>
+#include <unordered_map>
+#include "Constants.h"
+#include "GnssReplayUtils.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace common {
+class DeviceFileReader {
+  public:
+    static DeviceFileReader& Instance() {
+        static DeviceFileReader reader;
+        return reader;
+    }
+    std::string getLocationData();
+    std::string getGnssRawMeasurementData();
+    void getDataFromDeviceFile(const std::string& command, int mMinIntervalMs);
+
+  private:
+    DeviceFileReader();
+    ~DeviceFileReader();
+    std::unordered_map<std::string, std::string> data_;
+    std::string s_buffer_;
+    std::mutex mMutex;
+};
+}  // namespace common
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // android_hardware_gnss_common_default_DeviceFileReader_H_
\ No newline at end of file
diff --git a/gnss/common/utils/default/include/v2_1/GnssTemplate.h b/gnss/common/utils/default/include/v2_1/GnssTemplate.h
index 6f0ced1..19b1b45 100644
--- a/gnss/common/utils/default/include/v2_1/GnssTemplate.h
+++ b/gnss/common/utils/default/include/v2_1/GnssTemplate.h
@@ -30,6 +30,7 @@
 
 #include <cutils/properties.h>
 
+#include "DeviceFileReader.h"
 #include "GnssAntennaInfo.h"
 #include "GnssConfiguration.h"
 #include "GnssDebug.h"
@@ -163,19 +164,9 @@
 
 template <class T_IGnss>
 std::unique_ptr<V2_0::GnssLocation> GnssTemplate<T_IGnss>::getLocationFromHW() {
-    if (!mHardwareModeChecked) {
-        // default using /dev/gnss0
-        std::string gnss_dev_path = ReplayUtils::getGnssPath();
-
-        mGnssFd = open(gnss_dev_path.c_str(), O_RDWR | O_NONBLOCK);
-        if (mGnssFd == -1) {
-            ALOGW("Failed to open %s errno: %d", gnss_dev_path.c_str(), errno);
-        }
-        mHardwareModeChecked = true;
-    }
-
-    std::string inputStr = ::android::hardware::gnss::common::ReplayUtils::getDataFromDeviceFile(
-            CMD_GET_LOCATION, mMinIntervalMs);
+    mHardwareModeChecked = true;
+    std::string inputStr =
+            ::android::hardware::gnss::common::DeviceFileReader::Instance().getLocationData();
     return NmeaFixInfo::getLocationFromInputStr(inputStr);
 }