Flush the bucket when creating the metric producer.
Use int64 for value field.
E2e test for gauge/value metric.

BUG: b/74445671

Test: statsd test.
Change-Id: I823a0bade8f89834bdfb9cf48864852a47d7b63b
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 8e46714..e0222d9 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -205,6 +205,8 @@
     tests/e2e/Alarm_e2e_test.cpp \
     tests/e2e/Attribution_e2e_test.cpp \
     tests/e2e/GaugeMetric_e2e_push_test.cpp \
+    tests/e2e/GaugeMetric_e2e_pull_test.cpp \
+    tests/e2e/ValueMetric_pull_e2e_test.cpp \
     tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp \
     tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp \
     tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp \
diff --git a/cmds/statsd/benchmark/metric_util.cpp b/cmds/statsd/benchmark/metric_util.cpp
index 7d6c47b..e6272ed 100644
--- a/cmds/statsd/benchmark/metric_util.cpp
+++ b/cmds/statsd/benchmark/metric_util.cpp
@@ -365,7 +365,8 @@
     sp<AlarmMonitor> anomalyAlarmMonitor;
     sp<AlarmMonitor> periodicAlarmMonitor;
     sp<StatsLogProcessor> processor = new StatsLogProcessor(
-        uidMap, anomalyAlarmMonitor, periodicAlarmMonitor, timeBaseSec, [](const ConfigKey&){});
+        uidMap, anomalyAlarmMonitor, periodicAlarmMonitor, timeBaseSec * NS_PER_SEC,
+        [](const ConfigKey&){});
     processor->OnConfigUpdated(timeBaseSec * NS_PER_SEC, key, config);
     return processor;
 }
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 90ce735..efcb1fe 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -72,13 +72,13 @@
 StatsLogProcessor::StatsLogProcessor(const sp<UidMap>& uidMap,
                                      const sp<AlarmMonitor>& anomalyAlarmMonitor,
                                      const sp<AlarmMonitor>& periodicAlarmMonitor,
-                                     const long timeBaseSec,
+                                     const int64_t timeBaseNs,
                                      const std::function<void(const ConfigKey&)>& sendBroadcast)
     : mUidMap(uidMap),
       mAnomalyAlarmMonitor(anomalyAlarmMonitor),
       mPeriodicAlarmMonitor(periodicAlarmMonitor),
       mSendBroadcast(sendBroadcast),
-      mTimeBaseSec(timeBaseSec),
+      mTimeBaseNs(timeBaseNs),
       mLastLogTimestamp(0) {
 }
 
@@ -210,7 +210,7 @@
         const int64_t timestampNs, const ConfigKey& key, const StatsdConfig& config) {
     VLOG("Updated configuration for key %s", key.ToString().c_str());
     sp<MetricsManager> newMetricsManager =
-        new MetricsManager(key, config, mTimeBaseSec, (timestampNs - 1) / NS_PER_SEC + 1, mUidMap,
+        new MetricsManager(key, config, mTimeBaseNs, timestampNs, mUidMap,
                            mAnomalyAlarmMonitor, mPeriodicAlarmMonitor);
     auto it = mMetricsManagers.find(key);
     if (it != mMetricsManagers.end()) {
@@ -438,6 +438,10 @@
     WriteDataToDiskLocked();
 }
 
+void StatsLogProcessor::informPullAlarmFired(const int64_t timestampNs) {
+    mStatsPullerManager.OnAlarmFired(timestampNs);
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 1e82b1e..0e1d4ba 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -36,7 +36,7 @@
 public:
     StatsLogProcessor(const sp<UidMap>& uidMap, const sp<AlarmMonitor>& anomalyAlarmMonitor,
                       const sp<AlarmMonitor>& subscriberTriggerAlarmMonitor,
-                      const long timeBaseSec,
+                      const int64_t timeBaseNs,
                       const std::function<void(const ConfigKey&)>& sendBroadcast);
     virtual ~StatsLogProcessor();
 
@@ -70,6 +70,7 @@
 
     void dumpStates(FILE* out, bool verbose);
 
+    void informPullAlarmFired(const int64_t timestampNs);
 
 private:
     // For testing only.
@@ -125,7 +126,7 @@
     // to retrieve the stored data.
     std::function<void(const ConfigKey& key)> mSendBroadcast;
 
-    const long mTimeBaseSec;
+    const int64_t mTimeBaseNs;
 
     int64_t mLastLogTimestamp;
 
@@ -145,6 +146,12 @@
     FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid);
     FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByChain);
     FRIEND_TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent);
+    FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents);
+    FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm);
+    FRIEND_TEST(GaugeMetricE2eTest, TestAllConditionChangesSamplePulledEvents);
+    FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents);
+    FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm);
+
     FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_NoLink_OR_CombinationCondition);
     FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_Link_OR_CombinationCondition);
     FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_OR_CombinationCondition);
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index d3cda63..86a3a78 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -81,7 +81,7 @@
     StatsPuller::SetUidMap(mUidMap);
     mConfigManager = new ConfigManager();
     mProcessor = new StatsLogProcessor(mUidMap, mAnomalyAlarmMonitor, mPeriodicAlarmMonitor,
-                                       getElapsedRealtimeSec(), [this](const ConfigKey& key) {
+                                       getElapsedRealtimeNs(), [this](const ConfigKey& key) {
         sp<IStatsCompanionService> sc = getStatsCompanionService();
         auto receiver = mConfigManager->GetConfigReceiver(key);
         if (sc == nullptr) {
@@ -745,7 +745,7 @@
                                          "Only system uid can call informPollAlarmFired");
     }
 
-    mStatsPullerManager.OnAlarmFired();
+    mProcessor->informPullAlarmFired(getElapsedRealtimeNs());
 
     VLOG("StatsService::informPollAlarmFired succeeded");
 
diff --git a/cmds/statsd/src/external/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h
index 83d59c0..50ffe17 100644
--- a/cmds/statsd/src/external/StatsPullerManager.h
+++ b/cmds/statsd/src/external/StatsPullerManager.h
@@ -40,8 +40,8 @@
         return mPullerManager.PullerForMatcherExists(tagId);
     }
 
-    void OnAlarmFired() {
-        mPullerManager.OnAlarmFired();
+    void OnAlarmFired(const int64_t currentTimeNs) {
+        mPullerManager.OnAlarmFired(currentTimeNs);
     }
 
     virtual bool Pull(const int tagId, const int64_t timesNs,
diff --git a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
index 2f0e885..610faad 100644
--- a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
+++ b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
@@ -275,11 +275,9 @@
     }
 }
 
-void StatsPullerManagerImpl::OnAlarmFired() {
+void StatsPullerManagerImpl::OnAlarmFired(const int64_t currentTimeNs) {
     AutoMutex _l(mLock);
 
-    int64_t currentTimeNs = getElapsedRealtimeNs();
-
     int64_t minNextPullTimeNs = LONG_MAX;
 
     vector<pair<int, vector<ReceiverInfo*>>> needToPull =
@@ -288,7 +286,7 @@
         vector<ReceiverInfo*> receivers = vector<ReceiverInfo*>();
         if (pair.second.size() != 0) {
             for (ReceiverInfo& receiverInfo : pair.second) {
-                if (receiverInfo.nextPullTimeNs < currentTimeNs) {
+                if (receiverInfo.nextPullTimeNs <= currentTimeNs) {
                     receivers.push_back(&receiverInfo);
                 } else {
                     if (receiverInfo.nextPullTimeNs < minNextPullTimeNs) {
@@ -311,10 +309,9 @@
                     receiverPtr->onDataPulled(data);
                     // we may have just come out of a coma, compute next pull time
                     receiverInfo->nextPullTimeNs =
-                            ceil((double_t)(currentTimeNs - receiverInfo->nextPullTimeNs) /
-                                 receiverInfo->intervalNs) *
-                                    receiverInfo->intervalNs +
-                            receiverInfo->nextPullTimeNs;
+                            (currentTimeNs - receiverInfo->nextPullTimeNs) /
+                                receiverInfo->intervalNs * receiverInfo->intervalNs +
+                            receiverInfo->intervalNs + receiverInfo->nextPullTimeNs;
                     if (receiverInfo->nextPullTimeNs < minNextPullTimeNs) {
                         minNextPullTimeNs = receiverInfo->nextPullTimeNs;
                     }
diff --git a/cmds/statsd/src/external/StatsPullerManagerImpl.h b/cmds/statsd/src/external/StatsPullerManagerImpl.h
index 8c771f3..56d04b4 100644
--- a/cmds/statsd/src/external/StatsPullerManagerImpl.h
+++ b/cmds/statsd/src/external/StatsPullerManagerImpl.h
@@ -58,7 +58,7 @@
     // Verify if we know how to pull for this matcher
     bool PullerForMatcherExists(int tagId) const;
 
-    void OnAlarmFired();
+    void OnAlarmFired(const int64_t timeNs);
 
     bool Pull(const int tagId, const int64_t timeNs, vector<std::shared_ptr<LogEvent>>* data);
 
@@ -90,6 +90,11 @@
     void updateAlarmLocked();
 
     int64_t mNextPullTimeNs;
+
+    FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents);
+    FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm);
+    FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents);
+    FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm);
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index b589d0d..c342aa5 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -395,6 +395,14 @@
     }
 }
 
+string buildTimeString(int64_t timeSec) {
+    time_t t = timeSec;
+    struct tm* tm = localtime(&t);
+    char timeBuffer[80];
+    strftime(timeBuffer, sizeof(timeBuffer), "%Y-%m-%d %I:%M%p\n", tm);
+    return string(timeBuffer);
+}
+
 void StatsdStats::dumpStats(FILE* out) const {
     lock_guard<std::mutex> lock(mLock);
     time_t t = mStartTimeSec;
@@ -437,15 +445,19 @@
         }
 
         for (const auto& broadcastTime : configStats->broadcast_sent_time_sec) {
-            fprintf(out, "\tbroadcast time: %d\n", broadcastTime);
+            fprintf(out, "\tbroadcast time: %s(%lld)\n",
+                    buildTimeString(broadcastTime).c_str(), (long long)broadcastTime);
         }
 
         for (const auto& dataDropTime : configStats->data_drop_time_sec) {
-            fprintf(out, "\tdata drop time: %d\n", dataDropTime);
+            fprintf(out, "\tdata drop time: %s(%lld)\n",
+                    buildTimeString(dataDropTime).c_str(), (long long)dataDropTime);
         }
 
         for (const auto& dump : configStats->dump_report_stats) {
-            fprintf(out, "\tdump report time: %d bytes: %lld\n", dump.first, (long long)dump.second);
+            fprintf(out, "\tdump report time: %s(%lld) bytes: %lld\n",
+                    buildTimeString(dump.first).c_str(), (long long)dump.first,
+                    (long long)dump.second);
         }
 
         for (const auto& stats : pair.second->matcher_stats) {
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index c77e07b..e21392c 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -92,7 +92,7 @@
     mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0);
 
     VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
-         (long long)mBucketSizeNs, (long long)mStartTimeNs);
+         (long long)mBucketSizeNs, (long long)mTimeBaseNs);
 }
 
 CountMetricProducer::~CountMetricProducer() {
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 3125fa7..3661b31 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -122,7 +122,7 @@
         }
     }
     VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
