diff options
| -rw-r--r-- | cmds/statsd/src/atom_field_options.proto | 69 | ||||
| -rw-r--r-- | cmds/statsd/src/atoms.proto | 52 | ||||
| -rw-r--r-- | cmds/statsd/src/state/StateTracker.cpp | 80 | ||||
| -rw-r--r-- | cmds/statsd/src/state/StateTracker.h | 2 | ||||
| -rw-r--r-- | cmds/statsd/tests/state/StateTracker_test.cpp | 103 | ||||
| -rw-r--r-- | tools/stats_log_api_gen/Collation.cpp | 46 | ||||
| -rw-r--r-- | tools/stats_log_api_gen/Collation.h | 3 | ||||
| -rw-r--r-- | tools/stats_log_api_gen/atoms_info_writer.cpp | 28 | ||||
| -rw-r--r-- | tools/stats_log_api_gen/test.proto | 35 |
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 { |