Pass in event time when notifying listeners of a state change

Add an event time parameter to onStateChanged. Value and Duration
metrics need the event time for aggregation.

Test: bit statsd_test:*
Change-Id: I73c7a16de158de43bd9fbeb26ab8f0c32559a4a2
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index c29b32c..c1f95ee 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -121,10 +121,12 @@
     VLOG("~CountMetricProducer() called");
 }
 
-void CountMetricProducer::onStateChanged(int atomId, const HashableDimensionKey& primaryKey,
-                                         int oldState, int newState) {
-    VLOG("CountMetric %lld onStateChanged State%d, key %s, %d -> %d", (long long)mMetricId, atomId,
-         primaryKey.toString().c_str(), oldState, newState);
+void CountMetricProducer::onStateChanged(const int64_t eventTimeNs, const int32_t atomId,
+                                         const HashableDimensionKey& primaryKey, int oldState,
+                                         int newState) {
+    VLOG("CountMetric %lld onStateChanged time %lld, State%d, key %s, %d -> %d",
+         (long long)mMetricId, (long long)eventTimeNs, atomId, primaryKey.toString().c_str(),
+         oldState, newState);
 }
 
 void CountMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const {
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index 8b17d88..7b6c7e0 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -52,7 +52,8 @@
 
     virtual ~CountMetricProducer();
 
-    void onStateChanged(int32_t atomId, const HashableDimensionKey& primaryKey, int oldState,
+    void onStateChanged(const int64_t eventTimeNs, const int32_t atomId,
+                        const HashableDimensionKey& primaryKey, int oldState,
                         int newState) override;
 
 protected:
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index a513db6..3512f18 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -149,8 +149,8 @@
         return mConditionSliced;
     };
 
-    void onStateChanged(int atomId, const HashableDimensionKey& primaryKey, int oldState,
-                        int newState){};
+    void onStateChanged(const int64_t eventTimeNs, const int32_t atomId,
+                        const HashableDimensionKey& primaryKey, int oldState, int newState){};
 
     // Output the metrics data to [protoOutput]. All metrics reports end with the same timestamp.
     // This method clears all the past buckets.
diff --git a/cmds/statsd/src/state/StateListener.h b/cmds/statsd/src/state/StateListener.h
index f2b9a6b..d1af196 100644
--- a/cmds/statsd/src/state/StateListener.h
+++ b/cmds/statsd/src/state/StateListener.h
@@ -38,13 +38,15 @@
      * state groups and are responsible for mapping original state values to
      * the correct state group.
      *
+     * [eventTimeNs]: Time of the state change log event.
      * [atomId]: The id of the state atom
      * [primaryKey]: The primary field values of the state atom
      * [oldState]: Previous state value before state change
      * [newState]: Current state value after state change
      */
-    virtual void onStateChanged(int32_t atomId, const HashableDimensionKey& primaryKey,
-                                int oldState, int newState) = 0;
+    virtual void onStateChanged(const int64_t eventTimeNs, const int32_t atomId,
+                                const HashableDimensionKey& primaryKey, int oldState,
+                                int newState) = 0;
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/state/StateTracker.cpp b/cmds/statsd/src/state/StateTracker.cpp
index e6f6122..90ce1e9 100644
--- a/cmds/statsd/src/state/StateTracker.cpp
+++ b/cmds/statsd/src/state/StateTracker.cpp
@@ -38,49 +38,51 @@
 }
 
 void StateTracker::onLogEvent(const LogEvent& event) {
-    // parse event for primary field values i.e. primary key
+    int64_t eventTimeNs = event.GetElapsedTimestampNs();
+
+    // Parse event for primary field values i.e. primary key.
     HashableDimensionKey primaryKey;
     if (mPrimaryFields.size() > 0) {
         if (!filterValues(mPrimaryFields, event.getValues(), &primaryKey) ||
             primaryKey.getValues().size() != mPrimaryFields.size()) {
             ALOGE("StateTracker error extracting primary key from log event.");
-            handleReset();
+            handleReset(eventTimeNs);
             return;
         }
     } else {
-        // atom has no primary fields
+        // Use an empty HashableDimensionKey if atom has no primary fields.
         primaryKey = DEFAULT_DIMENSION_KEY;
     }
 
-    // parse event for state value
+    // Parse event for state value.
     FieldValue stateValue;
     int32_t state;
     if (!filterValues(mStateField, event.getValues(), &stateValue) ||
         stateValue.mValue.getType() != INT) {
         ALOGE("StateTracker error extracting state from log event. Type: %d",
               stateValue.mValue.getType());
-        handlePartialReset(primaryKey);
+        handlePartialReset(eventTimeNs, primaryKey);
         return;
     }
     state = stateValue.mValue.int_value;
 
     if (state == mResetState) {
         VLOG("StateTracker Reset state: %s", stateValue.mValue.toString().c_str());
-        handleReset();
+        handleReset(eventTimeNs);
     }
 
-    // track and update state
+    // Track and update state.
     int32_t oldState = 0;
     int32_t newState = 0;
     updateState(primaryKey, state, &oldState, &newState);
 
-    // notify all listeners if state has changed
+    // Notify all listeners if state has changed.
     if (oldState != newState) {
         VLOG("StateTracker updated state");
         for (auto listener : mListeners) {
             auto sListener = listener.promote();  // safe access to wp<>
             if (sListener != nullptr) {
-                sListener->onStateChanged(mAtomId, primaryKey, oldState, newState);
+                sListener->onStateChanged(eventTimeNs, mAtomId, primaryKey, oldState, newState);
             }
         }
     } else {
@@ -119,20 +121,22 @@
     return false;
 }
 
-void StateTracker::handleReset() {
+void StateTracker::handleReset(const int64_t eventTimeNs) {
     VLOG("StateTracker handle reset");
     for (const auto pair : mStateMap) {
         for (auto l : mListeners) {
             auto sl = l.promote();
             if (sl != nullptr) {
-                sl->onStateChanged(mAtomId, pair.first, pair.second.state, mDefaultState);
+                sl->onStateChanged(eventTimeNs, mAtomId, pair.first, pair.second.state,
+                                   mDefaultState);
             }
         }
     }
     mStateMap.clear();
 }
 
-void StateTracker::handlePartialReset(const HashableDimensionKey& primaryKey) {
+void StateTracker::handlePartialReset(const int64_t eventTimeNs,
+                                      const HashableDimensionKey& primaryKey) {
     VLOG("StateTracker handle partial reset");
     if (mStateMap.find(primaryKey) != mStateMap.end()) {
         mStateMap.erase(primaryKey);
diff --git a/cmds/statsd/src/state/StateTracker.h b/cmds/statsd/src/state/StateTracker.h
index 450412d..544857f 100644
--- a/cmds/statsd/src/state/StateTracker.h
+++ b/cmds/statsd/src/state/StateTracker.h
@@ -81,10 +81,10 @@
     std::set<wp<StateListener>> mListeners;
 
     // Reset all state values in map to default state
-    void handleReset();
+    void handleReset(const int64_t eventTimeNs);
 
     // Reset only the state value mapped to primary key to default state
-    void handlePartialReset(const HashableDimensionKey& primaryKey);
+    void handlePartialReset(const int64_t eventTimeNs, const HashableDimensionKey& primaryKey);
 
     // Update the StateMap based on the received state value.
     // Store the old and new states.