-         (long long)mBucketSizeNs, (long long)mStartTimeNs);
+         (long long)mBucketSizeNs, (long long)mTimeBaseNs);
 }
 
 DurationMetricProducer::~DurationMetricProducer() {
@@ -154,13 +154,13 @@
             return make_unique<OringDurationTracker>(
                     mConfigKey, mMetricId, eventKey, mWizard, mConditionTrackerIndex,
                     mDimensionsInCondition, mNested, mCurrentBucketStartTimeNs, mCurrentBucketNum,
-                    mStartTimeNs, mBucketSizeNs, mConditionSliced,
+                    mTimeBaseNs, mBucketSizeNs, mConditionSliced,
                     mHasLinksToAllConditionDimensionsInTracker, mAnomalyTrackers);
         case DurationMetric_AggregationType_MAX_SPARSE:
             return make_unique<MaxDurationTracker>(
                     mConfigKey, mMetricId, eventKey, mWizard, mConditionTrackerIndex,
                     mDimensionsInCondition, mNested, mCurrentBucketStartTimeNs, mCurrentBucketNum,
-                    mStartTimeNs, mBucketSizeNs, mConditionSliced,
+                    mTimeBaseNs, mBucketSizeNs, mConditionSliced,
                     mHasLinksToAllConditionDimensionsInTracker, mAnomalyTrackers);
     }
 }
@@ -650,7 +650,7 @@
 void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
                                                      const LogEvent& event) {
     int64_t eventTimeNs = event.GetElapsedTimestampNs();
-    if (eventTimeNs < mStartTimeNs) {
+    if (eventTimeNs < mTimeBaseNs) {
         return;
     }
 
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index 33ab9aa..2f2679e 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -68,7 +68,7 @@
     }
     mProto = std::make_unique<ProtoOutputStream>();
     VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
-         (long long)mBucketSizeNs, (long long)mStartTimeNs);
+         (long long)mBucketSizeNs, (long long)mTimeBaseNs);
 }
 
 EventMetricProducer::~EventMetricProducer() {
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 3c77aae..6886f7c 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -61,9 +61,9 @@
 GaugeMetricProducer::GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& metric,
                                          const int conditionIndex,
                                          const sp<ConditionWizard>& wizard, const int pullTagId,
-                                         const int64_t startTimeNs,
+                                         const int64_t timeBaseNs, const int64_t startTimeNs,
                                          shared_ptr<StatsPullerManager> statsPullerManager)
-    : MetricProducer(metric.id(), key, startTimeNs, conditionIndex, wizard),
+    : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, wizard),
       mStatsPullerManager(statsPullerManager),
       mPullTagId(pullTagId),
       mDimensionSoftLimit(StatsdStats::kAtomDimensionKeySizeLimitMap.find(pullTagId) !=
@@ -110,14 +110,15 @@
     }
     mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0);
 
+    flushIfNeededLocked(startTimeNs);
     // Kicks off the puller immediately.
     if (mPullTagId != -1 && mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) {
         mStatsPullerManager->RegisterReceiver(
-                mPullTagId, this, mCurrentBucketStartTimeNs + mBucketSizeNs, mBucketSizeNs);
+                mPullTagId, this, getCurrentBucketEndTimeNs(), mBucketSizeNs);
     }
 
     VLOG("Gauge metric %lld created. bucket size %lld start_time: %lld sliced %d",
-         (long long)metric.id(), (long long)mBucketSizeNs, (long long)mStartTimeNs,
+         (long long)metric.id(), (long long)mBucketSizeNs, (long long)mTimeBaseNs,
          mConditionSliced);
 }
 
@@ -125,14 +126,14 @@
 GaugeMetricProducer::GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& metric,
                                          const int conditionIndex,
                                          const sp<ConditionWizard>& wizard, const int pullTagId,
-                                         const int64_t startTimeNs)
-    : GaugeMetricProducer(key, metric, conditionIndex, wizard, pullTagId, startTimeNs,
+                                         const int64_t timeBaseNs, const int64_t startTimeNs)
+    : GaugeMetricProducer(key, metric, conditionIndex, wizard, pullTagId, timeBaseNs, startTimeNs,
                           make_shared<StatsPullerManager>()) {
 }
 
 GaugeMetricProducer::~GaugeMetricProducer() {
     VLOG("~GaugeMetricProducer() called");
-    if (mPullTagId != -1) {
+    if (mPullTagId != -1 && mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) {
         mStatsPullerManager->UnRegisterReceiver(mPullTagId, this);
     }
 }
@@ -214,18 +215,20 @@
                         android::util::AtomsInfo::kNotTruncatingTimestampAtomWhiteList.find(
                                 mTagId) ==
                         android::util::AtomsInfo::kNotTruncatingTimestampAtomWhiteList.end();
-                const int64_t wall_clock_ns = truncateTimestamp ?
-                    truncateTimestampNsToFiveMinutes(getWallClockNs()) : getWallClockNs();
                 for (const auto& atom : bucket.mGaugeAtoms) {
-                    int64_t timestampNs =  truncateTimestamp ?
-                        truncateTimestampNsToFiveMinutes(atom.mTimestamps) : atom.mTimestamps;
+                    const int64_t elapsedTimestampNs =  truncateTimestamp ?
+                        truncateTimestampNsToFiveMinutes(atom.mElapsedTimestamps) :
+                            atom.mElapsedTimestamps;
+                    const int64_t wallClockNs = truncateTimestamp ?
+                        truncateTimestampNsToFiveMinutes(atom.mWallClockTimestampNs) :
+                            atom.mWallClockTimestampNs;
                     protoOutput->write(
                         FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_ELAPSED_ATOM_TIMESTAMP,
-                        (long long)timestampNs);
+                        (long long)elapsedTimestampNs);
                     protoOutput->write(
                         FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED |
                             FIELD_ID_WALL_CLOCK_ATOM_TIMESTAMP,
-                        (long long)wall_clock_ns);
+                        (long long)wallClockNs);
                 }
             }
             protoOutput->end(bucketInfoToken);
@@ -241,7 +244,7 @@
     // TODO: Clear mDimensionKeyMap once the report is dumped.
 }
 
