Snap for 9157512 from e8e07eaa1f6ab3b4f793e3fa7ff254825741c03d to mainline-tzdata3-release

Change-Id: Iba406c6df9804ddcfe0cdc5685acc329a52e9cc8
diff --git a/audio/device_port_sink.cpp b/audio/device_port_sink.cpp
index 4f008d2..e7590ce 100644
--- a/audio/device_port_sink.cpp
+++ b/audio/device_port_sink.cpp
@@ -41,6 +41,13 @@
 constexpr int kMaxJitterUs = 3000;  // Enforced by CTS, should be <= 6ms
 
 struct TinyalsaSink : public DevicePortSink {
+    // Mostly magic numbers.
+    // In pcm, the hardware works with `period_size` granularity.
+    // The `period_count` is the number of `period_size` units in the pcm
+    // buffer.
+    static constexpr size_t kPcmPeriodCount = 4;
+    static constexpr size_t kPcmPeriodSizeMultiplier = 2;
+
     TinyalsaSink(unsigned pcmCard, unsigned pcmDevice,
                  const AudioConfig &cfg,
                  uint64_t &frames)
@@ -55,7 +62,8 @@
             , mPcm(talsa::pcmOpen(pcmCard, pcmDevice,
                                   util::countChannels(cfg.channelMask),
                                   cfg.sampleRateHz,
-                                  cfg.frameCount,
+                                  kPcmPeriodCount,
+                                  kPcmPeriodSizeMultiplier * cfg.frameCount / kPcmPeriodCount,
                                   true /* isOut */)) {
         if (mPcm) {
             LOG_ALWAYS_FATAL_IF(!talsa::pcmPrepare(mPcm.get()));
@@ -70,12 +78,13 @@
         mConsumeThread.join();
     }
 
-    Result start() override {
-        return talsa::pcmStart(mPcm.get()) ? Result::OK : FAILURE(Result::INVALID_STATE);
-    }
+    static int getLatencyMs(const AudioConfig &cfg) {
+        constexpr size_t inMs = 1000;
+        const size_t numerator = kPcmPeriodSizeMultiplier * cfg.frameCount;
+        const size_t denominator = kPcmPeriodCount * cfg.sampleRateHz / inMs;
 
-    Result stop() override {
-        return talsa::pcmStop(mPcm.get()) ? Result::OK : FAILURE(Result::INVALID_STATE);
+        // integer division with rounding
+        return (numerator + (denominator >> 1)) / denominator;
     }
 
     Result getPresentationPosition(uint64_t &frames, TimeSpec &ts) override {
@@ -247,8 +256,9 @@
             , mInitialFrames(frames)
             , mFrames(frames) {}
 
-    Result start() override { return Result::OK; }
-    Result stop() override { return Result::OK; }
+    static int getLatencyMs(const AudioConfig &) {
+        return 1;
+    }
 
     Result getPresentationPosition(uint64_t &frames, TimeSpec &ts) override {
         const AutoMutex lock(mFrameCountersMutex);
@@ -379,6 +389,20 @@
     return NullSink::create(cfg, readerBufferSizeHint, frames);
 }
 
+int DevicePortSink::getLatencyMs(const DeviceAddress &address, const AudioConfig &cfg) {
+    switch (address.device) {
+    default:
+        ALOGW("%s:%d unsupported device: '%x'", __func__, __LINE__, address.device);
+        return FAILURE(-1);
+
+    case AudioDevice::OUT_SPEAKER:
+        return TinyalsaSink::getLatencyMs(cfg);
+
+    case AudioDevice::OUT_TELEPHONY_TX:
+        return NullSink::getLatencyMs(cfg);
+    }
+}
+
 }  // namespace implementation
 }  // namespace V6_0
 }  // namespace audio
diff --git a/audio/device_port_sink.h b/audio/device_port_sink.h
index 536957b..29503f9 100644
--- a/audio/device_port_sink.h
+++ b/audio/device_port_sink.h
@@ -31,8 +31,6 @@
 
 struct DevicePortSink {
     virtual ~DevicePortSink() {}
-    virtual Result start() = 0;
-    virtual Result stop() = 0;
     virtual Result getPresentationPosition(uint64_t &frames, TimeSpec &ts) = 0;
     virtual size_t write(float volume, size_t bytesToWrite, IReader &) = 0;
 
@@ -41,6 +39,8 @@
                                                   const AudioConfig &,
                                                   const hidl_bitfield<AudioOutputFlag> &,
                                                   uint64_t &frames);
+
+    static int getLatencyMs(const DeviceAddress &, const AudioConfig &);
 };
 
 }  // namespace implementation
