Remove kStateAtomsInfo from atoms_info.

Use the annotation information in LogEvent/FieldValue instead.

- Initialize nested to true in FieldValue.mAnnotations

- Add filterPrimaryKey function to HashableDimensionKey for populating a
HashableDimensionKey with all FieldValues that have the primary key
annotation set.

- Create StateTrackers without checking if atom is a state atom. (We
  can't do this check anymore)

- Remove mAtomId, mStateField, mNested, mPrimaryFields, mDefaultState,
    mResetState members from StateTracker. Use the information passed in
    LogEvent in onLogEvent instead.

- Update tests to log annotations when logging events.

- Remote kStateAtomsFieldOptions from atoms_info.

- Make MetricProducer::mStateGroupMap const

- Rename handlePartialReset to clearStateForPrimaryKey

- Store "default" states in mStateMap. An entry in mStateMap means the
state is not kStateUnknown. Before, an entry in mStateMap meant the
state is not the "default" state.

- Consolidate all state change logic in updateStateForPrimaryKey()
    - remote StateTracker::updateState
    - handleReset and clearStateForPrimaryKey call
    updateStateForPrimaryKey for resetting and clearing of states
    respectively.

- Create a helper method for notifying StateTracker listeners

- Make StateManager::registerListener void

Bug: 151110842
Test: bit statsd_test:*
Change-Id: Ifb8371b213a178fcccaa484086fbdd283dbaec49
diff --git a/cmds/statsd/src/state/StateManager.cpp b/cmds/statsd/src/state/StateManager.cpp
index ea776fa..5514b446 100644
--- a/cmds/statsd/src/state/StateManager.cpp
+++ b/cmds/statsd/src/state/StateManager.cpp
@@ -38,20 +38,12 @@
     }
 }
 