-void GaugeMetricProducer::pullLocked() {
+void GaugeMetricProducer::pullLocked(const int64_t timestampNs) {
     bool triggerPuller = false;
     switch(mSamplingType) {
         // When the metric wants to do random sampling and there is already one gauge atom for the
@@ -262,7 +265,7 @@
     }
 
     vector<std::shared_ptr<LogEvent>> allData;
-    if (!mStatsPullerManager->Pull(mPullTagId, getElapsedRealtimeNs(), &allData)) {
+    if (!mStatsPullerManager->Pull(mPullTagId, timestampNs, &allData)) {
         ALOGE("Gauge Stats puller failed for tag: %d", mPullTagId);
         return;
     }
@@ -273,26 +276,26 @@
 }
 
 void GaugeMetricProducer::onConditionChangedLocked(const bool conditionMet,
-                                                   const int64_t eventTime) {
+                                                   const int64_t eventTimeNs) {
     VLOG("GaugeMetric %lld onConditionChanged", (long long)mMetricId);
-    flushIfNeededLocked(eventTime);
+    flushIfNeededLocked(eventTimeNs);
     mCondition = conditionMet;
 
-    if (mPullTagId != -1) {
-        pullLocked();
+    if (mPullTagId != -1 && mCondition) {
+        pullLocked(eventTimeNs);
     }  // else: Push mode. No need to proactively pull the gauge data.
 }
 
 void GaugeMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondition,
-                                                           const int64_t eventTime) {
+                                                           const int64_t eventTimeNs) {
     VLOG("GaugeMetric %lld onSlicedConditionMayChange overall condition %d", (long long)mMetricId,
          overallCondition);
-    flushIfNeededLocked(eventTime);
+    flushIfNeededLocked(eventTimeNs);
     // If the condition is sliced, mCondition is true if any of the dimensions is true. And we will
     // pull for every dimension.
     mCondition = overallCondition;
     if (mPullTagId != -1) {
-        pullLocked();
+        pullLocked(eventTimeNs);
     }  // else: Push mode. No need to proactively pull the gauge data.
 }
 
@@ -360,7 +363,7 @@
     if (hitGuardRailLocked(eventKey)) {
         return;
     }
-    GaugeAtom gaugeAtom(getGaugeFields(event), eventTimeNs);
+    GaugeAtom gaugeAtom(getGaugeFields(event), eventTimeNs, getWallClockNs());
     (*mCurrentSlicedBucket)[eventKey].push_back(gaugeAtom);
     // Anomaly detection on gauge metric only works when there is one numeric
     // field specified.
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index 04b7df9..08765c2 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -33,11 +33,12 @@
 namespace statsd {
 
 struct GaugeAtom {
-    GaugeAtom(std::shared_ptr<vector<FieldValue>> fields, int64_t timeNs)
-        : mFields(fields), mTimestamps(timeNs) {
+    GaugeAtom(std::shared_ptr<vector<FieldValue>> fields, int64_t elapsedTimeNs, int wallClockNs)
+        : mFields(fields), mElapsedTimestamps(elapsedTimeNs), mWallClockTimestampNs(wallClockNs) {
     }
     std::shared_ptr<vector<FieldValue>> mFields;
-    int64_t mTimestamps;
+    int64_t mElapsedTimestamps;
+    int64_t mWallClockTimestampNs;
 };
 
 struct GaugeBucket {
@@ -57,7 +58,7 @@
 public:
     GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& gaugeMetric,
                         const int conditionIndex, const sp<ConditionWizard>& wizard,
-                        const int pullTagId, const int64_t startTimeNs);
+                        const int pullTagId, const int64_t timeBaseNs, const int64_t startTimeNs);
 
     virtual ~GaugeMetricProducer();
 
@@ -76,7 +77,7 @@
         flushCurrentBucketLocked(eventTimeNs);
         mCurrentBucketStartTimeNs = eventTimeNs;
         if (mPullTagId != -1) {
-            pullLocked();
+            pullLocked(eventTimeNs);
         }
     };
 
@@ -94,7 +95,8 @@
     // for testing
     GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& gaugeMetric,
                         const int conditionIndex, const sp<ConditionWizard>& wizard,
-                        const int pullTagId, const int64_t startTimeNs,
+                        const int pullTagId,
+                        const int64_t timeBaseNs, const int64_t startTimeNs,
                         std::shared_ptr<StatsPullerManager> statsPullerManager);
 
     // Internal interface to handle condition change.
@@ -115,7 +117,7 @@
 
     void flushCurrentBucketLocked(const int64_t& eventTimeNs) override;
 
-    void pullLocked();
+    void pullLocked(const int64_t timestampNs);
 
     int mTagId;
 
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index bcf0e62..5ff8082 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -27,7 +27,7 @@
 void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event) {
     int64_t eventTimeNs = event.GetElapsedTimestampNs();
     // this is old event, maybe statsd restarted?
-    if (eventTimeNs < mStartTimeNs) {
+    if (eventTimeNs < mTimeBaseNs) {
         return;
     }
 
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index f931e57..532ecbf 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -40,12 +40,12 @@
 // be a no-op.
 class MetricProducer : public virtual PackageInfoListener {
 public:
-    MetricProducer(const int64_t& metricId, const ConfigKey& key, const int64_t startTimeNs,
+    MetricProducer(const int64_t& metricId, const ConfigKey& key, const int64_t timeBaseNs,
                    const int conditionIndex, const sp<ConditionWizard>& wizard)
         : mMetricId(metricId),
           mConfigKey(key),
-          mStartTimeNs(startTimeNs),
-          mCurrentBucketStartTimeNs(startTimeNs),
+          mTimeBaseNs(timeBaseNs),
+          mCurrentBucketStartTimeNs(timeBaseNs),
           mCurrentBucketNum(0),
           mCondition(conditionIndex >= 0 ? false : true),
           mConditionSliced(false),
@@ -165,6 +165,11 @@
         dropDataLocked(dropTimeNs);
     }
 
+    // For test only.
+    inline int64_t getCurrentBucketNum() const {
+        return mCurrentBucketNum;
+    }
+
 protected:
     virtual void onConditionChangedLocked(const bool condition, const int64_t eventTime) = 0;
     virtual void onSlicedConditionMayChangeLocked(bool overallCondition,
@@ -204,7 +209,7 @@
     // Convenience to compute the current bucket's end time, which is always aligned with the
     // start time of the metric.
     int64_t getCurrentBucketEndTimeNs() const {
-        return mStartTimeNs + (mCurrentBucketNum + 1) * mBucketSizeNs;
+        return mTimeBaseNs + (mCurrentBucketNum + 1) * mBucketSizeNs;
     }
 
     virtual void dropDataLocked(const int64_t dropTimeNs) = 0;
@@ -215,7 +220,7 @@
 
     // The time when this metric producer was first created. The end time for the current bucket
     // can be computed from this based on mCurrentBucketNum.
-    int64_t mStartTimeNs;
+    int64_t mTimeBaseNs;
 
     // Start time may not be aligned with the start of statsd if there is an app upgrade in the
     // middle of a bucket.
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index b7f1bd5..47a1a86 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -54,21 +54,21 @@
 const int FIELD_ID_ANNOTATIONS_INT32 = 2;
 
 MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
-                               const long timeBaseSec, const long currentTimeSec,
+                               const int64_t timeBaseNs, const int64_t currentTimeNs,
                                const sp<UidMap> &uidMap,
                                const sp<AlarmMonitor>& anomalyAlarmMonitor,
                                const sp<AlarmMonitor>& periodicAlarmMonitor)
     : mConfigKey(key), mUidMap(uidMap),
       mTtlNs(config.has_ttl_in_seconds() ? config.ttl_in_seconds() * NS_PER_SEC : -1),
       mTtlEndNs(-1),
-      mLastReportTimeNs(timeBaseSec * NS_PER_SEC),
+      mLastReportTimeNs(timeBaseNs),
       mLastReportWallClockNs(getWallClockNs()) {
     // Init the ttl end timestamp.
-    refreshTtl(timeBaseSec * NS_PER_SEC);
+    refreshTtl(timeBaseNs);
 
     mConfigValid =
             initStatsdConfig(key, config, *uidMap, anomalyAlarmMonitor, periodicAlarmMonitor,
-                             timeBaseSec, currentTimeSec, mTagIds, mAllAtomMatchers,
+                             timeBaseNs, currentTimeNs, mTagIds, mAllAtomMatchers,
                              mAllConditionTrackers, mAllMetricProducers, mAllAnomalyTrackers,
                              mAllPeriodicAlarmTrackers, mConditionToMetricMap, mTrackerToMetricMap,
                              mTrackerToConditionMap, mNoReportMetricIds);
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 6aa260a..3d2c595 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -37,7 +37,7 @@
 class MetricsManager : public PackageInfoListener {
 public:
     MetricsManager(const ConfigKey& configKey, const StatsdConfig& config,
-                   const long timeBaseSec, const long currentTimeSec,
+                   const int64_t timeBaseNs, const int64_t currentTimeNs,
                    const sp<UidMap>& uidMap, const sp<AlarmMonitor>& anomalyAlarmMonitor,
                    const sp<AlarmMonitor>& periodicAlarmMonitor);
 
@@ -187,6 +187,11 @@
     FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid);
     FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByChain);
     FRIEND_TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent);
+    FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents);
+    FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm);
+    FRIEND_TEST(GaugeMetricE2eTest, TestAllConditionChangesSamplePulledEvents);
+    FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents);
+    FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm);
     FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_NoLink_OR_CombinationCondition);
     FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_Link_OR_CombinationCondition);
     FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_OR_CombinationCondition);
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 89efae3..844c728 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -63,9 +63,9 @@
 ValueMetricProducer::ValueMetricProducer(const ConfigKey& key, const ValueMetric& metric,
                                          const int conditionIndex,
                                          const sp<ConditionWizard>& wizard, const int pullTagId,
-                                         const int64_t startTimeNs,
+                                         const int64_t timeBaseNs, const int64_t startTimestampNs,
                                          shared_ptr<StatsPullerManager> statsPullerManager)
-    : MetricProducer(metric.id(), key, startTimeNs, conditionIndex, wizard),
+    : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, wizard),
       mValueField(metric.value_field()),
       mStatsPullerManager(statsPullerManager),
       mPullTagId(pullTagId),
@@ -105,27 +105,28 @@
         }
     }
 
-    if (mValueField.child_size()) {
+    if (mValueField.child_size() > 0) {
         mField = mValueField.child(0).field();
     }
     mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0);
 
     // Kicks off the puller immediately.
+    flushIfNeededLocked(startTimestampNs);
     if (mPullTagId != -1) {
         mStatsPullerManager->RegisterReceiver(
             mPullTagId, this, mCurrentBucketStartTimeNs + mBucketSizeNs, mBucketSizeNs);
     }
 
     VLOG("value metric %lld created. bucket size %lld start_time: %lld",
-        (long long)metric.id(), (long long)mBucketSizeNs, (long long)mStartTimeNs);
+        (long long)metric.id(), (long long)mBucketSizeNs, (long long)mTimeBaseNs);
 }
 
 // for testing
 ValueMetricProducer::ValueMetricProducer(const ConfigKey& key, const ValueMetric& metric,
                                          const int conditionIndex,
                                          const sp<ConditionWizard>& wizard, const int pullTagId,
-                                         const int64_t startTimeNs)
-    : ValueMetricProducer(key, metric, conditionIndex, wizard, pullTagId, startTimeNs,
+                                         const int64_t timeBaseNs, const int64_t startTimeNs)
+    : ValueMetricProducer(key, metric, conditionIndex, wizard, pullTagId, timeBaseNs, startTimeNs,
                           make_shared<StatsPullerManager>()) {
 }
 
@@ -198,7 +199,6 @@
 
     VLOG("metric %lld dump report now...", (long long)mMetricId);
     mPastBuckets.clear();
-    // TODO: Clear mDimensionKeyMap once the report is dumped.
 }
 
 void ValueMetricProducer::onConditionChangedLocked(const bool condition,
@@ -237,8 +237,8 @@
         // For scheduled pulled data, the effective event time is snap to the nearest
         // bucket boundary to make bucket finalize.
         int64_t realEventTime = allData.at(0)->GetElapsedTimestampNs();
-        int64_t eventTime = mStartTimeNs +
-            ((realEventTime - mStartTimeNs) / mBucketSizeNs) * mBucketSizeNs;
+        int64_t eventTime = mTimeBaseNs +
+            ((realEventTime - mTimeBaseNs) / mBucketSizeNs) * mBucketSizeNs;
 
         mCondition = false;
         for (const auto& data : allData) {
@@ -310,7 +310,7 @@
     Interval& interval = mCurrentSlicedBucket[eventKey];
 
     int error = 0;
-    const long value = event.GetLong(mField, &error);
+    const int64_t value = event.GetLong(mField, &error);
     if (error < 0) {
         return;
     }
@@ -337,7 +337,7 @@
                 interval.hasValue = true;
                 interval.startUpdated = false;
             } else {
-                VLOG("No start for matching end %ld", value);
+                VLOG("No start for matching end %lld", (long long)value);
                 interval.tainted += 1;
             }
         }
