diff options
author | Arthur Ishiguro <arthuri@google.com> | 2017-10-02 16:16:15 -0700 |
---|---|---|
committer | Arthur Ishiguro <arthuri@google.com> | 2017-10-03 10:09:41 -0700 |
commit | b0bd0c2b3c1b0e7fb9c6652753a24de28809ff28 (patch) | |
tree | d49aabbd31e0b518458b0eeb58fd6612a35f40f7 | |
parent | 38f8f210741a7c22fb5117fbaeb17e781be64bd8 (diff) | |
download | chre-b0bd0c2b3c1b0e7fb9c6652753a24de28809ff28.tar.gz |
Fix overflow in time sync offset calculation
Ticks to nanosecond conversion math in time sync offset calculation
overflowed after 11 days.
Bug: 67059655
Test: Compile and run on device, and verify that offset matches expected
value based on the qTimer counter and elapsedRealtimenano() values.
Change-Id: I659cde63bc4db75b6df57e6f62a4c32e0d78195f
-rw-r--r-- | host/msm/daemon/chre_daemon.cc | 57 |
1 files changed, 38 insertions, 19 deletions
diff --git a/host/msm/daemon/chre_daemon.cc b/host/msm/daemon/chre_daemon.cc index b6563b5e..3c13f045 100644 --- a/host/msm/daemon/chre_daemon.cc +++ b/host/msm/daemon/chre_daemon.cc @@ -179,7 +179,7 @@ static void parseAndEmitLogMessages(unsigned char *message) { } } -static int64_t getTimeOffset() { +static int64_t getTimeOffset(bool *success) { int64_t timeOffset = 0; #if defined(__aarch64__) @@ -191,18 +191,34 @@ static int64_t getTimeOffset() { // Use uint64_t to store since the MRS instruction uses 64 bit (X) registers // (http://infocenter.arm.com/help/topic/ // com.arm.doc.den0024a/ch06s05s02.html) - uint64_t qTimerCount = 0, qTimerFreqKHz = 0; + uint64_t qTimerCount = 0, qTimerFreq = 0; uint64_t hostTimeNano = elapsedRealtimeNano(); asm volatile("mrs %0, cntpct_el0" : "=r"(qTimerCount)); - asm volatile("mrs %0, cntfrq_el0" : "=r"(qTimerFreqKHz)); - qTimerFreqKHz /= 1000; + asm volatile("mrs %0, cntfrq_el0" : "=r"(qTimerFreq)); + + constexpr uint64_t kOneSecondInNanoseconds = 1000000000; + if (qTimerFreq != 0) { + // Get the seconds part first, then convert the remainder to prevent + // overflow + uint64_t qTimerNanos = (qTimerCount / qTimerFreq); + if (qTimerNanos > UINT64_MAX / kOneSecondInNanoseconds) { + LOGE("CNTPCT_EL0 conversion to nanoseconds overflowed during time sync." + " Aborting time sync."); + *success = false; + } else { + qTimerNanos *= kOneSecondInNanoseconds; - if (qTimerFreqKHz != 0) { - uint64_t qTimerNanos = (qTimerCount < UINT64_MAX / 1000000) ? - (qTimerCount * 1000000) : UINT64_MAX; - qTimerNanos /= qTimerFreqKHz; + // Round the remainder portion to the nearest nanosecond + uint64_t remainder = (qTimerCount % qTimerFreq); + qTimerNanos += + (remainder * kOneSecondInNanoseconds + qTimerFreq / 2) / qTimerFreq; - timeOffset = hostTimeNano - qTimerNanos; + timeOffset = hostTimeNano - qTimerNanos; + *success = true; + } + } else { + LOGE("CNTFRQ_EL0 had 0 value. Aborting time sync."); + *success = false; } #else #error "Unsupported CPU architecture type" @@ -212,16 +228,19 @@ static int64_t getTimeOffset() { } static void sendTimeSyncMessage() { - int64_t timeOffset = getTimeOffset(); - - flatbuffers::FlatBufferBuilder builder(64); - HostProtocolHost::encodeTimeSyncMessage(builder, timeOffset); - int success = chre_slpi_deliver_message_from_host( - static_cast<const unsigned char *>(builder.GetBufferPointer()), - static_cast<int>(builder.GetSize())); - - if (success != 0) { - LOGE("Failed to deliver timestamp message from host to CHRE: %d", success); + bool timeSyncSuccess = true; + int64_t timeOffset = getTimeOffset(&timeSyncSuccess); + + if (timeSyncSuccess) { + flatbuffers::FlatBufferBuilder builder(64); + HostProtocolHost::encodeTimeSyncMessage(builder, timeOffset); + int success = chre_slpi_deliver_message_from_host( + static_cast<const unsigned char *>(builder.GetBufferPointer()), + static_cast<int>(builder.GetSize())); + + if (success != 0) { + LOGE("Failed to deliver timestamp message from host to CHRE: %d", success); + } } } |