summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/statsd/src/atom_field_options.proto69
-rw-r--r--cmds/statsd/src/atoms.proto52
-rw-r--r--cmds/statsd/src/state/StateTracker.cpp80
-rw-r--r--cmds/statsd/src/state/StateTracker.h2
-rw-r--r--cmds/statsd/tests/state/StateTracker_test.cpp103
-rw-r--r--tools/stats_log_api_gen/Collation.cpp46
-rw-r--r--tools/stats_log_api_gen/Collation.h3
-rw-r--r--tools/stats_log_api_gen/atoms_info_writer.cpp28
-rw-r--r--tools/stats_log_api_gen/test.proto35
9 files changed, 314 insertions, 104 deletions
diff --git a/cmds/statsd/src/atom_field_options.proto b/cmds/statsd/src/atom_field_options.proto
index 946c55087005..9c875ba7502d 100644
--- a/cmds/statsd/src/atom_field_options.proto
+++ b/cmds/statsd/src/atom_field_options.proto
@@ -24,46 +24,75 @@ option java_outer_classname = "AtomFieldOptions";
import "google/protobuf/descriptor.proto";
enum StateField {
- // Default value for fields that are not primary or exclusive state.
+ // Default value for fields that are not a primary or exclusive state field.
STATE_FIELD_UNSET = 0;
// Fields that represent the key that the state belongs to.
- PRIMARY = 1;
+ // Used on simple proto fields. Do not use on attribution chains.
+ PRIMARY_FIELD = 1;
// The field that represents the state. It's an exclusive state.
- EXCLUSIVE = 2;
-
+ EXCLUSIVE_STATE = 2;
+ // Used on an attribution chain field to indicate that the first uid is the
+ // primary field.
PRIMARY_FIELD_FIRST_UID = 3;
}
-// Used to annotate an atom that reprsents a state change. A state change atom must have exactly ONE
-// exclusive state field, and any number of primary key fields.
-// For example,
-// message UidProcessStateChanged {
-// optional int32 uid = 1 [(state_field_option).option = PRIMARY];
-// optional android.app.ProcessStateEnum state = 2 [(state_field_option).option = EXCLUSIVE];
+// Used to annotate an atom that represents a state change. A state change atom must have exactly
+// ONE exclusive state field, and any number of primary key fields. For example, message
+// UidProcessStateChanged {
+// optional int32 uid = 1 [(state_field_option).option = PRIMARY_FIELD];
+// optional android.app.ProcessStateEnum state = 2 [(state_field_option).option =
+// EXCLUSIVE_STATE];
// }
-// Each of this UidProcessStateChanged atom represents a state change for a specific uid.
+// Each UidProcessStateChanged atom event represents a state change for a specific uid.
// A new state automatically overrides the previous state.
//
-// If the atom has 2 or more primary fields, it means the combination of the primary fields are
-// the primary key.
+// If the atom has 2 or more primary fields, it means the combination of the
+// primary fields are the primary key.
// For example:
// message ThreadStateChanged {
-// optional int32 pid = 1 [(state_field_option).option = PRIMARY];
-// optional int32 tid = 2 [(state_field_option).option = PRIMARY];
-// optional int32 state = 3 [(state_field_option).option = EXCLUSIVE];
+// optional int32 pid = 1 [(state_field_option).option = PRIMARY_FIELD];
+// optional int32 tid = 2 [(state_field_option).option = PRIMARY_FIELD];
+// optional int32 state = 3 [(state_field_option).option = EXCLUSIVE_STATE];
// }
//
// Sometimes, there is no primary key field, when the state is GLOBAL.
// For example,
-//
// message ScreenStateChanged {
-// optional android.view.DisplayStateEnum state = 1 [(state_field_option).option = EXCLUSIVE];
+// optional android.view.DisplayStateEnum state = 1 [(state_field_option).option =
+// EXCLUSIVE_STATE];
// }
//
-// Only fields of primary types can be annotated. AttributionNode cannot be primary keys (and they
-// usually are not).
+// For state atoms with attribution chain, sometimes the primary key is the first uid in the chain.
+// For example:
+// message AudioStateChanged {
+// repeated AttributionNode attribution_node = 1
+// [(stateFieldOption).option = PRIMARY_KEY_FIRST_UID];
+//
+// enum State {
+// OFF = 0;
+// ON = 1;
+// // RESET indicates all audio stopped. Used when it (re)starts (e.g. after it crashes).
+// RESET = 2;
+// }
+// optional State state = 2 [(stateFieldOption).option = EXCLUSIVE_STATE];
+// }
message StateAtomFieldOption {
optional StateField option = 1 [default = STATE_FIELD_UNSET];
+
+ // Note: We cannot annotate directly on the enums because many enums are imported from other
+ // proto files in the platform. proto-lite cc library does not support annotations unfortunately
+
+ // Knowing the default state value allows state trackers to remove entries that become the
+ // default state. If there is no default value specified, the default value is unknown, and all
+ // states will be tracked in memory.
+ optional int32 default_state_value = 2;
+
+ // A reset state signals all states go to default value. For example, BLE reset means all active
+ // BLE scans are to be turned off.
+ optional int32 reset_state_value = 3;
+
+ // If the state change needs to count nesting.
+ optional bool nested = 4 [default = true];
}
// Used to generate StatsLog.write APIs.
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index cbece78ec355..4388a08a9016 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -508,7 +508,8 @@ message ThermalThrottlingStateChanged {
*/
message ScreenStateChanged {
// New screen state, from frameworks/base/core/proto/android/view/enums.proto.
- optional android.view.DisplayStateEnum state = 1 [(state_field_option).option = EXCLUSIVE];
+ optional android.view.DisplayStateEnum state = 1
+ [(state_field_option).option = EXCLUSIVE_STATE, (state_field_option).nested = false];
}
/**
@@ -519,10 +520,11 @@ message ScreenStateChanged {
* frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
*/
message UidProcessStateChanged {
- optional int32 uid = 1 [(state_field_option).option = PRIMARY, (is_uid) = true];
+ optional int32 uid = 1 [(state_field_option).option = PRIMARY_FIELD, (is_uid) = true];
// The state, from frameworks/base/core/proto/android/app/enums.proto.
- optional android.app.ProcessStateEnum state = 2 [(state_field_option).option = EXCLUSIVE];
+ optional android.app.ProcessStateEnum state = 2
+ [(state_field_option).option = EXCLUSIVE_STATE, (state_field_option).nested = false];
}
/**
@@ -554,7 +556,7 @@ message ActivityManagerSleepStateChanged {
ASLEEP = 1;
AWAKE = 2;
}
- optional State state = 1 [(state_field_option).option = EXCLUSIVE];
+ optional State state = 1 [(state_field_option).option = EXCLUSIVE_STATE];
}
/**
@@ -573,7 +575,7 @@ message MemoryFactorStateChanged {
CRITICAL = 4; // critical memory.
}
- optional State factor = 1 [(state_field_option).option = EXCLUSIVE];
+ optional State factor = 1 [(state_field_option).option = EXCLUSIVE_STATE];
}
/**
@@ -660,7 +662,8 @@ message ProcessLifeCycleStateChanged {
* packages/apps/Bluetooth/src/com/android/bluetooth/gatt/AppScanStats.java
*/
message BleScanStateChanged {
- repeated AttributionNode attribution_node = 1;
+ repeated AttributionNode attribution_node = 1
+ [(state_field_option).option = PRIMARY_FIELD_FIRST_UID];
enum State {
OFF = 0;
@@ -668,14 +671,19 @@ message BleScanStateChanged {
// RESET indicates all ble stopped. Used when it (re)starts (e.g. after it crashes).
RESET = 2;
}
- optional State state = 2;
+ optional State state = 2 [
+ (state_field_option).option = EXCLUSIVE_STATE,
+ (state_field_option).default_state_value = 0 /* State.OFF */,
+ (state_field_option).reset_state_value = 2 /* State.RESET */,
+ (state_field_option).nested = true
+ ];
// Does the scan have a filter.
- optional bool is_filtered = 3;
+ optional bool is_filtered = 3 [(state_field_option).option = PRIMARY_FIELD];
// Whether the scan is a CALLBACK_TYPE_FIRST_MATCH scan. Called 'background' scan internally.
- optional bool is_first_match = 4;
+ optional bool is_first_match = 4 [(state_field_option).option = PRIMARY_FIELD];
// Whether the scan set to piggy-back off the results of other scans (SCAN_MODE_OPPORTUNISTIC).
- optional bool is_opportunistic = 5;
+ optional bool is_opportunistic = 5 [(state_field_option).option = PRIMARY_FIELD];
}
/**
@@ -919,11 +927,11 @@ message WakelockStateChanged {
// The type (level) of the wakelock; e.g. a partial wakelock or a full wakelock.
// From frameworks/base/core/proto/android/os/enums.proto.
- optional android.os.WakeLockLevelEnum type = 2 [(state_field_option).option = PRIMARY];
+ optional android.os.WakeLockLevelEnum type = 2 [(state_field_option).option = PRIMARY_FIELD];
;
// The wakelock tag (Called tag in the Java API, sometimes name elsewhere).
- optional string tag = 3 [(state_field_option).option = PRIMARY];
+ optional string tag = 3 [(state_field_option).option = PRIMARY_FIELD];
enum State {
RELEASE = 0;
@@ -931,7 +939,11 @@ message WakelockStateChanged {
CHANGE_RELEASE = 2;
CHANGE_ACQUIRE = 3;
}
- optional State state = 4 [(state_field_option).option = EXCLUSIVE];
+ optional State state = 4 [
+ (state_field_option).option = EXCLUSIVE_STATE,
+ (state_field_option).default_state_value = 0,
+ (state_field_option).nested = true
+ ];
}
/**
@@ -3114,9 +3126,9 @@ message PictureInPictureStateChanged {
* services/core/java/com/android/server/wm/Session.java
*/
message OverlayStateChanged {
- optional int32 uid = 1 [(state_field_option).option = PRIMARY, (is_uid) = true];
+ optional int32 uid = 1 [(state_field_option).option = PRIMARY_FIELD, (is_uid) = true];
- optional string package_name = 2 [(state_field_option).option = PRIMARY];
+ optional string package_name = 2 [(state_field_option).option = PRIMARY_FIELD];
optional bool using_alert_window = 3;
@@ -3124,7 +3136,11 @@ message OverlayStateChanged {
ENTERED = 1;
EXITED = 2;
}
- optional State state = 4 [(state_field_option).option = EXCLUSIVE];
+ optional State state = 4 [
+ (state_field_option).option = EXCLUSIVE_STATE,
+ (state_field_option).nested = false,
+ (state_field_option).default_state_value = 2
+ ];
}
/*
@@ -3290,7 +3306,7 @@ message LmkKillOccurred {
*/
message AppDied {
// timestamp(elapsedRealtime) of record creation
- optional uint64 timestamp_millis = 1 [(state_field_option).option = EXCLUSIVE];
+ optional uint64 timestamp_millis = 1 [(state_field_option).option = EXCLUSIVE_STATE];
}
/**
@@ -3685,7 +3701,7 @@ message PrivacyIndicatorsInteracted {
DIALOG_LINE_ITEM = 5;
}
- optional Type type = 1 [(state_field_option).option = EXCLUSIVE];
+ optional Type type = 1 [(state_field_option).option = EXCLUSIVE_STATE];
// Used if the type is LINE_ITEM
optional string package_name = 2;
diff --git a/cmds/statsd/src/state/StateTracker.cpp b/cmds/statsd/src/state/StateTracker.cpp
index 3ad21e0c96ae..ab861275073c 100644
--- a/cmds/statsd/src/state/StateTracker.cpp
+++ b/cmds/statsd/src/state/StateTracker.cpp
@@ -26,7 +26,9 @@ namespace os {
namespace statsd {
StateTracker::StateTracker(const int32_t atomId, const util::StateAtomFieldOptions& stateAtomInfo)
- : mAtomId(atomId), mStateField(getSimpleMatcher(atomId, stateAtomInfo.exclusiveField)) {
+ : 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) {
@@ -38,7 +40,13 @@ StateTracker::StateTracker(const int32_t atomId, const util::StateAtomFieldOptio
}
}
- // TODO(tsaichristine): b/142108433 set default state, reset state, and nesting
+ if (stateAtomInfo.defaultState != util::UNSET_VALUE) {
+ mDefaultState = stateAtomInfo.defaultState;
+ }
+
+ if (stateAtomInfo.resetState != util::UNSET_VALUE) {
+ mResetState = stateAtomInfo.resetState;
+ }
}
void StateTracker::onLogEvent(const LogEvent& event) {
@@ -60,7 +68,6 @@ void StateTracker::onLogEvent(const LogEvent& event) {
// 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",
@@ -68,11 +75,12 @@ void StateTracker::onLogEvent(const LogEvent& event) {
handlePartialReset(eventTimeNs, primaryKey);
return;
}
- state = stateValue.mValue.int_value;
+ int32_t state = stateValue.mValue.int_value;
if (state == mResetState) {
VLOG("StateTracker Reset state: %s", stateValue.mValue.toString().c_str());
handleReset(eventTimeNs);
+ return;
}
// Track and update state.
@@ -113,15 +121,17 @@ bool StateTracker::getStateValue(const HashableDimensionKey& queryKey, FieldValu
return true;
}
} else if (queryKey.getValues().size() > mPrimaryFields.size()) {
- ALOGE("StateTracker query key size > primary key size is illegal");
+ ALOGE("StateTracker query key size %zu > primary key size %zu is illegal",
+ queryKey.getValues().size(), mPrimaryFields.size());
} else {
- ALOGE("StateTracker query key size < primary key size is not supported");
+ ALOGE("StateTracker query key size %zu < primary key size %zu is not supported",
+ queryKey.getValues().size(), mPrimaryFields.size());
}
- // Set the state value to unknown if:
+ // Set the state value to default state if:
// - query key size is incorrect
// - query key is not found in state map
- output->mValue = StateTracker::kStateUnknown;
+ output->mValue = mDefaultState;
return false;
}
@@ -164,18 +174,52 @@ void StateTracker::updateState(const HashableDimensionKey& primaryKey, const int
*oldState = mDefaultState;
}
- // update state map
- 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;
+ // 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;
+ }
+ *newState = eventState;
+ return;
}
- *newState = eventState;
- // TODO(tsaichristine): support atoms with nested counting
+ // Update state map for nested counting case.
+ //
+ // Nested counting is only allowed for binary state events such as ON/OFF or
+ // ACQUIRE/RELEASE. For example, WakelockStateChanged might have the state
+ // events: ON, ON, OFF. The state will still be ON until we see the same
+ // 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;
+ }
+ } else {
+ if (eventState != mDefaultState) {
+ mStateMap[primaryKey].state = eventState;
+ mStateMap[primaryKey].count = 1;
+ }
+ *newState = eventState;
+ }
}
} // namespace statsd
diff --git a/cmds/statsd/src/state/StateTracker.h b/cmds/statsd/src/state/StateTracker.h
index 70f16274c7f6..aeca2a53bfdc 100644
--- a/cmds/statsd/src/state/StateTracker.h
+++ b/cmds/statsd/src/state/StateTracker.h
@@ -74,6 +74,8 @@ private:
int32_t mResetState = kStateUnknown;
+ const bool mNested;
+
// Maps primary key to state value info
std::unordered_map<HashableDimensionKey, StateValueInfo> mStateMap;
diff --git a/cmds/statsd/tests/state/StateTracker_test.cpp b/cmds/statsd/tests/state/StateTracker_test.cpp
index 84aaa54bc5bf..b0acd5ad7452 100644
--- a/cmds/statsd/tests/state/StateTracker_test.cpp
+++ b/cmds/statsd/tests/state/StateTracker_test.cpp
@@ -127,6 +127,23 @@ std::shared_ptr<LogEvent> buildOverlayEventBadStateType(int uid, const std::stri
event->init();
return event;
}
+
+std::shared_ptr<LogEvent> buildBleScanEvent(int uid, bool acquire, bool reset) {
+ std::vector<AttributionNodeInternal> chain;
+ chain.push_back(AttributionNodeInternal());
+ AttributionNodeInternal& attr = chain.back();
+ attr.set_uid(uid);
+
+ std::shared_ptr<LogEvent> event =
+ std::make_shared<LogEvent>(android::util::BLE_SCAN_STATE_CHANGED, 1000);
+ event->write(chain);
+ event->write(reset ? 2 : acquire ? 1 : 0); // PARTIAL_WAKE_LOCK
+ event->write(0); // filtered
+ event->write(0); // first match
+ event->write(0); // opportunistic
+ event->init();
+ return event;
+}
// END: build event functions.
// START: get primary key functions
@@ -277,6 +294,80 @@ TEST(StateTrackerTest, TestUnregisterListener) {
}
/**
+ * Test a binary state atom with nested counting.
+ *
+ * To go from an "ON" state to an "OFF" state with nested counting, we must see
+ * an equal number of "OFF" events as "ON" events.
+ * For example, ACQUIRE, ACQUIRE, RELEASE will still be in the ACQUIRE state.
+ * ACQUIRE, ACQUIRE, RELEASE, RELEASE will be in the RELEASE state.
+ */
+TEST(StateTrackerTest, TestStateChangeNested) {
+ sp<TestStateListener> listener = new TestStateListener();
+ StateManager mgr;
+ mgr.registerListener(android::util::WAKELOCK_STATE_CHANGED, listener);
+
+ std::shared_ptr<LogEvent> event1 =
+ buildPartialWakelockEvent(1000 /* uid */, "tag", true /*acquire*/);
+ mgr.onLogEvent(*event1);
+ EXPECT_EQ(1, listener->updates.size());
+ EXPECT_EQ(1000, listener->updates[0].mKey.getValues()[0].mValue.int_value);
+ EXPECT_EQ(1, listener->updates[0].mState);
+ listener->updates.clear();
+
+ std::shared_ptr<LogEvent> event2 =
+ buildPartialWakelockEvent(1000 /* uid */, "tag", true /*acquire*/);
+ mgr.onLogEvent(*event2);
+ EXPECT_EQ(0, listener->updates.size());
+
+ std::shared_ptr<LogEvent> event3 =
+ buildPartialWakelockEvent(1000 /* uid */, "tag", false /*release*/);
+ mgr.onLogEvent(*event3);
+ EXPECT_EQ(0, listener->updates.size());
+
+ std::shared_ptr<LogEvent> event4 =
+ buildPartialWakelockEvent(1000 /* uid */, "tag", false /*release*/);
+ mgr.onLogEvent(*event4);
+ EXPECT_EQ(1, listener->updates.size());
+ EXPECT_EQ(1000, listener->updates[0].mKey.getValues()[0].mValue.int_value);
+ EXPECT_EQ(0, listener->updates[0].mState);
+}
+
+/**
+ * Test a state atom with a reset state.
+ *
+ * If the reset state value is seen, every state in the map is set to the default
+ * state and every listener is notified.
+ */
+TEST(StateTrackerTest, TestStateChangeReset) {
+ sp<TestStateListener> listener = new TestStateListener();
+ StateManager mgr;
+ mgr.registerListener(android::util::BLE_SCAN_STATE_CHANGED, listener);
+
+ std::shared_ptr<LogEvent> event1 =
+ buildBleScanEvent(1000 /* uid */, true /*acquire*/, false /*reset*/);
+ mgr.onLogEvent(*event1);
+ 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);
+ listener->updates.clear();
+
+ std::shared_ptr<LogEvent> event2 =
+ buildBleScanEvent(2000 /* uid */, true /*acquire*/, false /*reset*/);
+ mgr.onLogEvent(*event2);
+ 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);
+ listener->updates.clear();
+
+ std::shared_ptr<LogEvent> event3 =
+ buildBleScanEvent(2000 /* uid */, false /*acquire*/, true /*reset*/);
+ 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);
+}
+
+/**
* Test StateManager's onLogEvent and StateListener's onStateChanged correctly
* updates listener for states without primary keys.
*/
@@ -334,7 +425,7 @@ TEST(StateTrackerTest, TestStateChangePrimaryFieldAttrChain) {
// Log event.
std::shared_ptr<LogEvent> event =
- buildPartialWakelockEvent(1001 /* uid */, "tag1", false /* acquire */);
+ buildPartialWakelockEvent(1001 /* uid */, "tag1", true /* acquire */);
mgr.onLogEvent(*event);
EXPECT_EQ(1, mgr.getStateTrackersCount());
@@ -346,23 +437,25 @@ TEST(StateTrackerTest, TestStateChangePrimaryFieldAttrChain) {
EXPECT_EQ(1001, listener1->updates[0].mKey.getValues()[0].mValue.int_value);
EXPECT_EQ(1, listener1->updates[0].mKey.getValues()[1].mValue.int_value);
EXPECT_EQ("tag1", listener1->updates[0].mKey.getValues()[2].mValue.str_value);
- EXPECT_EQ(WakelockStateChanged::RELEASE, listener1->updates[0].mState);
+ EXPECT_EQ(WakelockStateChanged::ACQUIRE, listener1->updates[0].mState);
// Check StateTracker was updated by querying for state.
HashableDimensionKey queryKey;
getPartialWakelockKey(1001 /* uid */, "tag1", &queryKey);
- EXPECT_EQ(WakelockStateChanged::RELEASE,
+ EXPECT_EQ(WakelockStateChanged::ACQUIRE,
getStateInt(mgr, android::util::WAKELOCK_STATE_CHANGED, queryKey));
// No state stored for this query key.
HashableDimensionKey queryKey2;
getPartialWakelockKey(1002 /* uid */, "tag1", &queryKey2);
- EXPECT_EQ(-1, getStateInt(mgr, android::util::WAKELOCK_STATE_CHANGED, queryKey2));
+ EXPECT_EQ(WakelockStateChanged::RELEASE,
+ getStateInt(mgr, android::util::WAKELOCK_STATE_CHANGED, queryKey2));
// Partial query fails.
HashableDimensionKey queryKey3;
getPartialWakelockKey(1001 /* uid */, &queryKey3);
- EXPECT_EQ(-1, getStateInt(mgr, android::util::WAKELOCK_STATE_CHANGED, queryKey3));
+ EXPECT_EQ(WakelockStateChanged::RELEASE,
+ getStateInt(mgr, android::util::WAKELOCK_STATE_CHANGED, queryKey3));
}
/**
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index 7bbac137f998..e104e4ecbf92 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -40,18 +40,21 @@ AtomDecl::AtomDecl()
{
}
-AtomDecl::AtomDecl(const AtomDecl& that)
- : code(that.code),
- name(that.name),
- message(that.message),
- fields(that.fields),
- primaryFields(that.primaryFields),
- exclusiveField(that.exclusiveField),
- uidField(that.uidField),
- whitelisted(that.whitelisted),
- binaryFields(that.binaryFields),
- hasModule(that.hasModule),
- moduleName(that.moduleName) {}
+AtomDecl::AtomDecl(const AtomDecl &that)
+ : code(that.code),
+ name(that.name),
+ message(that.message),
+ fields(that.fields),
+ primaryFields(that.primaryFields),
+ exclusiveField(that.exclusiveField),
+ defaultState(that.defaultState),
+ resetState(that.resetState),
+ nested(that.nested),
+ uidField(that.uidField),
+ whitelisted(that.whitelisted),
+ binaryFields(that.binaryFields),
+ hasModule(that.hasModule),
+ moduleName(that.moduleName) {}
AtomDecl::AtomDecl(int c, const string& n, const string& m)
:code(c),
@@ -281,7 +284,7 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl,
atomDecl->fields.push_back(atField);
if (field->options().GetExtension(os::statsd::state_field_option).option() ==
- os::statsd::StateField::PRIMARY) {
+ os::statsd::StateField::PRIMARY_FIELD) {
if (javaType == JAVA_TYPE_UNKNOWN ||
javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
@@ -300,7 +303,7 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl,
}
if (field->options().GetExtension(os::statsd::state_field_option).option() ==
- os::statsd::StateField::EXCLUSIVE) {
+ os::statsd::StateField::EXCLUSIVE_STATE) {
if (javaType == JAVA_TYPE_UNKNOWN ||
javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
@@ -312,6 +315,21 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl,
} else {
errorCount++;
}
+
+ if (field->options()
+ .GetExtension(os::statsd::state_field_option)
+ .has_default_state_value()) {
+ atomDecl->defaultState = field->options()
+ .GetExtension(os::statsd::state_field_option)
+ .default_state_value();
+ }
+
+ if (field->options().GetExtension(os::statsd::state_field_option).has_reset_state_value()) {
+ atomDecl->resetState = field->options()
+ .GetExtension(os::statsd::state_field_option)
+ .reset_state_value();
+ }
+ atomDecl->nested = field->options().GetExtension(os::statsd::state_field_option).nested();
}
if (field->options().GetExtension(os::statsd::is_uid) == true) {
diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h
index 87d4d5db0cee..65d8e3efee5b 100644
--- a/tools/stats_log_api_gen/Collation.h
+++ b/tools/stats_log_api_gen/Collation.h
@@ -88,6 +88,9 @@ struct AtomDecl {
vector<int> primaryFields;
int exclusiveField = 0;
+ int defaultState = INT_MAX;
+ int resetState = INT_MAX;
+ bool nested;
int uidField = 0;
diff --git a/tools/stats_log_api_gen/atoms_info_writer.cpp b/tools/stats_log_api_gen/atoms_info_writer.cpp
index 66ae96401974..984c929f63bd 100644
--- a/tools/stats_log_api_gen/atoms_info_writer.cpp
+++ b/tools/stats_log_api_gen/atoms_info_writer.cpp
@@ -25,11 +25,15 @@ 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");
@@ -126,7 +130,7 @@ static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
"static std::map<int, StateAtomFieldOptions> "
"getStateAtomFieldOptions() {\n");
fprintf(out, " std::map<int, StateAtomFieldOptions> options;\n");
- fprintf(out, " StateAtomFieldOptions opt;\n");
+ fprintf(out, " StateAtomFieldOptions* opt;\n");
for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
atom != atoms.decls.end(); atom++) {
if (atom->primaryFields.size() == 0 && atom->exclusiveField == 0) {
@@ -136,14 +140,26 @@ static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
"\n // Adding primary and exclusive fields for atom "
"(%d)%s\n",
atom->code, atom->name.c_str());
- fprintf(out, " opt.primaryFields.clear();\n");
+ fprintf(out, " opt = &(options[static_cast<int>(%s)]);\n",
+ make_constant_name(atom->name).c_str());
+ fprintf(out, " opt->primaryFields.reserve(%lu);\n", atom->primaryFields.size());
for (const auto& field : atom->primaryFields) {
- fprintf(out, " opt.primaryFields.push_back(%d);\n", field);
+ fprintf(out, " opt->primaryFields.push_back(%d);\n", field);
}
- fprintf(out, " opt.exclusiveField = %d;\n", atom->exclusiveField);
- fprintf(out, " options[static_cast<int>(%s)] = opt;\n",
- make_constant_name(atom->name).c_str());
+ fprintf(out, " opt->exclusiveField = %d;\n", atom->exclusiveField);
+ if (atom->defaultState != INT_MAX) {
+ fprintf(out, " opt->defaultState = %d;\n", atom->defaultState);
+ } else {
+ fprintf(out, " opt->defaultState = UNSET_VALUE;\n");
+ }
+
+ if (atom->resetState != INT_MAX) {
+ fprintf(out, " opt->resetState = %d;\n", atom->resetState);
+ } else {
+ fprintf(out, " opt->resetState = UNSET_VALUE;\n");
+ }
+ fprintf(out, " opt->nested = %d;\n", atom->nested);
}
fprintf(out, " return options;\n");
diff --git a/tools/stats_log_api_gen/test.proto b/tools/stats_log_api_gen/test.proto
index c9a47632b4bb..b892194410ae 100644
--- a/tools/stats_log_api_gen/test.proto
+++ b/tools/stats_log_api_gen/test.proto
@@ -148,53 +148,42 @@ message GoodStateAtoms {
// The atom has only primary field but no exclusive state field.
message BadStateAtom1 {
- optional int32 uid = 1
- [(android.os.statsd.state_field_option).option = PRIMARY];
+ optional int32 uid = 1 [(android.os.statsd.state_field_option).option = PRIMARY_FIELD];
}
// Only primative types can be annotated.
message BadStateAtom2 {
repeated android.os.statsd.AttributionNode attribution = 1
- [(android.os.statsd.state_field_option).option = PRIMARY];
- optional int32 state = 2
- [(android.os.statsd.state_field_option).option = EXCLUSIVE];
+ [(android.os.statsd.state_field_option).option = PRIMARY_FIELD];
+ optional int32 state = 2 [(android.os.statsd.state_field_option).option = EXCLUSIVE_STATE];
}
// Having 2 exclusive state field in the atom means the atom is badly designed.
// E.g., putting bluetooth state and wifi state in the same atom.
message BadStateAtom3 {
- optional int32 uid = 1
- [(android.os.statsd.state_field_option).option = PRIMARY];
- optional int32 state = 2
- [(android.os.statsd.state_field_option).option = EXCLUSIVE];
- optional int32 state2 = 3
- [(android.os.statsd.state_field_option).option = EXCLUSIVE];
+ optional int32 uid = 1 [(android.os.statsd.state_field_option).option = PRIMARY_FIELD];
+ optional int32 state = 2 [(android.os.statsd.state_field_option).option = EXCLUSIVE_STATE];
+ optional int32 state2 = 3 [(android.os.statsd.state_field_option).option = EXCLUSIVE_STATE];
}
message GoodStateAtom1 {
- optional int32 uid = 1
- [(android.os.statsd.state_field_option).option = PRIMARY];
- optional int32 state = 2
- [(android.os.statsd.state_field_option).option = EXCLUSIVE];
+ optional int32 uid = 1 [(android.os.statsd.state_field_option).option = PRIMARY_FIELD];
+ optional int32 state = 2 [(android.os.statsd.state_field_option).option = EXCLUSIVE_STATE];
}
// Atoms can have exclusive state field, but no primary field. That means
// the state is globally exclusive (e.g., DisplayState).
message GoodStateAtom2 {
optional int32 uid = 1;
- optional int32 state = 2
- [(android.os.statsd.state_field_option).option = EXCLUSIVE];
+ optional int32 state = 2 [(android.os.statsd.state_field_option).option = EXCLUSIVE_STATE];
}
// We can have more than one primary fields. That means their combination is a
// primary key.
message GoodStateAtom3 {
- optional int32 uid = 1
- [(android.os.statsd.state_field_option).option = PRIMARY];
- optional int32 tid = 2
- [(android.os.statsd.state_field_option).option = PRIMARY];
- optional int32 state = 3
- [(android.os.statsd.state_field_option).option = EXCLUSIVE];
+ optional int32 uid = 1 [(android.os.statsd.state_field_option).option = PRIMARY_FIELD];
+ optional int32 tid = 2 [(android.os.statsd.state_field_option).option = PRIMARY_FIELD];
+ optional int32 state = 3 [(android.os.statsd.state_field_option).option = EXCLUSIVE_STATE];
}
message WhitelistedAtom {