@@ -359,7 +359,7 @@
 void ValueMetricProducer::flushIfNeededLocked(const int64_t& eventTimeNs) {
     int64_t currentBucketEndTimeNs = getCurrentBucketEndTimeNs();
 
-    if (currentBucketEndTimeNs > eventTimeNs) {
+    if (eventTimeNs < currentBucketEndTimeNs) {
         VLOG("eventTime is %lld, less than next bucket start time %lld", (long long)eventTimeNs,
              (long long)(currentBucketEndTimeNs));
         return;
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index b19adbe..9c5a56c 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -40,7 +40,7 @@
 public:
     ValueMetricProducer(const ConfigKey& key, const ValueMetric& valueMetric,
                         const int conditionIndex, const sp<ConditionWizard>& wizard,
-                        const int pullTagId, const int64_t startTimeNs);
+                        const int pullTagId, const int64_t timeBaseNs, const int64_t startTimeNs);
 
     virtual ~ValueMetricProducer();
 
@@ -115,7 +115,7 @@
     // for testing
     ValueMetricProducer(const ConfigKey& key, const ValueMetric& valueMetric,
                         const int conditionIndex, const sp<ConditionWizard>& wizard,
-                        const int pullTagId, const int64_t startTimeNs,
+                        const int pullTagId, const int64_t timeBaseNs, const int64_t startTimeNs,
                         std::shared_ptr<StatsPullerManager> statsPullerManager);
 
     // tagId for pulled data. -1 if this is not pulled
@@ -127,14 +127,14 @@
     typedef struct {
         // Pulled data always come in pair of <start, end>. This holds the value
         // for start. The diff (end - start) is added to sum.
-        long start;
+        int64_t start;
         // Whether the start data point is updated
         bool startUpdated;
         // If end data point comes before the start, record this pair as tainted
         // and the value is not added to the running sum.
         int tainted;
         // Running sum of known pairs in this bucket
-        long sum;
+        int64_t sum;
         // If this dimension has any non-tainted value. If not, don't report the
         // dimension.
         bool hasValue;
@@ -142,7 +142,7 @@
 
     std::unordered_map<MetricDimensionKey, Interval> mCurrentSlicedBucket;
 
-    std::unordered_map<MetricDimensionKey, long> mCurrentFullBucket;
+    std::unordered_map<MetricDimensionKey, int64_t> mCurrentFullBucket;
 
     // Save the past buckets and we can clear when the StatsLogReport is dumped.
     // TODO: Add a lock to mPastBuckets.
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 566d34e..811a00e 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -262,7 +262,8 @@
     return true;
 }
 
-bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const long timeBaseSec,
+bool initMetrics(const ConfigKey& key, const StatsdConfig& config,
+                 const int64_t timeBaseTimeNs, const int64_t currentTimeNs,
                  UidMap& uidMap, const unordered_map<int64_t, int>& logTrackerMap,
                  const unordered_map<int64_t, int>& conditionTrackerMap,
                  const vector<sp<LogMatchingTracker>>& allAtomMatchers,
@@ -277,8 +278,6 @@
     allMetricProducers.reserve(allMetricsCount);
     StatsPullerManager statsPullerManager;
 
-    uint64_t startTimeNs = timeBaseSec * NS_PER_SEC;
-
     // Build MetricProducers for each metric defined in config.
     // build CountMetricProducer
     for (int i = 0; i < config.count_metric_size(); i++) {
@@ -314,7 +313,7 @@
         }
 
         sp<MetricProducer> countProducer =
-                new CountMetricProducer(key, metric, conditionIndex, wizard, startTimeNs);
+                new CountMetricProducer(key, metric, conditionIndex, wizard, timeBaseTimeNs);
         allMetricProducers.push_back(countProducer);
     }
 
@@ -384,7 +383,7 @@
 
         sp<MetricProducer> durationMetric = new DurationMetricProducer(
                 key, metric, conditionIndex, trackerIndices[0], trackerIndices[1],
-                trackerIndices[2], nesting, wizard, internalDimensions, startTimeNs);
+                trackerIndices[2], nesting, wizard, internalDimensions, timeBaseTimeNs);
 
         allMetricProducers.push_back(durationMetric);
     }
@@ -420,7 +419,7 @@
         }
 
         sp<MetricProducer> eventMetric =
-                new EventMetricProducer(key, metric, conditionIndex, wizard, startTimeNs);
+                new EventMetricProducer(key, metric, conditionIndex, wizard, timeBaseTimeNs);
 
         allMetricProducers.push_back(eventMetric);
     }
@@ -467,7 +466,8 @@
         }
 
         sp<MetricProducer> valueProducer = new ValueMetricProducer(key, metric, conditionIndex,
-                                                                   wizard, pullTagId, startTimeNs);
+                                                                   wizard, pullTagId,
+                                                                   timeBaseTimeNs, currentTimeNs);
         allMetricProducers.push_back(valueProducer);
     }
 