-bool StateManager::registerListener(const int32_t atomId, wp<StateListener> listener) {
+void StateManager::registerListener(const int32_t atomId, wp<StateListener> listener) {
     // Check if state tracker already exists.
     if (mStateTrackers.find(atomId) == mStateTrackers.end()) {
-        // Create a new state tracker iff atom is a state atom.
-        auto it = android::util::AtomsInfo::kStateAtomsFieldOptions.find(atomId);
-        if (it != android::util::AtomsInfo::kStateAtomsFieldOptions.end()) {
-            mStateTrackers[atomId] = new StateTracker(atomId, it->second);
-        } else {
-            ALOGE("StateManager cannot register listener, Atom %d is not a state atom", atomId);
-            return false;
-        }
+        mStateTrackers[atomId] = new StateTracker(atomId);
     }
     mStateTrackers[atomId]->registerListener(listener);
-    return true;
 }
 
 void StateManager::unregisterListener(const int32_t atomId, wp<StateListener> listener) {
diff --git a/cmds/statsd/src/state/StateManager.h b/cmds/statsd/src/state/StateManager.h
index 8b3a421..577a0f5 100644
--- a/cmds/statsd/src/state/StateManager.h
+++ b/cmds/statsd/src/state/StateManager.h
@@ -45,10 +45,11 @@
     // Notifies the correct StateTracker of an event.
     void onLogEvent(const LogEvent& event);
 
-    // Returns true if atomId is being tracked and is associated with a state
-    // atom. StateManager notifies the correct StateTracker to register listener.
+    // Notifies the StateTracker for the given atomId to register listener.
     // If the correct StateTracker does not exist, a new StateTracker is created.
-    bool registerListener(const int32_t atomId, wp<StateListener> listener);
+    // Note: StateTrackers can be created for non-state atoms. They are essentially empty and
+    // do not perform any actions.
+    void registerListener(const int32_t atomId, wp<StateListener> listener);
 
     // Notifies the correct StateTracker to unregister a listener
     // and removes the tracker if it no longer has any listeners.
diff --git a/cmds/statsd/src/state/StateTracker.cpp b/cmds/statsd/src/state/StateTracker.cpp
index ab86127..b7f314a 100644
--- a/cmds/statsd/src/state/StateTracker.cpp
+++ b/cmds/statsd/src/state/StateTracker.cpp
@@ -25,81 +25,43 @@
 namespace os {
 namespace statsd {
 
-StateTracker::StateTracker(const int32_t atomId, const util::StateAtomFieldOptions& stateAtomInfo)
-    : mAtomId(atomId),
-      mStateField(getSimpleMatcher(atomId, stateAtomInfo.exclusiveField)),
-      mNested(stateAtomInfo.nested) {
-    // create matcher for each primary field
-    for (const auto& primaryField : stateAtomInfo.primaryFields) {
-        if (primaryField == util::FIRST_UID_IN_CHAIN) {
-            Matcher matcher = getFirstUidMatcher(atomId);
-            mPrimaryFields.push_back(matcher);
-        } else {
-            Matcher matcher = getSimpleMatcher(atomId, primaryField);
-            mPrimaryFields.push_back(matcher);
-        }
-    }
-
-    if (stateAtomInfo.defaultState != util::UNSET_VALUE) {
-        mDefaultState = stateAtomInfo.defaultState;
-    }
-
-    if (stateAtomInfo.resetState != util::UNSET_VALUE) {
-        mResetState = stateAtomInfo.resetState;
-    }
+StateTracker::StateTracker(const int32_t atomId) : mField(atomId, 0) {
 }
 
 void StateTracker::onLogEvent(const LogEvent& event) {
-    int64_t eventTimeNs = event.GetElapsedTimestampNs();
+    const 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(eventTimeNs);
-            return;
-        }
-    } else {
-        // Use an empty HashableDimensionKey if atom has no primary fields.
-        primaryKey = DEFAULT_DIMENSION_KEY;
+    filterPrimaryKey(event.getValues(), &primaryKey);
+
+    FieldValue stateValue;
+    if (!getStateFieldValueFromLogEvent(event, &stateValue)) {
+        ALOGE("StateTracker error extracting state from log event. Missing exclusive state field.");
+        clearStateForPrimaryKey(eventTimeNs, primaryKey);
+        return;
     }
 
-    // Parse event for state value.
-    FieldValue stateValue;
-    if (!filterValues(mStateField, event.getValues(), &stateValue) ||
-        stateValue.mValue.getType() != INT) {
+    mField.setField(stateValue.mField.getField());
+
+    if (stateValue.mValue.getType() != INT) {
         ALOGE("StateTracker error extracting state from log event. Type: %d",
               stateValue.mValue.getType());
-        handlePartialReset(eventTimeNs, primaryKey);
+        clearStateForPrimaryKey(eventTimeNs, primaryKey);
         return;
     }
 
-    int32_t state = stateValue.mValue.int_value;
-    if (state == mResetState) {
-        VLOG("StateTracker Reset state: %s", stateValue.mValue.toString().c_str());
-        handleReset(eventTimeNs);
+    const int32_t resetState = stateValue.mAnnotations.getResetState();
+    if (resetState != -1) {
+        VLOG("StateTracker new reset state: %d", resetState);
+        handleReset(eventTimeNs, resetState);
         return;
     }
 
-    // Track and update state.
-    int32_t oldState = 0;
-    int32_t newState = 0;
-    updateState(primaryKey, state, &oldState, &newState);
-
-    // 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(eventTimeNs, mAtomId, primaryKey, oldState, newState);
-            }
-        }
-    } else {
-        VLOG("StateTracker NO updated state");
-    }
+    const int32_t newState = stateValue.mValue.int_value;
+    const bool nested = stateValue.mAnnotations.isNested();
+    StateValueInfo* stateValueInfo = &mStateMap[primaryKey];
+    updateStateForPrimaryKey(eventTimeNs, primaryKey, newState, nested, stateValueInfo);
 }
 
 void StateTracker::registerListener(wp<StateListener> listener) {
@@ -111,81 +73,62 @@
 }
 
 bool StateTracker::getStateValue(const HashableDimensionKey& queryKey, FieldValue* output) const {
-    output->mField = mStateField.mMatcher;
+    output->mField = mField;
 
-    // Check that the query key has the correct number of primary fields.
-    if (queryKey.getValues().size() == mPrimaryFields.size()) {
-        auto it = mStateMap.find(queryKey);
-        if (it != mStateMap.end()) {
-            output->mValue = it->second.state;
-            return true;
-        }
-    } else if (queryKey.getValues().size() > mPrimaryFields.size()) {
-        ALOGE("StateTracker query key size %zu > primary key size %zu is illegal",
-              queryKey.getValues().size(), mPrimaryFields.size());
-    } else {
-        ALOGE("StateTracker query key size %zu < primary key size %zu is not supported",
-              queryKey.getValues().size(), mPrimaryFields.size());
+    if (const auto it = mStateMap.find(queryKey); it != mStateMap.end()) {
+        output->mValue = it->second.state;
+        return true;
     }
 
-    // Set the state value to default state if:
-    // - query key size is incorrect
-    // - query key is not found in state map
-    output->mValue = mDefaultState;
+    // Set the state value to kStateUnknown if query key is not found in state map.
+    output->mValue = kStateUnknown;
     return false;
 }
 
-void StateTracker::handleReset(const int64_t eventTimeNs) {
+void StateTracker::handleReset(const int64_t eventTimeNs, const int32_t newState) {
     VLOG("StateTracker handle reset");
-    for (const auto pair : mStateMap) {
-        for (auto l : mListeners) {
-            auto sl = l.promote();
-            if (sl != nullptr) {
-                sl->onStateChanged(eventTimeNs, mAtomId, pair.first, pair.second.state,
-                                   mDefaultState);
-            }
-        }
-    }
-    mStateMap.clear();
-}
-
-void StateTracker::handlePartialReset(const int64_t eventTimeNs,
-                                      const HashableDimensionKey& primaryKey) {
-    VLOG("StateTracker handle partial reset");
-    if (mStateMap.find(primaryKey) != mStateMap.end()) {
-        for (auto l : mListeners) {
-            auto sl = l.promote();
-            if (sl != nullptr) {
-                sl->onStateChanged(eventTimeNs, mAtomId, primaryKey,
-                                   mStateMap.find(primaryKey)->second.state, mDefaultState);
-            }
-        }
-        mStateMap.erase(primaryKey);
+    for (auto& [primaryKey, stateValueInfo] : mStateMap) {
+        updateStateForPrimaryKey(eventTimeNs, primaryKey, newState,
+                                 false /* nested; treat this state change as not nested */,
+                                 &stateValueInfo);
     }
 }
 
-void StateTracker::updateState(const HashableDimensionKey& primaryKey, const int32_t eventState,
-                               int32_t* oldState, int32_t* newState) {
-    // get old state (either current state in map or default state)
-    auto it = mStateMap.find(primaryKey);
+void StateTracker::clearStateForPrimaryKey(const int64_t eventTimeNs,
+                                           const HashableDimensionKey& primaryKey) {
+    VLOG("StateTracker clear state for primary key");
+    const std::unordered_map<HashableDimensionKey, StateValueInfo>::iterator it =
+            mStateMap.find(primaryKey);
+
+    // If there is no entry for the primaryKey in mStateMap, then the state is already
+    // kStateUnknown.
     if (it != mStateMap.end()) {
-        *oldState = it->second.state;
-    } else {
-        *oldState = mDefaultState;
+        updateStateForPrimaryKey(eventTimeNs, primaryKey, kStateUnknown,
+                                 false /* nested; treat this state change as not nested */,
+                                 &it->second);
+    }
+}
+
+void StateTracker::updateStateForPrimaryKey(const int64_t eventTimeNs,
+                                            const HashableDimensionKey& primaryKey,
+                                            const int32_t newState, const bool nested,
+                                            StateValueInfo* stateValueInfo) {
+    const int32_t oldState = stateValueInfo->state;
+
+    if (kStateUnknown == newState) {
+        mStateMap.erase(primaryKey);
     }
 
     // Update state map for non-nested counting case.
     // Every state event triggers a state overwrite.
-    if (!mNested) {
-        if (eventState == mDefaultState) {
-            // remove (key, state) pair if state returns to default state
-            VLOG("\t StateTracker changed to default state")
-            mStateMap.erase(primaryKey);
-        } else {
-            mStateMap[primaryKey].state = eventState;
-            mStateMap[primaryKey].count = 1;
+    if (!nested) {
+        stateValueInfo->state = newState;
+        stateValueInfo->count = 1;
+
+        // Notify listeners if state has changed.
+        if (oldState != newState) {
+            notifyListeners(eventTimeNs, primaryKey, oldState, newState);
         }
-        *newState = eventState;
         return;
     }
 
@@ -197,31 +140,47 @@
     // number of OFF events as ON events.
     //
     // In atoms.proto, a state atom with nested counting enabled
-    // must only have 2 states and one of the states must be the default state.
-    it = mStateMap.find(primaryKey);
-    if (it != mStateMap.end()) {
-        *newState = it->second.state;
-        if (eventState == it->second.state) {
-            it->second.count++;
-        } else if (eventState == mDefaultState) {
-            if ((--it->second.count) == 0) {
-                mStateMap.erase(primaryKey);
-                *newState = mDefaultState;
-            }
-        } else {
-            ALOGE("StateTracker Nest counting state has a third state instead of the binary state "
-                  "limit.");
-            return;
+    // must only have 2 states. There is no enforcemnt here of this requirement.
+    // The atom must be logged correctly.
+    if (kStateUnknown == newState) {
+        if (kStateUnknown != oldState) {
+            notifyListeners(eventTimeNs, primaryKey, oldState, newState);
         }
-    } else {
-        if (eventState != mDefaultState) {
-            mStateMap[primaryKey].state = eventState;
-            mStateMap[primaryKey].count = 1;
-        }
-        *newState = eventState;
+    } else if (oldState == kStateUnknown) {
+        stateValueInfo->state = newState;
+        stateValueInfo->count = 1;
+        notifyListeners(eventTimeNs, primaryKey, oldState, newState);
+    } else if (oldState == newState) {
+        stateValueInfo->count++;
+    } else if (--stateValueInfo->count == 0) {
+        stateValueInfo->state = newState;
+        stateValueInfo->count = 1;
+        notifyListeners(eventTimeNs, primaryKey, oldState, newState);
     }
 }
 
+void StateTracker::notifyListeners(const int64_t eventTimeNs,
+                                   const HashableDimensionKey& primaryKey, const int32_t oldState,
+                                   const int32_t newState) {
+    for (auto l : mListeners) {
+        auto sl = l.promote();
+        if (sl != nullptr) {
+            sl->onStateChanged(eventTimeNs, mField.getTag(), primaryKey, oldState, newState);
+        }
+    }
+}
+
+bool getStateFieldValueFromLogEvent(const LogEvent& event, FieldValue* output) {
+    const int exclusiveStateFieldIndex = event.getExclusiveStateFieldIndex();
+    if (-1 == exclusiveStateFieldIndex) {
+        ALOGE("error extracting state from log event. Missing exclusive state field.");
+        return false;
+    }
+
+    *output = event.getValues()[exclusiveStateFieldIndex];
+    return true;
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/state/StateTracker.h b/cmds/statsd/src/state/StateTracker.h
index 154750e..c5f6315 100644
--- a/cmds/statsd/src/state/StateTracker.h
+++ b/cmds/statsd/src/state/StateTracker.h
@@ -15,7 +15,6 @@
  */
 #pragma once
 
-#include <atoms_info.h>
 #include <utils/RefBase.h>
 #include "HashableDimensionKey.h"
 #include "logd/LogEvent.h"
@@ -30,7 +29,7 @@
 
 class StateTracker : public virtual RefBase {
 public:
-    StateTracker(const int32_t atomId, const android::util::StateAtomFieldOptions& stateAtomInfo);
+    StateTracker(const int32_t atomId);
 
     virtual ~StateTracker(){};
 
@@ -60,21 +59,11 @@
 
 private:
     struct StateValueInfo {
-        int32_t state;  // state value
-        int count;      // nested count (only used for binary states)
+        int32_t state = kStateUnknown;  // state value
+        int count = 0;                  // nested count (only used for binary states)
     };
 
-    const int32_t mAtomId;  // id of the state atom being tracked
-
-    Matcher mStateField;  // matches the atom's exclusive state field
-
-    std::vector<Matcher> mPrimaryFields;  // matches the atom's primary fields
-
-    int32_t mDefaultState = kStateUnknown;
-
-    int32_t mResetState = kStateUnknown;
-
-    const bool mNested;
+    Field mField;
 
     // Maps primary key to state value info
     std::unordered_map<HashableDimensionKey, StateValueInfo> mStateMap;
@@ -82,20 +71,24 @@
     // Set of all StateListeners (objects listening for state changes)
     std::set<wp<StateListener>> mListeners;
 
-    // Reset all state values in map to default state.
-    void handleReset(const int64_t eventTimeNs);
+    // Reset all state values in map to the given state.
+    void handleReset(const int64_t eventTimeNs, const int32_t newState);
 
-    // Reset only the state value mapped to the given primary key to default state.
-    // Partial resets are used when we only need to update the state of one primary
-    // key instead of clearing/reseting every key in the map.
-    void handlePartialReset(const int64_t eventTimeNs, const HashableDimensionKey& primaryKey);
+    // Clears the state value mapped to the given primary key by setting it to kStateUnknown.
+    void clearStateForPrimaryKey(const int64_t eventTimeNs, const HashableDimensionKey& primaryKey);
 
     // Update the StateMap based on the received state value.
-    // Store the old and new states.
-    void updateState(const HashableDimensionKey& primaryKey, const int32_t eventState,
-                     int32_t* oldState, int32_t* newState);
+    void updateStateForPrimaryKey(const int64_t eventTimeNs, const HashableDimensionKey& primaryKey,
+                                  const int32_t newState, const bool nested,
+                                  StateValueInfo* stateValueInfo);
+
+    // Notify registered state listeners of state change.
+    void notifyListeners(const int64_t eventTimeNs, const HashableDimensionKey& primaryKey,
+                         const int32_t oldState, const int32_t newState);
 };
 
+bool getStateFieldValueFromLogEvent(const LogEvent& event, FieldValue* output);
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android