Merge "Remove kStateAtomsInfo from atoms_info." into rvc-dev

This commit is contained in:
Muhammad Qureshi
2020-04-16 13:01:52 +00:00
committed by Android (Google) Code Review
16 changed files with 236 additions and 263 deletions

View File

@@ -181,6 +181,7 @@ public:
return false;
}
bool matches(const Matcher& that) const;
};
@@ -360,7 +361,9 @@ struct Value {
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 @@ public:
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 @@ public:
// 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 @@ private:
// there are only 4 booleans, just one byte is required.
uint8_t mBooleanBitmask = 0;
int mResetState = -1;
int32_t mResetState = -1;
};
/**

View File

@@ -180,6 +180,23 @@ bool filterValues(const vector<Matcher>& matcherFields, const vector<FieldValue>
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) {

View File

@@ -153,6 +153,18 @@ bool filterValues(const Matcher& matcherField, const std::vector<FieldValue>& va
bool filterValues(const std::vector<Matcher>& matcherFields, const std::vector<FieldValue>& values,
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.
*

View File

@@ -293,7 +293,8 @@ void LogEvent::parseExclusiveStateAnnotation(uint8_t annotationType) {
}
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) {

View File

@@ -170,6 +170,20 @@ public:
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 @@ private:
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);

View File

@@ -451,7 +451,7 @@ protected:
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.

View File

@@ -795,9 +795,7 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
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;

View File

@@ -38,20 +38,12 @@ void StateManager::onLogEvent(const LogEvent& event) {
}
}
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) {

View File

@@ -45,10 +45,11 @@ public:
// 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.

View File

@@ -25,81 +25,43 @@ namespace android {
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 @@ void StateTracker::unregisterListener(wp<StateListener> listener) {
}
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 @@ void StateTracker::updateState(const HashableDimensionKey& primaryKey, const int
// 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

View File

@@ -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 @@ namespace statsd {
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 @@ public:
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 @@ private:
// 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

View File

@@ -232,7 +232,7 @@ TEST(CountMetricE2eTest, TestSlicedStateWithMap) {
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 @@ TEST(CountMetricE2eTest, TestMultipleSlicedStates) {
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());
}
}

View File

@@ -921,18 +921,18 @@ TEST(DurationMetricE2eTest, TestWithConditionAndSlicedState) {
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

View File

@@ -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 @@ TEST(StateTrackerTest, TestRegisterListener) {
// 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 @@ TEST(StateTrackerTest, TestStateChangeReset) {
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 @@ TEST(StateTrackerTest, TestStateChangeReset) {
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 @@ TEST(StateTrackerTest, TestStateChangeReset) {
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 @@ TEST(StateTrackerTest, TestStateChangePrimaryFieldAttrChain) {
// 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));
}

View File

@@ -569,6 +569,8 @@ std::unique_ptr<LogEvent> CreateScreenStateChangedEvent(
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 @@ std::unique_ptr<LogEvent> CreateWakelockStateChangedEvent(uint64_t timestampNs,
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 @@ std::unique_ptr<LogEvent> CreateUidProcessStateChangedEvent(
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 @@ std::unique_ptr<LogEvent> CreateBleScanStateChangedEvent(uint64_t timestampNs,
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 @@ std::unique_ptr<LogEvent> CreateOverlayStateChangedEvent(int64_t timestampNs, co
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());

View File

@@ -26,26 +26,11 @@ namespace android {
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 @@ static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
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) {