@@ -526,7 +526,7 @@
         }
 
         sp<MetricProducer> gaugeProducer = new GaugeMetricProducer(
-                key, metric, conditionIndex, wizard, pullTagId, startTimeNs);
+                key, metric, conditionIndex, wizard, pullTagId, timeBaseTimeNs, currentTimeNs);
         allMetricProducers.push_back(gaugeProducer);
     }
     for (int i = 0; i < config.no_report_metric_size(); ++i) {
@@ -601,11 +601,11 @@
 
 bool initAlarms(const StatsdConfig& config, const ConfigKey& key,
                 const sp<AlarmMonitor>& periodicAlarmMonitor,
-                const long timeBaseSec, const long currentTimeSec,
+                const int64_t timeBaseNs, const int64_t currentTimeNs,
                 vector<sp<AlarmTracker>>& allAlarmTrackers) {
     unordered_map<int64_t, int> alarmTrackerMap;
-    uint64_t startMillis = (uint64_t)timeBaseSec * MS_PER_SEC;
-    uint64_t currentTimeMillis = (uint64_t)currentTimeSec * MS_PER_SEC;
+    int64_t startMillis = timeBaseNs / 1000 / 1000;
+    int64_t currentTimeMillis = currentTimeNs / 1000 /1000;
     for (int i = 0; i < config.alarm_size(); i++) {
         const Alarm& alarm = config.alarm(i);
         if (alarm.offset_millis() <= 0) {
@@ -646,8 +646,9 @@
 
 bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap& uidMap,
                       const sp<AlarmMonitor>& anomalyAlarmMonitor,
-                      const sp<AlarmMonitor>& periodicAlarmMonitor, const long timeBaseSec,
-                      const long currentTimeSec, set<int>& allTagIds,
+                      const sp<AlarmMonitor>& periodicAlarmMonitor,
+                      const int64_t timeBaseNs, const int64_t currentTimeNs,
+                      set<int>& allTagIds,
                       vector<sp<LogMatchingTracker>>& allAtomMatchers,
                       vector<sp<ConditionTracker>>& allConditionTrackers,
                       vector<sp<MetricProducer>>& allMetricProducers,
@@ -673,7 +674,8 @@
         return false;
     }
 
-    if (!initMetrics(key, config, timeBaseSec, uidMap, logTrackerMap, conditionTrackerMap,
+    if (!initMetrics(key, config, timeBaseNs, currentTimeNs, uidMap,
+                     logTrackerMap, conditionTrackerMap,
                      allAtomMatchers, allConditionTrackers, allMetricProducers,
                      conditionToMetricMap, trackerToMetricMap, metricProducerMap,
                      noReportMetricIds)) {
@@ -686,7 +688,7 @@
         return false;
     }
     if (!initAlarms(config, key, periodicAlarmMonitor,
-                    timeBaseSec, currentTimeSec, allPeriodicAlarmTrackers)) {
+                    timeBaseNs, currentTimeNs, allPeriodicAlarmTrackers)) {
         ALOGE("initAlarms failed");
         return false;
     }
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h
index 0ebdcf9..d749bf4 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.h
+++ b/cmds/statsd/src/metrics/metrics_manager_util.h
@@ -81,7 +81,9 @@
 //                          the list of MetricProducer index
 // [trackerToMetricMap]: contains the mapping from log tracker to MetricProducer index.
 bool initMetrics(
-        const ConfigKey& key, const StatsdConfig& config, const long timeBaseSec, UidMap& uidMap,
+        const ConfigKey& key, const StatsdConfig& config,
+        const int64_t timeBaseTimeNs, const int64_t currentTimeNs,
+        UidMap& uidMap,
         const std::unordered_map<int64_t, int>& logTrackerMap,
         const std::unordered_map<int64_t, int>& conditionTrackerMap,
         const std::unordered_map<int, std::vector<MetricConditionLink>>& eventConditionLinks,
@@ -96,8 +98,9 @@
 // Parameters are the members of MetricsManager. See MetricsManager for declaration.
 bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap& uidMap,
                       const sp<AlarmMonitor>& anomalyAlarmMonitor,
-                      const sp<AlarmMonitor>& periodicAlarmMonitor, const long timeBaseSec,
-                      const long currentTimeSec, std::set<int>& allTagIds,
+                      const sp<AlarmMonitor>& periodicAlarmMonitor,
+                      const int64_t timeBaseNs, const int64_t currentTimeNs,
+                      std::set<int>& allTagIds,
                       std::vector<sp<LogMatchingTracker>>& allAtomMatchers,
                       std::vector<sp<ConditionTracker>>& allConditionTrackers,
                       std::vector<sp<MetricProducer>>& allMetricProducers,
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 36b24c8..4f7581d 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -97,9 +97,9 @@
 }
 
 message GaugeBucketInfo {
-  optional int64 start_bucket_nanos = 1;
+  optional int64 start_bucket_elapsed_nanos = 1;
 
-  optional int64 end_bucket_nanos = 2;
+  optional int64 end_bucket_elapsed_nanos = 2;
 
   repeated Atom atom = 3;
 
diff --git a/cmds/statsd/tests/e2e/Alarm_e2e_test.cpp b/cmds/statsd/tests/e2e/Alarm_e2e_test.cpp
index 73c4e7b..9ea0b81 100644
--- a/cmds/statsd/tests/e2e/Alarm_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Alarm_e2e_test.cpp
@@ -51,7 +51,7 @@
     int64_t bucketStartTimeNs = 10000000000;
 
     ConfigKey cfgKey;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
     EXPECT_EQ(2u, processor->mMetricsManagers.begin()->second->mAllPeriodicAlarmTrackers.size());
diff --git a/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp b/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp
index 93ecde5..c78d99e 100644
--- a/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp
@@ -65,7 +65,7 @@
         TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
 
     ConfigKey cfgKey;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
     EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
@@ -168,7 +168,7 @@
         TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
 
     ConfigKey cfgKey;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
     EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
diff --git a/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp b/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp
index e924b03..50da9e2 100644
--- a/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp
@@ -101,7 +101,7 @@
         TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
 
     ConfigKey cfgKey;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
     EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
@@ -278,7 +278,7 @@
         TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
 
     ConfigKey cfgKey;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
     EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
@@ -391,7 +391,7 @@
     config.mutable_alert(0)->set_refractory_period_secs(refractory_period_sec);
 
     ConfigKey cfgKey;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
     EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
diff --git a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
index 4dd0da8..4f035be 100644
--- a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
@@ -62,7 +62,7 @@
         TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
 
     ConfigKey cfgKey;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
 
@@ -204,7 +204,7 @@
         TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
 
     ConfigKey cfgKey;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
 
diff --git a/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp b/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp
index bb3ad64..b98dc60 100644
--- a/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp
@@ -68,7 +68,7 @@
         TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
 
     ConfigKey cfgKey;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
 
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
index eb57d470..0758fd0 100644
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
@@ -90,7 +90,7 @@
                     TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
 
             auto processor = CreateStatsLogProcessor(
-                    bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+                    bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
             EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
             EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
 
@@ -404,7 +404,7 @@
                     TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
 
             auto processor = CreateStatsLogProcessor(
-                    bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+                    bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
             EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
             EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
 
@@ -648,7 +648,7 @@
                 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
 
         auto processor = CreateStatsLogProcessor(
-                bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+                bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
         EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
         EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
 
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp
index 9729a2e..e74be1e 100644
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp
@@ -75,7 +75,7 @@
     int64_t bucketSizeNs =
             TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
 
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
 
@@ -283,7 +283,7 @@
     int64_t bucketSizeNs =
             TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
 
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
     std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"),
@@ -465,7 +465,8 @@
         int64_t bucketSizeNs =
                 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
 
-        auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+        auto processor = CreateStatsLogProcessor(
+                bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
         EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
         EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
 
@@ -666,7 +667,8 @@
         int64_t bucketSizeNs =
                 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
 
-        auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+        auto processor = CreateStatsLogProcessor(
+                bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
         EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
         EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
 
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
index 4e2c36e..c32048b 100644
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
@@ -80,7 +80,7 @@
                     TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
 
             auto processor = CreateStatsLogProcessor(
-                    bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+                    bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
             EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
             EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
 
@@ -363,7 +363,7 @@
                     TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
 
             auto processor = CreateStatsLogProcessor(
-                    bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+                    bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
             EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
             EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
 
@@ -582,7 +582,7 @@
                 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
 
         auto processor = CreateStatsLogProcessor(
-                bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+                bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
         EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
         EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
 
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
new file mode 100644
index 0000000..9561fcf4
--- /dev/null
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
@@ -0,0 +1,396 @@
+// Copyright (C) 2017 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 <gtest/gtest.h>
+
+#include "src/StatsLogProcessor.h"
+#include "src/stats_log_util.h"
+#include "tests/statsd_test_util.h"
+
+#include <vector>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+#ifdef __ANDROID__
+
+namespace {
+
+StatsdConfig CreateStatsdConfig(const GaugeMetric::SamplingType sampling_type) {
+    StatsdConfig config;
+    config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+    auto temperatureAtomMatcher = CreateTemperatureAtomMatcher();
+    *config.add_atom_matcher() = temperatureAtomMatcher;
+    *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
+    *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
+
+    auto screenIsOffPredicate = CreateScreenIsOffPredicate();
+    *config.add_predicate() = screenIsOffPredicate;
+
+    auto gaugeMetric = config.add_gauge_metric();
+    gaugeMetric->set_id(123456);
+    gaugeMetric->set_what(temperatureAtomMatcher.id());
+    gaugeMetric->set_condition(screenIsOffPredicate.id());
+    gaugeMetric->set_sampling_type(sampling_type);
+    gaugeMetric->mutable_gauge_fields_filter()->set_include_all(true);
+    *gaugeMetric->mutable_dimensions_in_what() =
+        CreateDimensions(android::util::TEMPERATURE, {2/* sensor name field */ });
+    gaugeMetric->set_bucket(FIVE_MINUTES);
+
+    return config;
+}
+
+}  // namespace
+
+TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents) {
+    auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE);
+    int64_t baseTimeNs = 10 * NS_PER_SEC;
+    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
+    int64_t bucketSizeNs =
+        TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
+
+    ConfigKey cfgKey;
+    auto processor = CreateStatsLogProcessor(
+        baseTimeNs, configAddedTimeNs, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+    int startBucketNum = processor->mMetricsManagers.begin()->second->
+            mAllMetricProducers[0]->getCurrentBucketNum();
+    EXPECT_GT(startBucketNum, (int64_t)0);
+
+    // When creating the config, the gauge metric producer should register the alarm at the
+    // end of the current bucket.
+    EXPECT_EQ((size_t)1, StatsPullerManagerImpl::GetInstance().mReceivers.size());
+    EXPECT_EQ(bucketSizeNs,
+              StatsPullerManagerImpl::GetInstance().mReceivers.begin()->
+                    second.front().intervalNs);
+    int64_t& nextPullTimeNs = StatsPullerManagerImpl::GetInstance().mReceivers.begin()->
+            second.front().nextPullTimeNs;
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs);
+
+    auto screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+                                                        configAddedTimeNs + 55);
+    processor->OnLogEvent(screenOffEvent.get());
+
+    // Pulling alarm arrives on time and reset the sequential pulling alarm.
+    processor->informPullAlarmFired(nextPullTimeNs + 1);
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, nextPullTimeNs);
+
+    auto screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+                                                       configAddedTimeNs + bucketSizeNs + 10);
+    processor->OnLogEvent(screenOnEvent.get());
+
+    screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+                                                   configAddedTimeNs + bucketSizeNs + 100);
+    processor->OnLogEvent(screenOffEvent.get());
+
+    processor->informPullAlarmFired(nextPullTimeNs + 1);
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs,
+              nextPullTimeNs);
+
+    processor->informPullAlarmFired(nextPullTimeNs + 1);
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, nextPullTimeNs);
+
+    screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+                                                  configAddedTimeNs + 3 * bucketSizeNs + 2);
+    processor->OnLogEvent(screenOnEvent.get());
+
+    processor->informPullAlarmFired(nextPullTimeNs + 3);
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs);
+
+    screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+                                                  configAddedTimeNs + 5 * bucketSizeNs + 1);
+    processor->OnLogEvent(screenOffEvent.get());
+
+    processor->informPullAlarmFired(nextPullTimeNs + 2);
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, nextPullTimeNs);
+
+    processor->informPullAlarmFired(nextPullTimeNs + 2);
+
+    ConfigMetricsReportList reports;
+    vector<uint8_t> buffer;
+    processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, &buffer);
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
+    sortMetricDataByDimensionsValue(
+            reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
+    EXPECT_GT((int)gaugeMetrics.data_size(), 1);
+
+    auto data = gaugeMetrics.data(0);
+    EXPECT_EQ(android::util::TEMPERATURE, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(2 /* sensor name field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
+    EXPECT_EQ(6, data.bucket_info_size());
+
+    EXPECT_EQ(1, data.bucket_info(0).atom_size());
+    EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
+    EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(1, data.bucket_info(0).wall_clock_timestamp_nanos_size());
+    EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+    EXPECT_FALSE(data.bucket_info(0).atom(0).temperature().sensor_name().empty());
+    EXPECT_GT(data.bucket_info(0).atom(0).temperature().temperature_dc(), 0);
+
+    EXPECT_EQ(1, data.bucket_info(1).atom_size());
+    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 1,
+              data.bucket_info(1).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
+    EXPECT_FALSE(data.bucket_info(1).atom(0).temperature().sensor_name().empty());
+    EXPECT_GT(data.bucket_info(1).atom(0).temperature().temperature_dc(), 0);
+
+    EXPECT_EQ(1, data.bucket_info(2).atom_size());
+    EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
+    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs + 1,
+              data.bucket_info(2).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
+    EXPECT_FALSE(data.bucket_info(2).atom(0).temperature().sensor_name().empty());
+    EXPECT_GT(data.bucket_info(2).atom(0).temperature().temperature_dc(), 0);
+
+    EXPECT_EQ(1, data.bucket_info(3).atom_size());
+    EXPECT_EQ(1, data.bucket_info(3).elapsed_timestamp_nanos_size());
+    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs + 1,
+              data.bucket_info(3).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(3).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(3).end_bucket_elapsed_nanos());
+    EXPECT_FALSE(data.bucket_info(3).atom(0).temperature().sensor_name().empty());
+    EXPECT_GT(data.bucket_info(3).atom(0).temperature().temperature_dc(), 0);
+
+    EXPECT_EQ(1, data.bucket_info(4).atom_size());
+    EXPECT_EQ(1, data.bucket_info(4).elapsed_timestamp_nanos_size());
+    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 1,
+              data.bucket_info(4).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(4).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(4).end_bucket_elapsed_nanos());
+    EXPECT_FALSE(data.bucket_info(4).atom(0).temperature().sensor_name().empty());
+    EXPECT_GT(data.bucket_info(4).atom(0).temperature().temperature_dc(), 0);
+
+    EXPECT_EQ(1, data.bucket_info(5).atom_size());
+    EXPECT_EQ(1, data.bucket_info(5).elapsed_timestamp_nanos_size());
+    EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs + 2,
+              data.bucket_info(5).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(5).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(5).end_bucket_elapsed_nanos());
+    EXPECT_FALSE(data.bucket_info(5).atom(0).temperature().sensor_name().empty());
+    EXPECT_GT(data.bucket_info(5).atom(0).temperature().temperature_dc(), 0);
+}
+
+TEST(GaugeMetricE2eTest, TestAllConditionChangesSamplePulledEvents) {
+    auto config = CreateStatsdConfig(GaugeMetric::ALL_CONDITION_CHANGES);
+    int64_t baseTimeNs = 10 * NS_PER_SEC;
+    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
+    int64_t bucketSizeNs =
+        TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
+
+    ConfigKey cfgKey;
+    auto processor = CreateStatsLogProcessor(
+        baseTimeNs, configAddedTimeNs, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+    int startBucketNum = processor->mMetricsManagers.begin()->second->
+            mAllMetricProducers[0]->getCurrentBucketNum();
+    EXPECT_GT(startBucketNum, (int64_t)0);
+
+    auto screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+                                                        configAddedTimeNs + 55);
+    processor->OnLogEvent(screenOffEvent.get());
+
+    auto screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+                                                       configAddedTimeNs + bucketSizeNs + 10);
+    processor->OnLogEvent(screenOnEvent.get());
+
+    screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+                                                   configAddedTimeNs + bucketSizeNs + 100);
+    processor->OnLogEvent(screenOffEvent.get());
+
+    screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+                                                  configAddedTimeNs + 3 * bucketSizeNs + 2);
+    processor->OnLogEvent(screenOnEvent.get());
+
+    screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+                                                  configAddedTimeNs + 5 * bucketSizeNs + 1);
+    processor->OnLogEvent(screenOffEvent.get());
+    screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+                                                  configAddedTimeNs + 5 * bucketSizeNs + 3);
+    processor->OnLogEvent(screenOnEvent.get());
+    screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+                                                  configAddedTimeNs + 5 * bucketSizeNs + 10);
+    processor->OnLogEvent(screenOffEvent.get());
+
+    ConfigMetricsReportList reports;
+    vector<uint8_t> buffer;
+    processor->onDumpReport(cfgKey, configAddedTimeNs + 8 * bucketSizeNs + 10, false, &buffer);
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
+    sortMetricDataByDimensionsValue(
+            reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
+    EXPECT_GT((int)gaugeMetrics.data_size(), 1);
+
+    auto data = gaugeMetrics.data(0);
+    EXPECT_EQ(android::util::TEMPERATURE, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(2 /* sensor name field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
+    EXPECT_EQ(3, data.bucket_info_size());
+
+    EXPECT_EQ(1, data.bucket_info(0).atom_size());
+    EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
+    EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(1, data.bucket_info(0).wall_clock_timestamp_nanos_size());
+    EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+    EXPECT_FALSE(data.bucket_info(0).atom(0).temperature().sensor_name().empty());
+    EXPECT_GT(data.bucket_info(0).atom(0).temperature().temperature_dc(), 0);
+
+    EXPECT_EQ(1, data.bucket_info(1).atom_size());
+    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 100,
+              data.bucket_info(1).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
+    EXPECT_FALSE(data.bucket_info(1).atom(0).temperature().sensor_name().empty());
+    EXPECT_GT(data.bucket_info(1).atom(0).temperature().temperature_dc(), 0);
+
+    EXPECT_EQ(2, data.bucket_info(2).atom_size());
+    EXPECT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size());
+    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 1,
+              data.bucket_info(2).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 10,
+              data.bucket_info(2).elapsed_timestamp_nanos(1));
+    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
+    EXPECT_FALSE(data.bucket_info(2).atom(0).temperature().sensor_name().empty());
+    EXPECT_GT(data.bucket_info(2).atom(0).temperature().temperature_dc(), 0);
+    EXPECT_FALSE(data.bucket_info(2).atom(1).temperature().sensor_name().empty());
+    EXPECT_GT(data.bucket_info(2).atom(1).temperature().temperature_dc(), 0);
+}
+
+
+TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm) {
+    auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE);
+    int64_t baseTimeNs = 10 * NS_PER_SEC;
+    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
+    int64_t bucketSizeNs =
+        TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
+
+    ConfigKey cfgKey;
+    auto processor = CreateStatsLogProcessor(
+        baseTimeNs, configAddedTimeNs, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+    int startBucketNum = processor->mMetricsManagers.begin()->second->
+            mAllMetricProducers[0]->getCurrentBucketNum();
+    EXPECT_GT(startBucketNum, (int64_t)0);
+
+    // When creating the config, the gauge metric producer should register the alarm at the
+    // end of the current bucket.
+    EXPECT_EQ((size_t)1, StatsPullerManagerImpl::GetInstance().mReceivers.size());
+    EXPECT_EQ(bucketSizeNs,
+              StatsPullerManagerImpl::GetInstance().mReceivers.begin()->
+                    second.front().intervalNs);
+    int64_t& nextPullTimeNs = StatsPullerManagerImpl::GetInstance().mReceivers.begin()->
+            second.front().nextPullTimeNs;
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs);
+
+    auto screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+                                                        configAddedTimeNs + 55);
+    processor->OnLogEvent(screenOffEvent.get());
+
+    auto screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+                                                       configAddedTimeNs + bucketSizeNs + 10);
+    processor->OnLogEvent(screenOnEvent.get());
+
+    // Pulling alarm arrives one bucket size late.
+    processor->informPullAlarmFired(nextPullTimeNs + bucketSizeNs);
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, nextPullTimeNs);
+
+    screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+                                                   configAddedTimeNs + 3 * bucketSizeNs + 11);
+    processor->OnLogEvent(screenOffEvent.get());
+
+    // Pulling alarm arrives more than one bucket size late.
+    processor->informPullAlarmFired(nextPullTimeNs + bucketSizeNs + 12);
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs);
+
+    ConfigMetricsReportList reports;
+    vector<uint8_t> buffer;
+    processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, &buffer);
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
+    sortMetricDataByDimensionsValue(
+            reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
+    EXPECT_GT((int)gaugeMetrics.data_size(), 1);
+
+    auto data = gaugeMetrics.data(0);
+    EXPECT_EQ(android::util::TEMPERATURE, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(2 /* sensor name field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
+    EXPECT_EQ(3, data.bucket_info_size());
+
+    EXPECT_EQ(1, data.bucket_info(0).atom_size());
+    EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
+    EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(1, data.bucket_info(0).wall_clock_timestamp_nanos_size());
+    EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+    EXPECT_FALSE(data.bucket_info(0).atom(0).temperature().sensor_name().empty());
+    EXPECT_GT(data.bucket_info(0).atom(0).temperature().temperature_dc(), 0);
+
+    EXPECT_EQ(1, data.bucket_info(1).atom_size());
+    EXPECT_EQ(configAddedTimeNs + 3 * bucketSizeNs + 11,
+              data.bucket_info(1).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
+    EXPECT_FALSE(data.bucket_info(1).atom(0).temperature().sensor_name().empty());
+    EXPECT_GT(data.bucket_info(1).atom(0).temperature().temperature_dc(), 0);
+
+    EXPECT_EQ(1, data.bucket_info(2).atom_size());
+    EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
+    EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs + 12,
+              data.bucket_info(2).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
+    EXPECT_FALSE(data.bucket_info(2).atom(0).temperature().sensor_name().empty());
+    EXPECT_GT(data.bucket_info(2).atom(0).temperature().temperature_dc(), 0);
+
+}
+
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
index 18a0485..d79cb33 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
@@ -96,7 +96,8 @@
             TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
 
         ConfigKey cfgKey;
-        auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+        auto processor = CreateStatsLogProcessor(
+                bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
         EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
         EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
 
@@ -169,9 +170,11 @@
             EXPECT_EQ(2, data.bucket_info(0).atom_size());
             EXPECT_EQ(2, data.bucket_info(0).elapsed_timestamp_nanos_size());
             EXPECT_EQ(2, data.bucket_info(0).wall_clock_timestamp_nanos_size());
-            EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_nanos());
-            EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_nanos());
-            EXPECT_EQ(AppStartOccurred::HOT, data.bucket_info(0).atom(0).app_start_occurred().type());
+            EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+            EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
+                      data.bucket_info(0).end_bucket_elapsed_nanos());
+            EXPECT_EQ(AppStartOccurred::HOT,
+                      data.bucket_info(0).atom(0).app_start_occurred().type());
             EXPECT_EQ("activity_name2",
                       data.bucket_info(0).atom(0).app_start_occurred().activity_name());
             EXPECT_EQ(102L,
@@ -186,8 +189,10 @@
             EXPECT_EQ(1, data.bucket_info(1).atom_size());
             EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
             EXPECT_EQ(1, data.bucket_info(1).wall_clock_timestamp_nanos_size());
-            EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(1).start_bucket_nanos());
-            EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, data.bucket_info(1).end_bucket_nanos());
+            EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
+                      data.bucket_info(1).start_bucket_elapsed_nanos());
+            EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+                      data.bucket_info(1).end_bucket_elapsed_nanos());
             EXPECT_EQ(AppStartOccurred::WARM,
                       data.bucket_info(1).atom(0).app_start_occurred().type());
             EXPECT_EQ("activity_name4",
@@ -199,9 +204,9 @@
             EXPECT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size());
             EXPECT_EQ(2, data.bucket_info(2).wall_clock_timestamp_nanos_size());
             EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-                      data.bucket_info(2).start_bucket_nanos());
+                      data.bucket_info(2).start_bucket_elapsed_nanos());
             EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
-                      data.bucket_info(2).end_bucket_nanos());
+                      data.bucket_info(2).end_bucket_elapsed_nanos());
             EXPECT_EQ(AppStartOccurred::COLD,
                       data.bucket_info(2).atom(0).app_start_occurred().type());
             EXPECT_EQ("activity_name5",
@@ -218,9 +223,11 @@
             EXPECT_EQ(1, data.bucket_info(0).atom_size());
             EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
             EXPECT_EQ(1, data.bucket_info(0).wall_clock_timestamp_nanos_size());
-            EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_nanos());
-            EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_nanos());
-            EXPECT_EQ(AppStartOccurred::HOT, data.bucket_info(0).atom(0).app_start_occurred().type());
+            EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+            EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
+                      data.bucket_info(0).end_bucket_elapsed_nanos());
+            EXPECT_EQ(AppStartOccurred::HOT,
+                      data.bucket_info(0).atom(0).app_start_occurred().type());
             EXPECT_EQ("activity_name2",
                       data.bucket_info(0).atom(0).app_start_occurred().activity_name());
             EXPECT_EQ(102L,
@@ -229,8 +236,10 @@
             EXPECT_EQ(1, data.bucket_info(1).atom_size());
             EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
             EXPECT_EQ(1, data.bucket_info(1).wall_clock_timestamp_nanos_size());
-            EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(1).start_bucket_nanos());
-            EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, data.bucket_info(1).end_bucket_nanos());
+            EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
+                      data.bucket_info(1).start_bucket_elapsed_nanos());
+            EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+                      data.bucket_info(1).end_bucket_elapsed_nanos());
             EXPECT_EQ(AppStartOccurred::WARM,
                       data.bucket_info(1).atom(0).app_start_occurred().type());
             EXPECT_EQ("activity_name4",
@@ -242,9 +251,9 @@
             EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
             EXPECT_EQ(1, data.bucket_info(2).wall_clock_timestamp_nanos_size());
             EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-                      data.bucket_info(2).start_bucket_nanos());
+                      data.bucket_info(2).start_bucket_elapsed_nanos());
             EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
-                      data.bucket_info(2).end_bucket_nanos());
+                      data.bucket_info(2).end_bucket_elapsed_nanos());
             EXPECT_EQ(AppStartOccurred::COLD,
                       data.bucket_info(2).atom(0).app_start_occurred().type());
             EXPECT_EQ("activity_name5",
@@ -264,8 +273,10 @@
         EXPECT_EQ(1, data.bucket_info(0).atom_size());
         EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
         EXPECT_EQ(1, data.bucket_info(0).wall_clock_timestamp_nanos_size());
-        EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_nanos());
-        EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_nanos());
+        EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+                  data.bucket_info(0).start_bucket_elapsed_nanos());
+        EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
+                  data.bucket_info(0).end_bucket_elapsed_nanos());
         EXPECT_EQ(AppStartOccurred::COLD, data.bucket_info(0).atom(0).app_start_occurred().type());
         EXPECT_EQ("activity_name7",
                   data.bucket_info(0).atom(0).app_start_occurred().activity_name());
diff --git a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
index 1952a6f..4ace382 100644
--- a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
@@ -107,7 +107,7 @@
         TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
 
     ConfigKey cfgKey;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
 
@@ -224,7 +224,8 @@
             TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
 
     ConfigKey cfgKey;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+    auto processor = CreateStatsLogProcessor(
+            bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
 
diff --git a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
new file mode 100644
index 0000000..62b6fcc
--- /dev/null
+++ b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
@@ -0,0 +1,260 @@
+// Copyright (C) 2017 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 <gtest/gtest.h>
+
+#include "src/StatsLogProcessor.h"
+#include "src/stats_log_util.h"
+#include "tests/statsd_test_util.h"
+
+#include <vector>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+#ifdef __ANDROID__
+
+namespace {
+
+StatsdConfig CreateStatsdConfig() {
+    StatsdConfig config;
+    config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+    auto temperatureAtomMatcher = CreateTemperatureAtomMatcher();
+    *config.add_atom_matcher() = temperatureAtomMatcher;
+    *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
+    *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
+
+    auto screenIsOffPredicate = CreateScreenIsOffPredicate();
+    *config.add_predicate() = screenIsOffPredicate;
+
+    auto valueMetric = config.add_value_metric();
+    valueMetric->set_id(123456);
+    valueMetric->set_what(temperatureAtomMatcher.id());
+    valueMetric->set_condition(screenIsOffPredicate.id());
+    *valueMetric->mutable_value_field() =
+        CreateDimensions(android::util::TEMPERATURE, {3/* temperature degree field */ });
+    *valueMetric->mutable_dimensions_in_what() =
+        CreateDimensions(android::util::TEMPERATURE, {2/* sensor name field */ });
+    valueMetric->set_bucket(FIVE_MINUTES);
+
+    return config;
+}
+
+}  // namespace
+
+TEST(ValueMetricE2eTest, TestPulledEvents) {
+    auto config = CreateStatsdConfig();
+    int64_t baseTimeNs = 10 * NS_PER_SEC;
+    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
+    int64_t bucketSizeNs =
+        TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
+
+    ConfigKey cfgKey;
+    auto processor = CreateStatsLogProcessor(
+        baseTimeNs, configAddedTimeNs, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+    int startBucketNum = processor->mMetricsManagers.begin()->second->
+            mAllMetricProducers[0]->getCurrentBucketNum();
+    EXPECT_GT(startBucketNum, (int64_t)0);
+
+    // When creating the config, the gauge metric producer should register the alarm at the
+    // end of the current bucket.
+    EXPECT_EQ((size_t)1, StatsPullerManagerImpl::GetInstance().mReceivers.size());
+    EXPECT_EQ(bucketSizeNs,
+              StatsPullerManagerImpl::GetInstance().mReceivers.begin()->
+                    second.front().intervalNs);
+    int64_t& expectedPullTimeNs = StatsPullerManagerImpl::GetInstance().mReceivers.begin()->
+            second.front().nextPullTimeNs;
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs);
+
+    auto screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+                                                        configAddedTimeNs + 55);
+    processor->OnLogEvent(screenOffEvent.get());
+
+    auto screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+                                                       configAddedTimeNs + 65);
+    processor->OnLogEvent(screenOnEvent.get());
+
+    screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+                                                   configAddedTimeNs + 75);
+    processor->OnLogEvent(screenOffEvent.get());
+
+    // Pulling alarm arrives on time and reset the sequential pulling alarm.
+    processor->informPullAlarmFired(expectedPullTimeNs + 1);
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, expectedPullTimeNs);
+
+    processor->informPullAlarmFired(expectedPullTimeNs + 1);
+
+    screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+                                                       configAddedTimeNs + 2 * bucketSizeNs + 15);
+    processor->OnLogEvent(screenOnEvent.get());
+
+    processor->informPullAlarmFired(expectedPullTimeNs + 1);
+
+    processor->informPullAlarmFired(expectedPullTimeNs + 1);
+
+    screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+                                                   configAddedTimeNs + 4 * bucketSizeNs + 11);
+    processor->OnLogEvent(screenOffEvent.get());
+
+    processor->informPullAlarmFired(expectedPullTimeNs + 1);
+
+    processor->informPullAlarmFired(expectedPullTimeNs + 1);
+
+    ConfigMetricsReportList reports;
+    vector<uint8_t> buffer;
+    processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, &buffer);
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    StatsLogReport::ValueMetricDataWrapper valueMetrics;
+    sortMetricDataByDimensionsValue(
+            reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
+    EXPECT_GT((int)valueMetrics.data_size(), 1);
+
+    auto data = valueMetrics.data(0);
+    EXPECT_EQ(android::util::TEMPERATURE, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(2 /* sensor name field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
+    EXPECT_EQ(5, data.bucket_info_size());
+
+    EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+    EXPECT_TRUE(data.bucket_info(0).has_value());
+
+    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
+    EXPECT_TRUE(data.bucket_info(1).has_value());
+
+    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
+    EXPECT_TRUE(data.bucket_info(2).has_value());
+
+    EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(3).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(3).end_bucket_elapsed_nanos());
+    EXPECT_TRUE(data.bucket_info(3).has_value());
+
+    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(4).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(4).end_bucket_elapsed_nanos());
+    EXPECT_TRUE(data.bucket_info(4).has_value());
+}
+
+TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm) {
+    auto config = CreateStatsdConfig();
+    int64_t baseTimeNs = 10 * NS_PER_SEC;
+    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
+    int64_t bucketSizeNs =
+        TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
+
+    ConfigKey cfgKey;
+    auto processor = CreateStatsLogProcessor(
+        baseTimeNs, configAddedTimeNs, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+    int startBucketNum = processor->mMetricsManagers.begin()->second->
+            mAllMetricProducers[0]->getCurrentBucketNum();
+    EXPECT_GT(startBucketNum, (int64_t)0);
+
+    // When creating the config, the gauge metric producer should register the alarm at the
+    // end of the current bucket.
+    EXPECT_EQ((size_t)1, StatsPullerManagerImpl::GetInstance().mReceivers.size());
+    EXPECT_EQ(bucketSizeNs,
+              StatsPullerManagerImpl::GetInstance().mReceivers.begin()->
+                    second.front().intervalNs);
+    int64_t& expectedPullTimeNs = StatsPullerManagerImpl::GetInstance().mReceivers.begin()->
+            second.front().nextPullTimeNs;
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs);
+
+    // Screen off/on/off events.
+    auto screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+                                                        configAddedTimeNs + 55);
+    processor->OnLogEvent(screenOffEvent.get());
+
+    auto screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+                                                       configAddedTimeNs + 65);
+    processor->OnLogEvent(screenOnEvent.get());
+
+    screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+                                                   configAddedTimeNs + 75);
+    processor->OnLogEvent(screenOffEvent.get());
+
+    // Pulling alarm arrives late by 2 buckets and 1 ns.
+    processor->informPullAlarmFired(expectedPullTimeNs + 2 * bucketSizeNs + 1);
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, expectedPullTimeNs);
+
+    screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+                                                       configAddedTimeNs + 4 * bucketSizeNs + 65);
+    processor->OnLogEvent(screenOnEvent.get());
+
+    // Pulling alarm arrives late by one bucket size + 21ns.
+    processor->informPullAlarmFired(expectedPullTimeNs + bucketSizeNs + 21);
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, expectedPullTimeNs);
+
+    screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+                                                   configAddedTimeNs + 6 * bucketSizeNs + 31);
+    processor->OnLogEvent(screenOffEvent.get());
+
+    processor->informPullAlarmFired(expectedPullTimeNs + bucketSizeNs + 21);
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 8 * bucketSizeNs, expectedPullTimeNs);
+
+    processor->informPullAlarmFired(expectedPullTimeNs + 1);
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 9 * bucketSizeNs, expectedPullTimeNs);
+
+    ConfigMetricsReportList reports;
+    vector<uint8_t> buffer;
+    processor->onDumpReport(cfgKey, configAddedTimeNs + 9 * bucketSizeNs + 10, false, &buffer);
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    StatsLogReport::ValueMetricDataWrapper valueMetrics;
+    sortMetricDataByDimensionsValue(
+            reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
+    EXPECT_GT((int)valueMetrics.data_size(), 1);
+
+    auto data = valueMetrics.data(0);
+    EXPECT_EQ(android::util::TEMPERATURE, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(2 /* sensor name field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
+    EXPECT_EQ(3, data.bucket_info_size());
+
+    EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+    EXPECT_TRUE(data.bucket_info(0).has_value());
+
+    EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
+    EXPECT_TRUE(data.bucket_info(1).has_value());
+
+    EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 10 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
+    EXPECT_TRUE(data.bucket_info(2).has_value());
+}
+
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
index f2d47c7..55bf4be 100644
--- a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
@@ -121,7 +121,7 @@
     uint64_t bucketStartTimeNs = 10000000000;
     uint64_t bucketSizeNs =
             TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
     FeedEvents(config, processor);
@@ -154,7 +154,7 @@
     uint64_t bucketStartTimeNs = 10000000000;
     uint64_t bucketSizeNs =
             TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
     FeedEvents(config, processor);
@@ -188,7 +188,7 @@
     uint64_t bucketStartTimeNs = 10000000000;
     uint64_t bucketSizeNs =
             TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
     FeedEvents(config, processor);
@@ -231,7 +231,7 @@
     uint64_t bucketStartTimeNs = 10000000000;
     uint64_t bucketSizeNs =
             TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
     FeedEvents(config, processor);
@@ -256,7 +256,7 @@
     uint64_t bucketStartTimeNs = 10000000000;
     uint64_t bucketSizeNs =
             TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
     FeedEvents(config, processor);
@@ -284,7 +284,7 @@
     uint64_t bucketStartTimeNs = 10000000000;
     uint64_t bucketSizeNs =
             TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
     FeedEvents(config, processor);
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index a1f865d..698ce72 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -67,7 +67,7 @@
     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
 
     GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-                                      tagId, bucketStartTimeNs, pullerManager);
+                                      tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
     gaugeProducer.setBucketSize(60 * NS_PER_SEC);
 
     vector<shared_ptr<LogEvent>> allData;
@@ -144,7 +144,7 @@
             make_shared<StrictMock<MockStatsPullerManager>>();
     GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
                                       -1 /* -1 means no pulling */, bucketStartTimeNs,
-                                      pullerManager);
+                                      bucketStartTimeNs, pullerManager);
 
     gaugeProducer.setBucketSize(60 * NS_PER_SEC);
     sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor);