diff --git a/audio/device_port_source.cpp b/audio/device_port_source.cpp
index c7dba44..9d49580 100644
--- a/audio/device_port_source.cpp
+++ b/audio/device_port_source.cpp
@@ -22,6 +22,7 @@
 #include <audio_utils/channels.h>
 #include <audio_utils/format.h>
 #include <log/log.h>
+#include <utils/Mutex.h>
 #include <utils/ThreadDefs.h>
 #include <utils/Timers.h>
 #include "device_port_source.h"
@@ -44,6 +45,13 @@
 constexpr int kMaxJitterUs = 3000;  // Enforced by CTS, should be <= 6ms
 
 struct TinyalsaSource : public DevicePortSource {
+    // Mostly magic numbers.
+    // In pcm, the hardware works with `period_size` granularity.
+    // The `period_count` is the number of `period_size` units in the pcm
+    // buffer.
+    static constexpr size_t kPcmPeriodCount = 4;
+    static constexpr size_t kPcmPeriodSizeMultiplier = 2;
+
     TinyalsaSource(unsigned pcmCard, unsigned pcmDevice,
                    const AudioConfig &cfg, uint64_t &frames)
             : mStartNs(systemTime(SYSTEM_TIME_MONOTONIC))
@@ -56,7 +64,8 @@
             , mPcm(talsa::pcmOpen(pcmCard, pcmDevice,
                                   util::countChannels(cfg.channelMask),
                                   cfg.sampleRateHz,
-                                  cfg.frameCount,
+                                  kPcmPeriodCount,
+                                  kPcmPeriodSizeMultiplier * cfg.frameCount / kPcmPeriodCount,
                                   false /* isOut */)) {
         if (mPcm) {
             LOG_ALWAYS_FATAL_IF(!talsa::pcmPrepare(mPcm.get()));
@@ -71,17 +80,11 @@
         mProduceThread.join();
     }
 
-    Result start() override {
-        return talsa::pcmStart(mPcm.get()) ? Result::OK : FAILURE(Result::INVALID_STATE);
-    }
-
-    Result stop() override {
-        return talsa::pcmStop(mPcm.get()) ? Result::OK : FAILURE(Result::INVALID_STATE);
-    }
-
     Result getCapturePosition(uint64_t &frames, uint64_t &time) override {
+        const AutoMutex lock(mFrameCountersMutex);
+
         const nsecs_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
-        const uint64_t nowFrames = getCaptureFrames(nowNs);
+        const uint64_t nowFrames = getCaptureFramesLocked(nowNs);
         mFrames += (nowFrames - mPreviousFrames);
         mPreviousFrames = nowFrames;
 
@@ -90,26 +93,28 @@
         return Result::OK;
     }
 
-    uint64_t getCaptureFrames(const nsecs_t nowNs) const {
+    uint64_t getCaptureFramesLocked(const nsecs_t nowNs) const {
         return uint64_t(mSampleRateHz) * ns2us(nowNs - mStartNs) / 1000000;
     }
 
-    uint64_t getAvailableFrames(const nsecs_t nowNs) const {
-        return getCaptureFrames(nowNs) - mSentFrames;
+    uint64_t getAvailableFramesLocked(const nsecs_t nowNs) const {
+        return getCaptureFramesLocked(nowNs) - mSentFrames;
     }
 
-    uint64_t getAvailableFramesNow() const {
-        return getAvailableFrames(systemTime(SYSTEM_TIME_MONOTONIC));
+    uint64_t getAvailableFramesNowLocked() const {
+        return getAvailableFramesLocked(systemTime(SYSTEM_TIME_MONOTONIC));
     }
 
-    size_t getWaitFramesNow(const size_t requestedFrames) const {
-        const size_t availableFrames = getAvailableFramesNow();
+    size_t getWaitFramesNowLocked(const size_t requestedFrames) const {
+        const size_t availableFrames = getAvailableFramesNowLocked();
         return (requestedFrames > availableFrames)
             ? (requestedFrames - availableFrames) : 0;
     }
 
     size_t read(float volume, size_t bytesToRead, IWriter &writer) override {
-        const size_t waitFrames = getWaitFramesNow(bytesToRead / mFrameSize);
+        const AutoMutex lock(mFrameCountersMutex);
+
+        const size_t waitFrames = getWaitFramesNowLocked(bytesToRead / mFrameSize);
         const auto blockUntil =
             std::chrono::high_resolution_clock::now() +
                 + std::chrono::microseconds(waitFrames * 1000000 / mSampleRateHz);
@@ -150,8 +155,8 @@
                     const size_t nZeroBytes = nZeroFrames * mFrameSize;
 
                     writer(zeroes, nZeroBytes);
-                    mSentFrames += nZeroFrames;
                     bytesToRead -= nZeroBytes;
+                    mSentFrames += nZeroFrames;
                 }
                 break;
             }
@@ -208,15 +213,16 @@
     const unsigned mSampleRateHz;
     const unsigned mFrameSize;
     const unsigned mReadSizeFrames;
-    uint64_t &mFrames;
-    uint64_t mPreviousFrames = 0;
-    uint64_t mSentFrames = 0;
+    uint64_t &mFrames GUARDED_BY(mFrameCountersMutex);
+    uint64_t mPreviousFrames GUARDED_BY(mFrameCountersMutex) = 0;
+    uint64_t mSentFrames GUARDED_BY(mFrameCountersMutex) = 0;
     std::atomic<uint32_t> mFramesLost = 0;
     RingBuffer mRingBuffer;
     talsa::Mixer mMixer;
     talsa::PcmPtr mPcm;
     std::thread mProduceThread;
     std::atomic<bool> mProduceThreadRunning = true;
+    mutable Mutex mFrameCountersMutex;
 };
 
 template <class G> struct GeneratedSource : public DevicePortSource {
@@ -231,12 +237,11 @@
             , mNChannels(util::countChannels(cfg.channelMask))
             , mGenerator(std::move(generator)) {}
 
-    Result start() override { return Result::OK; }
-    Result stop() override { return Result::OK; }
-
     Result getCapturePosition(uint64_t &frames, uint64_t &time) override {
+        const AutoMutex lock(mFrameCountersMutex);
+
         const nsecs_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
-        const uint64_t nowFrames = getCaptureFrames(nowNs);
+        const uint64_t nowFrames = getCaptureFramesLocked(nowNs);
         mFrames += (nowFrames - mPreviousFrames);
         mPreviousFrames = nowFrames;
         frames = mFrames;
@@ -244,15 +249,16 @@
         return Result::OK;
     }
 
-    uint64_t getCaptureFrames(const nsecs_t nowNs) const {
+    uint64_t getCaptureFramesLocked(const nsecs_t nowNs) const {
         return uint64_t(mSampleRateHz) * ns2us(nowNs - mStartNs) / 1000000;
     }
 
-    uint64_t getAvailableFrames(const nsecs_t nowNs) const {
-        return getCaptureFrames(nowNs) - mSentFrames;
+    uint64_t getAvailableFramesLocked(const nsecs_t nowNs) const {
+        return getCaptureFramesLocked(nowNs) - mSentFrames;
     }
 
     size_t read(float volume, size_t bytesToRead, IWriter &writer) override {
+        const AutoMutex lock(mFrameCountersMutex);
         mWriteBuffer.resize(bytesToRead / sizeof(int16_t));
 
         int16_t *samples = mWriteBuffer.data();
@@ -262,7 +268,7 @@
         unsigned availableFrames;
         while (true) {
             const nsecs_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
-            availableFrames = getAvailableFrames(nowNs);
+            availableFrames = getAvailableFramesLocked(nowNs);
             if (availableFrames < requestedFrames / 2) {
                 const unsigned neededMoreFrames = requestedFrames / 2 - availableFrames;
 
@@ -280,25 +286,27 @@
             adjust_channels(samples, 1, samples, nChannels,
                             sizeof(*samples), nFrames * sizeof(*samples));
         }
-        mSentFrames += nFrames;
 
         aops::multiplyByVolume(volume,
                                mWriteBuffer.data(),
                                nSamples);
 
         writer(mWriteBuffer.data(), nSamples * sizeof(*samples));
+        mSentFrames += nFrames;
+
         return 0;
     }
 
 private:
     std::vector<int16_t> mWriteBuffer;
-    uint64_t &mFrames;
+    uint64_t &mFrames GUARDED_BY(mFrameCountersMutex);
     const nsecs_t mStartNs;
     const unsigned mSampleRateHz;
     const unsigned mNChannels;
-    uint64_t mPreviousFrames = 0;
-    uint64_t mSentFrames = 0;
+    uint64_t mPreviousFrames GUARDED_BY(mFrameCountersMutex) = 0;
+    uint64_t mSentFrames GUARDED_BY(mFrameCountersMutex) = 0;
     G mGenerator;
+    mutable Mutex mFrameCountersMutex;
 };
 
 std::vector<int16_t> convertFloatsToInt16(const std::vector<float> &pcmFloat) {
diff --git a/audio/device_port_source.h b/audio/device_port_source.h
index d82e2b3..16b5d27 100644
--- a/audio/device_port_source.h
+++ b/audio/device_port_source.h
@@ -31,8 +31,6 @@
 
 struct DevicePortSource {
     virtual ~DevicePortSource() {}
-    virtual Result start() = 0;
-    virtual Result stop() = 0;
     virtual Result getCapturePosition(uint64_t &frames, uint64_t &time) = 0;
     virtual size_t read(float volume, size_t bytesToRead, IWriter &) = 0;
 
diff --git a/audio/stream_in.cpp b/audio/stream_in.cpp
index b78c30f..dc354f6 100644
--- a/audio/stream_in.cpp
+++ b/audio/stream_in.cpp
@@ -73,13 +73,6 @@
             mEfGroup.reset(rawEfGroup);
         }
 
-        mSource = DevicePortSource::create(mDataMQ.getQuantumCount(),
-                                           stream->getDeviceAddress(),
-                                           stream->getAudioConfig(),
-                                           stream->getAudioOutputFlags(),
-                                           stream->getFrameCounter());
-        LOG_ALWAYS_FATAL_IF(!mSource);
-
         mThread = std::thread(&ReadThread::threadLoop, this);
     }
 
@@ -102,14 +95,6 @@
         return mTid.get_future();
     }
 
-    Result start() {
-        return mSource->start();
-    }
-
-    Result stop() {
-        return mSource->stop();
-    }
-
     void threadLoop() {
         util::setThreadPriority(PRIORITY_URGENT_AUDIO);
         mTid.set_value(pthread_self());
@@ -123,11 +108,19 @@
             }
 
             if (efState & STAND_BY_REQUEST) {
-                mSource->stop();
+                mSource.reset();
             }
 
             if (efState & (MessageQueueFlagBits::NOT_FULL | 0)) {
-                mSource->start();
+                if (!mSource) {
+                    mSource = DevicePortSource::create(mDataMQ.getQuantumCount(),
+                                                       mStream->getDeviceAddress(),
+                                                       mStream->getAudioConfig(),
+                                                       mStream->getAudioOutputFlags(),
+                                                       mStream->getFrameCounter());
+                    LOG_ALWAYS_FATAL_IF(!mSource);
+                }
+
                 processCommand();
             }
         }
@@ -344,15 +337,11 @@
 }
 
 Return<Result> StreamIn::start() {
-    return mReadThread
-        ? static_cast<ReadThread*>(mReadThread.get())->start()
-        : FAILURE(Result::INVALID_STATE);
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<Result> StreamIn::stop() {
-    return mReadThread
-        ? static_cast<ReadThread*>(mReadThread.get())->stop()
-        : FAILURE(Result::INVALID_STATE);
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<void> StreamIn::createMmapBuffer(int32_t minSizeFrames,
diff --git a/audio/stream_out.cpp b/audio/stream_out.cpp
index dfe45b8..633258e 100644
--- a/audio/stream_out.cpp
+++ b/audio/stream_out.cpp
@@ -75,13 +75,6 @@
             mEfGroup.reset(rawEfGroup);
         }
 
-        mSink = DevicePortSink::create(mDataMQ.getQuantumCount(),
-                                       stream->getDeviceAddress(),
-                                       stream->getAudioConfig(),
-                                       stream->getAudioOutputFlags(),
-                                       stream->getFrameCounter());
-        LOG_ALWAYS_FATAL_IF(!mSink);
-
         mThread = std::thread(&WriteThread::threadLoop, this);
     }
 
@@ -104,13 +97,6 @@
         return mTid.get_future();
     }
 
-    Result start() {
-        return mSink->start();
-    }
-
-    Result stop() {
-        return mSink->stop();
-    }
 
     void threadLoop() {
         util::setThreadPriority(PRIORITY_URGENT_AUDIO);
@@ -125,11 +111,19 @@
             }
 
             if (efState & STAND_BY_REQUEST) {
-                mSink->stop();
+                mSink.reset();
             }
 
             if (efState & (MessageQueueFlagBits::NOT_EMPTY | 0)) {
-                mSink->start();
+                if (!mSink) {
+                    mSink = DevicePortSink::create(mDataMQ.getQuantumCount(),
+                                                   mStream->getDeviceAddress(),
+                                                   mStream->getAudioConfig(),
+                                                   mStream->getAudioOutputFlags(),
+                                                   mStream->getFrameCounter());
+                    LOG_ALWAYS_FATAL_IF(!mSink);
+                }
+
                 processCommand();
             }
         }
@@ -213,8 +207,16 @@
     IStreamOut::WriteStatus doGetLatency() {
         IStreamOut::WriteStatus status;
 
-        status.retval = Result::OK;
-        status.reply.latencyMs = mStream->getLatency();
+        const int latencyMs =
+            DevicePortSink::getLatencyMs(mStream->getDeviceAddress(),
+                                         mStream->getAudioConfig());
+
+        if (latencyMs >= 0) {
+            status.retval = Result::OK;
+            status.reply.latencyMs = latencyMs;
+        } else {
+            status.retval = Result::INVALID_STATE;
+        }
 
         return status;
     }
@@ -370,15 +372,11 @@
 }
 
 Return<Result> StreamOut::start() {
-    return mWriteThread
-        ? static_cast<WriteThread*>(mWriteThread.get())->start()
-        : FAILURE(Result::INVALID_STATE);
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<Result> StreamOut::stop() {
-    return mWriteThread
-        ? static_cast<WriteThread*>(mWriteThread.get())->stop()
-        : FAILURE(Result::INVALID_STATE);
+    return FAILURE(Result::NOT_SUPPORTED);
 }
 
 Return<void> StreamOut::createMmapBuffer(int32_t minSizeFrames,
@@ -394,7 +392,10 @@
 }
 
 Return<uint32_t> StreamOut::getLatency() {
-    return mCommon.getFrameCount() * 1000 / mCommon.getSampleRate();
+    const int latencyMs = DevicePortSink::getLatencyMs(getDeviceAddress(), getAudioConfig());
+
+    return (latencyMs >= 0) ? latencyMs :
+        (mCommon.getFrameCount() * 1000 / mCommon.getSampleRate());
 }
 
 Return<Result> StreamOut::setVolume(float left, float right) {
diff --git a/audio/talsa.cpp b/audio/talsa.cpp
index d406bb4..2cfe628 100644
--- a/audio/talsa.cpp
+++ b/audio/talsa.cpp
@@ -105,16 +105,16 @@
                                            const unsigned int card,
                                            const unsigned int nChannels,
                                            const size_t sampleRateHz,
-                                           const size_t frameCount,
+                                           const size_t periodCount,
+                                           const size_t periodSize,
                                            const bool isOut) {
     struct pcm_config pcm_config;
     memset(&pcm_config, 0, sizeof(pcm_config));
 
     pcm_config.channels = nChannels;
     pcm_config.rate = sampleRateHz;
-    pcm_config.period_count = 4; // Approx interrupts per buffer
-    // Approx frames between interrupts
-    pcm_config.period_size = 2 * frameCount / pcm_config.period_count;
+    pcm_config.period_count = periodCount; // Approx interrupts per buffer
+    pcm_config.period_size = periodSize; // Approx frames between interrupts
     pcm_config.format = PCM_FORMAT_S16_LE;
 
     PcmPtr pcm =
@@ -125,8 +125,8 @@
         return pcm;
     } else {
         ALOGE("%s:%d pcm_open failed for nChannels=%u sampleRateHz=%zu "
-              "frameCount=%zu isOut=%d with %s", __func__, __LINE__,
-              nChannels, sampleRateHz, frameCount, isOut,
+              "period_count=%zu period_size=%zu isOut=%d with %s", __func__, __LINE__,
+              nChannels, sampleRateHz, periodCount, periodSize, isOut,
               pcm_get_error(pcm.get()));
         return FAILURE(nullptr);
     }
@@ -182,13 +182,26 @@
         return FAILURE(false);
     }
 
-    const int r = ::pcm_read(pcm, data, count);
-    if (r) {
-        ALOGE("%s:%d pcm_read failed with %s (%d)",
-              __func__, __LINE__, ::pcm_get_error(pcm), r);
-        return FAILURE(false);
-    } else {
-        return true;
+    int tries = 3;
+    while (true) {
+        --tries;
+        const int r = ::pcm_read(pcm, data, count);
+        switch (-r) {
+        case 0:
+            return true;
+
+        case EIO:
+        case EAGAIN:
+            if (tries > 0) {
+                break;
+            }
+            [[fallthrough]];
+
+        default:
+            ALOGW("%s:%d pcm_read failed with '%s' (%d)",
+                  __func__, __LINE__, ::pcm_get_error(pcm), r);
+            return FAILURE(false);
+        }
     }
 }
 
@@ -197,13 +210,26 @@
         return FAILURE(false);
     }
 
-    const int r = ::pcm_write(pcm, data, count);
-    if (r) {
-        ALOGE("%s:%d pcm_write failed with %s (%d)",
-              __func__, __LINE__, ::pcm_get_error(pcm), r);
-        return FAILURE(false);
-    } else {
-        return true;
+    int tries = 3;
+    while (true) {
+        --tries;
+        const int r = ::pcm_write(pcm, data, count);
+        switch (-r) {
+        case 0:
+            return true;
+
+        case EIO:
+        case EAGAIN:
+            if (tries > 0) {
+                break;
+            }
+            [[fallthrough]];
+
+        default:
+            ALOGW("%s:%d pcm_write failed with '%s' (%d)",
+                  __func__, __LINE__, ::pcm_get_error(pcm), r);
+            return FAILURE(false);
+        }
     }
 }
 
diff --git a/audio/talsa.h b/audio/talsa.h
index 73df5ca..37c0c1b 100644
--- a/audio/talsa.h
+++ b/audio/talsa.h
@@ -31,7 +31,9 @@
 typedef struct pcm pcm_t;
 struct PcmDeleter { void operator()(pcm_t *x) const; };
 typedef std::unique_ptr<pcm_t, PcmDeleter> PcmPtr;
-PcmPtr pcmOpen(unsigned int dev, unsigned int card, unsigned int nChannels, size_t sampleRateHz, size_t frameCount, bool isOut);
+PcmPtr pcmOpen(unsigned int dev, unsigned int card, unsigned int nChannels,
+               size_t sampleRateHz, size_t periodCount, size_t periodSize,
+               bool isOut);
 bool pcmPrepare(pcm_t *pcm);
 bool pcmStart(pcm_t *pcm);
 bool pcmStop(pcm_t *pcm);
diff --git a/camera/JpegCompressor.cpp b/camera/JpegCompressor.cpp
index 168b98a..4efba28 100644
--- a/camera/JpegCompressor.cpp
+++ b/camera/JpegCompressor.cpp
@@ -46,7 +46,11 @@
 
 NV21JpegCompressor::NV21JpegCompressor()
 {
+#ifdef __LP64__
+    const char dlName[] = "/vendor/lib64/hw/camera.ranchu.jpeg.so";
+#else
     const char dlName[] = "/vendor/lib/hw/camera.ranchu.jpeg.so";
+#endif
     if (mDl == NULL) {
         mDl = dlopen(dlName, RTLD_NOW);
     }
diff --git a/gnss/gnss_hw_listener.cpp b/gnss/gnss_hw_listener.cpp
index cde8c57..fdc400f 100644
--- a/gnss/gnss_hw_listener.cpp
+++ b/gnss/gnss_hw_listener.cpp
@@ -74,11 +74,15 @@
         m_buffer.push_back(c);
     }
     if (c == '\n') {
-        const ahg20::ElapsedRealtime ts = util::makeElapsedRealtime(util::nowNanos());
+        using namespace std::chrono;
 
-        if (parse(m_buffer.data() + 1, m_buffer.data() + m_buffer.size() - 2, ts)) {
-            m_sink->gnssNmea(ts.timestampNs / 1000000,
-                             hidl_string(m_buffer.data(), m_buffer.size()));
+        const ahg10::GnssUtcTime t = time_point_cast<milliseconds>(
+                system_clock::now()).time_since_epoch().count();
+        const ahg20::ElapsedRealtime ert = util::makeElapsedRealtime(
+                android::elapsedRealtimeNano());
+
+        if (parse(m_buffer.data() + 1, m_buffer.data() + m_buffer.size() - 2, t, ert)) {
+            m_sink->gnssNmea(t, hidl_string(m_buffer.data(), m_buffer.size()));
         } else {
             m_buffer.back() = 0;
             ALOGW("%s:%d: failed to parse an NMEA message, '%s'",
@@ -92,11 +96,12 @@
 }
 
 bool GnssHwListener::parse(const char* begin, const char* end,
-                           const ahg20::ElapsedRealtime& ts) {
+                           const ahg10::GnssUtcTime& t,
+                           const ahg20::ElapsedRealtime& ert) {
     if (const char* fields = testNmeaField(begin, end, "GPRMC", ',')) {
-        return parseGPRMC(fields, end, ts);
+        return parseGPRMC(fields, end, t, ert);
     } else if (const char* fields = testNmeaField(begin, end, "GPGGA", ',')) {
-        return parseGPGGA(fields, end, ts);
+        return parseGPGGA(fields, end, t, ert);
     } else {
         return false;
     }
@@ -118,7 +123,8 @@
 //     11  W          East/West
 //     12  *70        checksum
 bool GnssHwListener::parseGPRMC(const char* begin, const char*,
-                                const ahg20::ElapsedRealtime& ts) {
+                                const ahg10::GnssUtcTime& t,
+                                const ahg20::ElapsedRealtime& ert) {
     double speedKnots = 0;
     double course = 0;
     double variation = 0;
@@ -155,7 +161,7 @@
     const double speed = speedKnots * 0.514444;
 
     ahg20::GnssLocation loc20;
-    loc20.elapsedRealtime = ts;
+    loc20.elapsedRealtime = ert;
 
     auto& loc10 = loc20.v1_0;
 
@@ -166,7 +172,7 @@
     loc10.horizontalAccuracyMeters = 5;
     loc10.speedAccuracyMetersPerSecond = .5;
     loc10.bearingAccuracyDegrees = 30;
-    loc10.timestamp = ts.timestampNs / 1000000;
+    loc10.timestamp = t;
 
     using ahg10::GnssLocationFlags;
     loc10.gnssLocationFlags =
@@ -205,6 +211,7 @@
 //    dgps age         <dontcare> time in seconds since last DGPS fix
 //    dgps sid         <dontcare> DGPS station id
 bool GnssHwListener::parseGPGGA(const char* begin, const char* end,
+                                const ahg10::GnssUtcTime&,
                                 const ahg20::ElapsedRealtime&) {
     double altitude = 0;
     int latdmm = 0;
diff --git a/gnss/gnss_hw_listener.h b/gnss/gnss_hw_listener.h
index 234908b..47ff77d 100644
--- a/gnss/gnss_hw_listener.h
+++ b/gnss/gnss_hw_listener.h
@@ -28,9 +28,15 @@
     void consume(char);
 
 private:
-    bool parse(const char* begin, const char* end, const ahg20::ElapsedRealtime&);
-    bool parseGPRMC(const char* begin, const char* end, const ahg20::ElapsedRealtime&);
-    bool parseGPGGA(const char* begin, const char* end, const ahg20::ElapsedRealtime&);
+    bool parse(const char* begin, const char* end,
+               const ahg10::GnssUtcTime& t,
+               const ahg20::ElapsedRealtime& ert);
+    bool parseGPRMC(const char* begin, const char* end,
+                    const ahg10::GnssUtcTime& t,
+                    const ahg20::ElapsedRealtime& ert);
+    bool parseGPGGA(const char* begin, const char* end,
+                    const ahg10::GnssUtcTime& t,
+                    const ahg20::ElapsedRealtime& ert);
 
     const DataSink*     m_sink;
     std::vector<char>   m_buffer;
diff --git a/gnss/util.cpp b/gnss/util.cpp
index d0be41b..cef7473 100644
--- a/gnss/util.cpp
+++ b/gnss/util.cpp
@@ -14,17 +14,11 @@
  * limitations under the License.
  */
 
-#include <chrono>
 #include "util.h"
 
 namespace goldfish {
 namespace util {
 
-int64_t nowNanos() {
-    using namespace std::chrono;
-    return time_point_cast<nanoseconds>(system_clock::now()).time_since_epoch().count();
-}
-
 ahg20::ElapsedRealtime makeElapsedRealtime(long long timestampNs) {
     ahg20::ElapsedRealtime ts = {
         .flags = ahg20::ElapsedRealtimeFlags::HAS_TIMESTAMP_NS |
diff --git a/gnss/util.h b/gnss/util.h
index ba1b5a4..6119e93 100644
--- a/gnss/util.h
+++ b/gnss/util.h
@@ -23,8 +23,6 @@
 
 namespace util {
 
-int64_t nowNanos();
-
 ahg20::ElapsedRealtime makeElapsedRealtime(long long timestampNs);
 
 }  // namespace util