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/FieldValue.h b/cmds/statsd/src/FieldValue.h
index 92e09ea..e251399 100644
--- a/cmds/statsd/src/FieldValue.h
+++ b/cmds/statsd/src/FieldValue.h
@@ -181,6 +181,7 @@
return false;
}
+
bool matches(const Matcher& that) const;
};
@@ -360,7 +361,9 @@
class Annotations {
public:
- Annotations() {}
+ Annotations() {
+ setNested(true); // Nested = true by default
+ }
// This enum stores where particular annotations can be found in the
// bitmask. Note that these pos do not correspond to annotation ids.
@@ -379,7 +382,9 @@
inline void setUidField(bool isUid) { setBitmaskAtPos(UID_POS, isUid); }
- inline void setResetState(int resetState) { mResetState = resetState; }
+ inline void setResetState(int32_t resetState) {
+ mResetState = resetState;
+ }
// Default value = false
inline bool isNested() const { return getValueFromBitmask(NESTED_POS); }
@@ -395,7 +400,9 @@
// If a reset state is not sent in the StatsEvent, returns -1. Note that a
// reset satate is only sent if and only if a reset should be triggered.
- inline int getResetState() const { return mResetState; }
+ inline int32_t getResetState() const {
+ return mResetState;
+ }
private:
inline void setBitmaskAtPos(int pos, bool value) {
@@ -411,7 +418,7 @@
// there are only 4 booleans, just one byte is required.
uint8_t mBooleanBitmask = 0;
- int mResetState = -1;
+ int32_t mResetState = -1;
};
/**
diff --git a/cmds/statsd/src/HashableDimensionKey.cpp b/cmds/statsd/src/HashableDimensionKey.cpp
index 29249f4..eba66e0 100644
--- a/cmds/statsd/src/HashableDimensionKey.cpp
+++ b/cmds/statsd/src/HashableDimensionKey.cpp
@@ -180,6 +180,23 @@
return num_matches > 0;
}
+bool filterPrimaryKey(const std::vector<FieldValue>& values, HashableDimensionKey* output) {
+ size_t num_matches = 0;
+ const int32_t simpleFieldMask = 0xff7f0000;
+ const int32_t attributionUidFieldMask = 0xff7f7f7f;
+ for (const auto& value : values) {
+ if (value.mAnnotations.isPrimaryField()) {
+ output->addValue(value);
+ output->mutableValue(num_matches)->mField.setTag(value.mField.getTag());
+ const int32_t mask =
+ isAttributionUidField(value) ? attributionUidFieldMask : simpleFieldMask;
+ output->mutableValue(num_matches)->mField.setField(value.mField.getField() & mask);
+ num_matches++;
+ }
+ }
+ return num_matches > 0;
+}
+
void filterGaugeValues(const std::vector<Matcher>& matcherFields,
const std::vector<FieldValue>& values, std::vector<FieldValue>* output) {
for (const auto& field : matcherFields) {
diff --git a/cmds/statsd/src/HashableDimensionKey.h b/cmds/statsd/src/HashableDimensionKey.h
index 33a5024..bd01100 100644
--- a/cmds/statsd/src/HashableDimensionKey.h
+++ b/cmds/statsd/src/HashableDimensionKey.h
@@ -154,6 +154,18 @@
HashableDimensionKey* output);
/**
+ * Creating HashableDimensionKeys from State Primary Keys in FieldValues.
+ *
+ * This function may make modifications to the Field if the matcher has Position=FIRST,LAST or ALL
+ * in it. This is because: for example, when we create dimension from last uid in attribution chain,
+ * In one event, uid 1000 is at position 5 and it's the last
+ * In another event, uid 1000 is at position 6, and it's the last
+ * these 2 events should be mapped to the same dimension. So we will remove the original position
+ * from the dimension key for the uid field (by applying 0x80 bit mask).
+ */
+bool filterPrimaryKey(const std::vector<FieldValue>& values, HashableDimensionKey* output);
+
+/**
* Filter the values from FieldValues using the matchers.
*
* In contrast to the above function, this function will not do any modification to the original
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 8b6a864..61cd017 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -293,7 +293,8 @@
}
const bool exclusiveState = readNextValue<uint8_t>();
- mValues[mValues.size() - 1].mAnnotations.setExclusiveState(exclusiveState);
+ mExclusiveStateFieldIndex = mValues.size() - 1;
+ mValues[getExclusiveStateFieldIndex()].mAnnotations.setExclusiveState(exclusiveState);
}
void LogEvent::parseTriggerStateResetAnnotation(uint8_t annotationType) {
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 4eeb7d6..c9c0305 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -170,6 +170,20 @@
return mAttributionChainIndex;
}
+ // Returns the index of the exclusive state field within the FieldValues vector if
+ // an exclusive state exists. If there is no exclusive state field, returns -1.
+ //
+ // If the index within the atom definition is desired, do the following:
+ // int vectorIndex = LogEvent.getExclusiveStateFieldIndex();
+ // if (vectorIndex != -1) {
+ // FieldValue& v = LogEvent.getValues()[vectorIndex];
+ // int atomIndex = v.mField.getPosAtDepth(0);
+ // }
+ // Note that atomIndex is 1-indexed.
+ inline int getExclusiveStateFieldIndex() const {
+ return mExclusiveStateFieldIndex;
+ }
+
inline LogEvent makeCopy() {
return LogEvent(*this);
}
@@ -297,6 +311,7 @@
bool mTruncateTimestamp = false;
int mUidFieldIndex = -1;
int mAttributionChainIndex = -1;
+ int mExclusiveStateFieldIndex = -1;
};
void writeExperimentIdsToProto(const std::vector<int64_t>& experimentIds, std::vector<uint8_t>* protoOut);
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 4550e65..6aba13ca 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -451,7 +451,7 @@
std::vector<int32_t> mSlicedStateAtoms;
// Maps atom ids and state values to group_ids (<atom_id, <value, group_id>>).
- std::unordered_map<int32_t, std::unordered_map<int, int64_t>> mStateGroupMap;
+ const std::unordered_map<int32_t, std::unordered_map<int, int64_t>> mStateGroupMap;
// MetricStateLinks defined in statsd_config that link fields in the state
// atom to fields in the "what" atom.
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 2fcb13b..88616dd 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -795,9 +795,7 @@
for (const auto& it : allMetricProducers) {
// Register metrics to StateTrackers
for (int atomId : it->getSlicedStateAtoms()) {
- if (!StateManager::getInstance().registerListener(atomId, it)) {
- return false;
- }
+ StateManager::getInstance().registerListener(atomId, it);
}
}
return true;
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
diff --git a/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
index a5da9c8..b1461a1 100644
--- a/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
@@ -232,7 +232,7 @@
StateMap map = state.map();
for (auto group : map.group()) {
for (auto value : group.value()) {
- EXPECT_EQ(metricProducer->mStateGroupMap[SCREEN_STATE_ATOM_ID][value],
+ EXPECT_EQ(metricProducer->mStateGroupMap.at(SCREEN_STATE_ATOM_ID).at(value),
group.group_id());
}
}
@@ -614,7 +614,7 @@
StateMap map = state1.map();
for (auto group : map.group()) {
for (auto value : group.value()) {
- EXPECT_EQ(metricProducer->mStateGroupMap[SCREEN_STATE_ATOM_ID][value],
+ EXPECT_EQ(metricProducer->mStateGroupMap.at(SCREEN_STATE_ATOM_ID).at(value),
group.group_id());
}
}
diff --git a/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp
index ba09a35..d59ec3e 100644
--- a/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp
@@ -921,18 +921,18 @@
bucket #1 bucket #2
| 1 2 3 4 5 6 7 8 (minutes)
|---------------------------------------|------------------
- ON OFF ON (BatterySaverMode)
+ ON OFF ON (BatterySaverMode)
T F T (DeviceUnpluggedPredicate)
- | | | (ScreenIsOnEvent)
+ | | | (ScreenIsOnEvent)
| | | (ScreenIsOffEvent)
| (ScreenDozeEvent)
*/
// Initialize log events.
std::vector<std::unique_ptr<LogEvent>> events;
- events.push_back(CreateBatterySaverOnEvent(bucketStartTimeNs + 20 * NS_PER_SEC)); // 0:30
events.push_back(CreateScreenStateChangedEvent(
- bucketStartTimeNs + 60 * NS_PER_SEC,
- android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 1:10
+ bucketStartTimeNs + 20 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 0:30
+ events.push_back(CreateBatterySaverOnEvent(bucketStartTimeNs + 60 * NS_PER_SEC)); // 1:10
events.push_back(CreateScreenStateChangedEvent(
bucketStartTimeNs + 80 * NS_PER_SEC,
android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 1:30
diff --git a/cmds/statsd/tests/state/StateTracker_test.cpp b/cmds/statsd/tests/state/StateTracker_test.cpp
index 78c80bc..ba2a4cf 100644
--- a/cmds/statsd/tests/state/StateTracker_test.cpp
+++ b/cmds/statsd/tests/state/StateTracker_test.cpp
@@ -19,6 +19,7 @@
#include "state/StateListener.h"
#include "state/StateManager.h"
+#include "state/StateTracker.h"
#include "stats_event.h"
#include "tests/statsd_test_util.h"
@@ -127,23 +128,23 @@
// Register listener to non-existing StateTracker
EXPECT_EQ(0, mgr.getStateTrackersCount());
- EXPECT_TRUE(mgr.registerListener(util::SCREEN_STATE_CHANGED, listener1));
+ mgr.registerListener(util::SCREEN_STATE_CHANGED, listener1);
EXPECT_EQ(1, mgr.getStateTrackersCount());
EXPECT_EQ(1, mgr.getListenersCount(util::SCREEN_STATE_CHANGED));
// Register listener to existing StateTracker
- EXPECT_TRUE(mgr.registerListener(util::SCREEN_STATE_CHANGED, listener2));
+ mgr.registerListener(util::SCREEN_STATE_CHANGED, listener2);
EXPECT_EQ(1, mgr.getStateTrackersCount());
EXPECT_EQ(2, mgr.getListenersCount(util::SCREEN_STATE_CHANGED));
// Register already registered listener to existing StateTracker
- EXPECT_TRUE(mgr.registerListener(util::SCREEN_STATE_CHANGED, listener2));
+ mgr.registerListener(util::SCREEN_STATE_CHANGED, listener2);
EXPECT_EQ(1, mgr.getStateTrackersCount());
EXPECT_EQ(2, mgr.getListenersCount(util::SCREEN_STATE_CHANGED));
// Register listener to non-state atom
- EXPECT_FALSE(mgr.registerListener(util::BATTERY_LEVEL_CHANGED, listener2));
- EXPECT_EQ(1, mgr.getStateTrackersCount());
+ mgr.registerListener(util::BATTERY_LEVEL_CHANGED, listener2);
+ EXPECT_EQ(2, mgr.getStateTrackersCount());
}
/**
@@ -249,6 +250,9 @@
EXPECT_EQ(1, listener->updates.size());
EXPECT_EQ(1000, listener->updates[0].mKey.getValues()[0].mValue.int_value);
EXPECT_EQ(BleScanStateChanged::ON, listener->updates[0].mState);
+ FieldValue stateFieldValue;
+ mgr.getStateValue(util::BLE_SCAN_STATE_CHANGED, listener->updates[0].mKey, &stateFieldValue);
+ EXPECT_EQ(BleScanStateChanged::ON, stateFieldValue.mValue.int_value);
listener->updates.clear();
std::unique_ptr<LogEvent> event2 =
@@ -258,6 +262,8 @@
EXPECT_EQ(1, listener->updates.size());
EXPECT_EQ(2000, listener->updates[0].mKey.getValues()[0].mValue.int_value);
EXPECT_EQ(BleScanStateChanged::ON, listener->updates[0].mState);
+ mgr.getStateValue(util::BLE_SCAN_STATE_CHANGED, listener->updates[0].mKey, &stateFieldValue);
+ EXPECT_EQ(BleScanStateChanged::ON, stateFieldValue.mValue.int_value);
listener->updates.clear();
std::unique_ptr<LogEvent> event3 =
@@ -265,8 +271,12 @@
BleScanStateChanged::RESET, false, false, false);
mgr.onLogEvent(*event3);
EXPECT_EQ(2, listener->updates.size());
- EXPECT_EQ(BleScanStateChanged::OFF, listener->updates[0].mState);
- EXPECT_EQ(BleScanStateChanged::OFF, listener->updates[1].mState);
+ for (const TestStateListener::Update& update : listener->updates) {
+ EXPECT_EQ(BleScanStateChanged::OFF, update.mState);
+
+ mgr.getStateValue(util::BLE_SCAN_STATE_CHANGED, update.mKey, &stateFieldValue);
+ EXPECT_EQ(BleScanStateChanged::OFF, stateFieldValue.mValue.int_value);
+ }
}
/**
@@ -352,13 +362,13 @@
// No state stored for this query key.
HashableDimensionKey queryKey2;
getPartialWakelockKey(1002 /* uid */, "tag1", &queryKey2);
- EXPECT_EQ(WakelockStateChanged::RELEASE,
+ EXPECT_EQ(-1 /*StateTracker::kStateUnknown*/,
getStateInt(mgr, util::WAKELOCK_STATE_CHANGED, queryKey2));
// Partial query fails.
HashableDimensionKey queryKey3;
getPartialWakelockKey(1001 /* uid */, &queryKey3);
- EXPECT_EQ(WakelockStateChanged::RELEASE,
+ EXPECT_EQ(-1 /*StateTracker::kStateUnknown*/,
getStateInt(mgr, util::WAKELOCK_STATE_CHANGED, queryKey3));
}
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index 687014f..7216e1d 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -569,6 +569,8 @@
AStatsEvent_setAtomId(statsEvent, util::SCREEN_STATE_CHANGED);
AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
AStatsEvent_writeInt32(statsEvent, state);
+ AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_EXCLUSIVE_STATE, true);
+ AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_STATE_NESTED, false);
std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
parseStatsEventToLogEvent(statsEvent, logEvent.get());
@@ -662,9 +664,14 @@
AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
writeAttribution(statsEvent, attributionUids, attributionTags);
+ AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID, true);
AStatsEvent_writeInt32(statsEvent, android::os::WakeLockLevelEnum::PARTIAL_WAKE_LOCK);
+ AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_PRIMARY_FIELD, true);
AStatsEvent_writeString(statsEvent, wakelockName.c_str());
+ AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_PRIMARY_FIELD, true);
AStatsEvent_writeInt32(statsEvent, state);
+ AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_EXCLUSIVE_STATE, true);
+ AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_STATE_NESTED, true);
std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
parseStatsEventToLogEvent(statsEvent, logEvent.get());
@@ -803,7 +810,11 @@
AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
AStatsEvent_writeInt32(statsEvent, uid);
+ AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_IS_UID, true);
+ AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_PRIMARY_FIELD, true);
AStatsEvent_writeInt32(statsEvent, state);
+ AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_EXCLUSIVE_STATE, true);
+ AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_STATE_NESTED, false);
std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
parseStatsEventToLogEvent(statsEvent, logEvent.get());
@@ -821,10 +832,20 @@
AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
writeAttribution(statsEvent, attributionUids, attributionTags);
+ AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID, true);
AStatsEvent_writeInt32(statsEvent, state);
- AStatsEvent_writeInt32(statsEvent, filtered); // filtered
- AStatsEvent_writeInt32(statsEvent, firstMatch); // first match
- AStatsEvent_writeInt32(statsEvent, opportunistic); // opportunistic
+ AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_EXCLUSIVE_STATE, true);
+ AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_STATE_NESTED, true);
+ if (state == util::BLE_SCAN_STATE_CHANGED__STATE__RESET) {
+ AStatsEvent_addInt32Annotation(statsEvent, ANNOTATION_ID_TRIGGER_STATE_RESET,
+ util::BLE_SCAN_STATE_CHANGED__STATE__OFF);
+ }
+ AStatsEvent_writeBool(statsEvent, filtered); // filtered
+ AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_PRIMARY_FIELD, true);
+ AStatsEvent_writeBool(statsEvent, firstMatch); // first match
+ AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_PRIMARY_FIELD, true);
+ AStatsEvent_writeBool(statsEvent, opportunistic); // opportunistic
+ AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_PRIMARY_FIELD, true);
std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
parseStatsEventToLogEvent(statsEvent, logEvent.get());
@@ -840,9 +861,14 @@
AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
AStatsEvent_writeInt32(statsEvent, uid);
+ AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_IS_UID, true);
+ AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_PRIMARY_FIELD, true);
AStatsEvent_writeString(statsEvent, packageName.c_str());
- AStatsEvent_writeInt32(statsEvent, usingAlertWindow);
+ AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_PRIMARY_FIELD, true);
+ AStatsEvent_writeBool(statsEvent, usingAlertWindow);
AStatsEvent_writeInt32(statsEvent, state);
+ AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_EXCLUSIVE_STATE, true);
+ AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_STATE_NESTED, false);
std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
parseStatsEventToLogEvent(statsEvent, logEvent.get());
diff --git a/tools/stats_log_api_gen/atoms_info_writer.cpp b/tools/stats_log_api_gen/atoms_info_writer.cpp
index 5fe9498..9261da6 100644
--- a/tools/stats_log_api_gen/atoms_info_writer.cpp
+++ b/tools/stats_log_api_gen/atoms_info_writer.cpp
@@ -26,26 +26,11 @@
namespace stats_log_api_gen {
static void write_atoms_info_header_body(FILE* out, const Atoms& atoms) {
- fprintf(out, "static int UNSET_VALUE = INT_MAX;\n");
- fprintf(out, "static int FIRST_UID_IN_CHAIN = 0;\n");
-
- fprintf(out, "struct StateAtomFieldOptions {\n");
- fprintf(out, " std::vector<int> primaryFields;\n");
- fprintf(out, " int exclusiveField;\n");
- fprintf(out, " int defaultState = UNSET_VALUE;\n");
- fprintf(out, " int resetState = UNSET_VALUE;\n");
- fprintf(out, " bool nested;\n");
- fprintf(out, "};\n");
- fprintf(out, "\n");
-
fprintf(out, "struct AtomsInfo {\n");
fprintf(out,
" const static std::set<int> "
"kTruncatingTimestampAtomBlackList;\n");
fprintf(out, " const static std::set<int> kAtomsWithAttributionChain;\n");
- fprintf(out,
- " const static std::map<int, StateAtomFieldOptions> "
- "kStateAtomsFieldOptions;\n");
fprintf(out, " const static std::set<int> kWhitelistedAtoms;\n");
fprintf(out, "};\n");
fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n", atoms.maxPushedAtomId);
@@ -100,49 +85,6 @@
fprintf(out, "};\n");
fprintf(out, "\n");
- fprintf(out,
- "static std::map<int, StateAtomFieldOptions> "
- "getStateAtomFieldOptions() {\n");
- fprintf(out, " std::map<int, StateAtomFieldOptions> options;\n");
- fprintf(out, " StateAtomFieldOptions* opt;\n");
- for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end();
- atomIt++) {
- if ((*atomIt)->primaryFields.size() == 0 && (*atomIt)->exclusiveField == 0) {
- continue;
- }
- fprintf(out,
- "\n // Adding primary and exclusive fields for atom "
- "(%d)%s\n",
- (*atomIt)->code, (*atomIt)->name.c_str());
- fprintf(out, " opt = &(options[%d /* %s */]);\n", (*atomIt)->code,
- make_constant_name((*atomIt)->name).c_str());
- fprintf(out, " opt->primaryFields.reserve(%lu);\n", (*atomIt)->primaryFields.size());
- for (const auto& field : (*atomIt)->primaryFields) {
- fprintf(out, " opt->primaryFields.push_back(%d);\n", field);
- }
-
- fprintf(out, " opt->exclusiveField = %d;\n", (*atomIt)->exclusiveField);
- if ((*atomIt)->defaultState != INT_MAX) {
- fprintf(out, " opt->defaultState = %d;\n", (*atomIt)->defaultState);
- } else {
- fprintf(out, " opt->defaultState = UNSET_VALUE;\n");
- }
-
- if ((*atomIt)->triggerStateReset != INT_MAX) {
- fprintf(out, " opt->resetState = %d;\n", (*atomIt)->triggerStateReset);
- } else {
- fprintf(out, " opt->resetState = UNSET_VALUE;\n");
- }
- fprintf(out, " opt->nested = %d;\n", (*atomIt)->nested);
- }
-
- fprintf(out, " return options;\n");
- fprintf(out, "}\n");
-
- fprintf(out,
- "const std::map<int, StateAtomFieldOptions> "
- "AtomsInfo::kStateAtomsFieldOptions = "
- "getStateAtomFieldOptions();\n");
}
int write_atoms_info_header(FILE* out, const Atoms& atoms, const string& namespaceStr) {