@@ -228,7 +228,7 @@
             }));
 
     GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-                                      tagId, bucketStartTimeNs, pullerManager);
+                                      tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
     gaugeProducer.setBucketSize(60 * NS_PER_SEC);
 
     vector<shared_ptr<LogEvent>> allData;
@@ -297,7 +297,7 @@
             }));
 
     GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard, tagId,
-                                      bucketStartTimeNs, pullerManager);
+                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
     gaugeProducer.setBucketSize(60 * NS_PER_SEC);
 
     gaugeProducer.onConditionChanged(true, bucketStartTimeNs + 8);
@@ -389,7 +389,7 @@
             }));
 
     GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard, tagId, bucketStartTimeNs,
-                                      pullerManager);
+                                      bucketStartTimeNs, pullerManager);
     gaugeProducer.setBucketSize(60 * NS_PER_SEC);
 
     gaugeProducer.onSlicedConditionMayChange(true, bucketStartTimeNs + 8);
@@ -433,7 +433,7 @@
     gaugeFieldMatcher->set_field(tagId);
     gaugeFieldMatcher->add_child()->set_field(2);
     GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-                                      tagId, bucketStartTimeNs, pullerManager);
+                                      tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
     gaugeProducer.setBucketSize(60 * NS_PER_SEC);
 
     Alert alert;
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 7b52265..81d8892 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -68,7 +68,7 @@
     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
 
     ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-                                      tagId, bucketStartTimeNs, pullerManager);
+                                      tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
     valueProducer.setBucketSize(60 * NS_PER_SEC);
 
     vector<shared_ptr<LogEvent>> allData;
@@ -168,7 +168,7 @@
             }));
 
     ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, tagId, bucketStartTimeNs,
-                                      pullerManager);
+                                      bucketStartTimeNs, pullerManager);
     valueProducer.setBucketSize(60 * NS_PER_SEC);
     valueProducer.onConditionChanged(true, bucketStartTimeNs + 8);
 
@@ -221,7 +221,7 @@
     shared_ptr<MockStatsPullerManager> pullerManager =
             make_shared<StrictMock<MockStatsPullerManager>>();
     ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, -1, bucketStartTimeNs,
-                                      pullerManager);
+                                      bucketStartTimeNs, pullerManager);
     valueProducer.setBucketSize(60 * NS_PER_SEC);
 
     shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
@@ -277,7 +277,7 @@
                 return true;
             }));
     ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, tagId, bucketStartTimeNs,
-                                      pullerManager);
+                                      bucketStartTimeNs, pullerManager);
     valueProducer.setBucketSize(60 * NS_PER_SEC);
 
     vector<shared_ptr<LogEvent>> allData;
@@ -320,7 +320,7 @@
             make_shared<StrictMock<MockStatsPullerManager>>();
 
     ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, -1, bucketStartTimeNs,
-                                      pullerManager);
+                                      bucketStartTimeNs, pullerManager);
     valueProducer.setBucketSize(60 * NS_PER_SEC);
 
     shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
@@ -368,7 +368,7 @@
 
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-                                      -1 /*not pulled*/, bucketStartTimeNs);
+                                      -1 /*not pulled*/, bucketStartTimeNs, bucketStartTimeNs);
     valueProducer.setBucketSize(60 * NS_PER_SEC);
 
     sp<AnomalyTracker> anomalyTracker = valueProducer.addAnomalyTracker(alert, alarmMonitor);
@@ -447,7 +447,7 @@
     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
 
     ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-                                      tagId, bucketStartTimeNs, pullerManager);
+                                      tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
     valueProducer.setBucketSize(60 * NS_PER_SEC);
 
     vector<shared_ptr<LogEvent>> allData;
@@ -556,7 +556,7 @@
             }));
 
     ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, tagId, bucketStartTimeNs,
-                                      pullerManager);
+                                      bucketStartTimeNs, pullerManager);
     valueProducer.setBucketSize(60 * NS_PER_SEC);
     valueProducer.onConditionChanged(true, bucketStartTimeNs + 8);
 
@@ -650,7 +650,7 @@
             }));
 
     ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, tagId, bucketStartTimeNs,
-                                      pullerManager);
+                                      bucketStartTimeNs, pullerManager);
     valueProducer.setBucketSize(60 * NS_PER_SEC);
     valueProducer.onConditionChanged(true, bucketStartTimeNs + 8);
 
@@ -742,7 +742,7 @@
             }));
 
     ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, tagId, bucketStartTimeNs,
-                                      pullerManager);
+                                      bucketStartTimeNs, pullerManager);
     valueProducer.setBucketSize(60 * NS_PER_SEC);
     valueProducer.onConditionChanged(true, bucketStartTimeNs + 8);
 
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index 649c399..1264909 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -18,6 +18,7 @@
 namespace os {
 namespace statsd {
 
+
 AtomMatcher CreateSimpleAtomMatcher(const string& name, int atomId) {
     AtomMatcher atom_matcher;
     atom_matcher.set_id(StringToId(name));
@@ -26,6 +27,10 @@
     return atom_matcher;
 }
 
+AtomMatcher CreateTemperatureAtomMatcher() {
+    return CreateSimpleAtomMatcher("TemperatureMatcher", android::util::TEMPERATURE);
+}
+
 AtomMatcher CreateScheduledJobStateChangedAtomMatcher(const string& name,
                                                       ScheduledJobStateChanged::State state) {
     AtomMatcher atom_matcher;
@@ -444,8 +449,8 @@
     return logEvent;
 }
 
-sp<StatsLogProcessor> CreateStatsLogProcessor(const long timeBaseSec, const StatsdConfig& config,
-                                              const ConfigKey& key) {
+sp<StatsLogProcessor> CreateStatsLogProcessor(const int64_t timeBaseNs, const int64_t currentTimeNs,
+                                              const StatsdConfig& config, const ConfigKey& key) {
     sp<UidMap> uidMap = new UidMap();
     sp<AlarmMonitor> anomalyAlarmMonitor =
         new AlarmMonitor(1,  [](const sp<IStatsCompanionService>&, int64_t){},
@@ -454,8 +459,8 @@
         new AlarmMonitor(1,  [](const sp<IStatsCompanionService>&, int64_t){},
                 [](const sp<IStatsCompanionService>&){});
     sp<StatsLogProcessor> processor = new StatsLogProcessor(
-        uidMap, anomalyAlarmMonitor, periodicAlarmMonitor, timeBaseSec, [](const ConfigKey&){});
-    processor->OnConfigUpdated(timeBaseSec * NS_PER_SEC, key, config);
+        uidMap, anomalyAlarmMonitor, periodicAlarmMonitor, timeBaseNs, [](const ConfigKey&){});
+    processor->OnConfigUpdated(currentTimeNs, key, config);
     return processor;
 }
 
diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h
index 1ac630c..6ecca46 100644
--- a/cmds/statsd/tests/statsd_test_util.h
+++ b/cmds/statsd/tests/statsd_test_util.h
@@ -28,6 +28,9 @@
 // Create AtomMatcher proto to simply match a specific atom type.
 AtomMatcher CreateSimpleAtomMatcher(const string& name, int atomId);
 
+// Create AtomMatcher proto for temperature atom.
+AtomMatcher CreateTemperatureAtomMatcher();
+
 // Create AtomMatcher proto for scheduled job state changed.
 AtomMatcher CreateScheduledJobStateChangedAtomMatcher();
 
@@ -172,8 +175,9 @@
 AttributionNodeInternal CreateAttribution(const int& uid, const string& tag);
 
 // Create a statsd log event processor upon the start time in seconds, config and key.
-sp<StatsLogProcessor> CreateStatsLogProcessor(const long timeBaseSec, const StatsdConfig& config,
-                                              const ConfigKey& key);
+sp<StatsLogProcessor> CreateStatsLogProcessor(const int64_t timeBaseNs,
+                                              const int64_t currentTimeNs,
+                                              const StatsdConfig& config, const ConfigKey& key);
 
 // Util function to sort the log events by timestamp.
 void sortLogEventsByTimestamp(std::vector<std::unique_ptr<LogEvent>> *events);