Statsd sends active config broadcasts
Statsd now sends active configs changed broadcasts when needed per uid.
Also made an adb command to help debug.
More gts tests and unit tests required, will follow.
Test: GTS in topic
Bug: 123372077
Change-Id: Ib079018ded85d002581ffc2ba1240138ce7a54e7
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index dd18bd4..653ef2e 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -88,12 +88,15 @@
const sp<AlarmMonitor>& anomalyAlarmMonitor,
const sp<AlarmMonitor>& periodicAlarmMonitor,
const int64_t timeBaseNs,
- const std::function<bool(const ConfigKey&)>& sendBroadcast)
+ const std::function<bool(const ConfigKey&)>& sendBroadcast,
+ const std::function<bool(
+ const int&, const vector<int64_t>&)>& activateBroadcast)
: mUidMap(uidMap),
mPullerManager(pullerManager),
mAnomalyAlarmMonitor(anomalyAlarmMonitor),
mPeriodicAlarmMonitor(periodicAlarmMonitor),
mSendBroadcast(sendBroadcast),
+ mSendActivationBroadcast(activateBroadcast),
mTimeBaseNs(timeBaseNs),
mLargestTimestampSeen(0),
mLastTimestampSeen(0) {
@@ -223,11 +226,73 @@
mapIsolatedUidToHostUidIfNecessaryLocked(event);
}
+ std::unordered_set<int> uidsWithActiveConfigsChanged;
+ std::unordered_map<int, std::vector<int64_t>> activeConfigsPerUid;
// pass the event to metrics managers.
for (auto& pair : mMetricsManagers) {
+ int uid = pair.first.GetUid();
+ int64_t configId = pair.first.GetId();
+ bool isPrevActive = pair.second->isActive();
pair.second->onLogEvent(*event);
+ bool isCurActive = pair.second->isActive();
+ // Map all active configs by uid.
+ if (isCurActive) {
+ auto activeConfigs = activeConfigsPerUid.find(uid);
+ if (activeConfigs != activeConfigsPerUid.end()) {
+ activeConfigs->second.push_back(configId);
+ } else {
+ vector<int64_t> newActiveConfigs;
+ newActiveConfigs.push_back(configId);
+ activeConfigsPerUid[uid] = newActiveConfigs;
+ }
+ }
+ // The activation state of this config changed.
+ if (isPrevActive != isCurActive) {
+ VLOG("Active status changed for uid %d", uid);
+ uidsWithActiveConfigsChanged.insert(uid);
+ StatsdStats::getInstance().noteActiveStatusChanged(pair.first, isCurActive);
+ }
flushIfNecessaryLocked(event->GetElapsedTimestampNs(), pair.first, *(pair.second));
}
+
+ for (int uid : uidsWithActiveConfigsChanged) {
+ // Send broadcast so that receivers can pull data.
+ auto lastBroadcastTime = mLastActivationBroadcastTimes.find(uid);
+ if (lastBroadcastTime != mLastActivationBroadcastTimes.end()) {
+ if (currentTimestampNs - lastBroadcastTime->second <
+ StatsdStats::kMinActivationBroadcastPeriodNs) {
+ VLOG("StatsD would've sent an activation broadcast but the rate limit stopped us.");
+ return;
+ }
+ }
+ auto activeConfigs = activeConfigsPerUid.find(uid);
+ if (activeConfigs != activeConfigsPerUid.end()) {
+ if (mSendActivationBroadcast(uid, activeConfigs->second)) {
+ VLOG("StatsD sent activation notice for uid %d", uid);
+ mLastActivationBroadcastTimes[uid] = currentTimestampNs;
+ }
+ } else {
+ std::vector<int64_t> emptyActiveConfigs;
+ if (mSendActivationBroadcast(uid, emptyActiveConfigs)) {
+ VLOG("StatsD sent EMPTY activation notice for uid %d", uid);
+ mLastActivationBroadcastTimes[uid] = currentTimestampNs;
+ }
+ }
+ }
+}
+
+void StatsLogProcessor::GetActiveConfigs(const int uid, vector<int64_t>& outActiveConfigs) {
+ std::lock_guard<std::mutex> lock(mMetricsMutex);
+ GetActiveConfigsLocked(uid, outActiveConfigs);
+}
+
+void StatsLogProcessor::GetActiveConfigsLocked(const int uid, vector<int64_t>& outActiveConfigs) {
+ outActiveConfigs.clear();
+ for (auto& pair : mMetricsManagers) {
+ if (pair.first.GetUid() == uid && pair.second->isActive()) {
+ outActiveConfigs.push_back(pair.first.GetId());
+ }
+ }
}
void StatsLogProcessor::OnConfigUpdated(const int64_t timestampNs, const ConfigKey& key,
@@ -444,6 +509,18 @@
mLastBroadcastTimes.erase(key);
+ int uid = key.GetUid();
+ bool lastConfigForUid = true;
+ for (auto it : mMetricsManagers) {
+ if (it.first.GetUid() == uid) {
+ lastConfigForUid = false;
+ break;
+ }
+ }
+ if (lastConfigForUid) {
+ mLastActivationBroadcastTimes.erase(uid);
+ }
+
if (mMetricsManagers.empty()) {
mPullerManager->ForceClearPullerCache();
}
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index caf1a71..ea9c6e7 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -49,7 +49,9 @@
const sp<AlarmMonitor>& anomalyAlarmMonitor,
const sp<AlarmMonitor>& subscriberTriggerAlarmMonitor,
const int64_t timeBaseNs,
- const std::function<bool(const ConfigKey&)>& sendBroadcast);
+ const std::function<bool(const ConfigKey&)>& sendBroadcast,
+ const std::function<bool(const int&,
+ const vector<int64_t>&)>& sendActivationBroadcast);
virtual ~StatsLogProcessor();
void OnLogEvent(LogEvent* event);
@@ -60,6 +62,8 @@
size_t GetMetricsSize(const ConfigKey& key) const;
+ void GetActiveConfigs(const int uid, vector<int64_t>& outActiveConfigs);
+
void onDumpReport(const ConfigKey& key, const int64_t dumpTimeNs,
const bool include_current_partial_bucket, const bool erase_data,
const DumpReportReason dumpReportReason, vector<uint8_t>* outData);
@@ -125,6 +129,9 @@
std::unordered_map<ConfigKey, long> mLastBroadcastTimes;
+ // Last time we sent a broadcast to this uid that the active configs had changed.
+ std::unordered_map<int, long> mLastActivationBroadcastTimes;
+
// Tracks when we last checked the bytes consumed for each config key.
std::unordered_map<ConfigKey, long> mLastByteSizeTimes;
@@ -144,6 +151,8 @@
void OnConfigUpdatedLocked(
const int64_t currentTimestampNs, const ConfigKey& key, const StatsdConfig& config);
+ void GetActiveConfigsLocked(const int uid, vector<int64_t>& outActiveConfigs);
+
void WriteDataToDiskLocked(const DumpReportReason dumpReportReason);
void WriteDataToDiskLocked(const ConfigKey& key, const int64_t timestampNs,
const DumpReportReason dumpReportReason);
@@ -174,6 +183,10 @@
// to retrieve the stored data.
std::function<bool(const ConfigKey& key)> mSendBroadcast;
+ // Function used to send a broadcast so that receiver can be notified of which configs
+ // are currently active.
+ std::function<bool(const int& uid, const vector<int64_t>& configIds)> mSendActivationBroadcast;
+
const int64_t mTimeBaseNs;
// Largest timestamp of the events that we have processed.
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index bd21a95..b478fed 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -176,6 +176,21 @@
sc->sendDataBroadcast(receiver, mProcessor->getLastReportTimeNs(key));
return true;
}
+ },
+ [this](const int& uid, const vector<int64_t>& activeConfigs) {
+ auto receiver = mConfigManager->GetActiveConfigsChangedReceiver(uid);
+ sp<IStatsCompanionService> sc = getStatsCompanionService();
+ if (sc == nullptr) {
+ VLOG("Could not access statsCompanion");
+ return false;
+ } else if (receiver == nullptr) {
+ VLOG("Could not find receiver for uid %d", uid);
+ return false;
+ } else {
+ sc->sendActiveConfigsChangedBroadcast(receiver, activeConfigs);
+ VLOG("StatsService::active configs broadcast succeeded for uid %d" , uid);
+ return true;
+ }
});
mConfigManager->AddListener(mProcessor);
@@ -357,6 +372,9 @@
if (!args[0].compare(String8("print-logs"))) {
return cmd_print_logs(out, args);
}
+ if (!args[0].compare(String8("send-active-configs"))) {
+ return cmd_trigger_active_config_broadcast(out, args);
+ }
if (!args[0].compare(String8("data-subscribe"))) {
if (mShellSubscriber == nullptr) {
mShellSubscriber = new ShellSubscriber(mUidMap, mPullerManager);
@@ -449,6 +467,19 @@
dprintf(out, " NAME The name of the configuration\n");
dprintf(out, "\n");
dprintf(out, "\n");
+ dprintf(out,
+ "usage: adb shell cmd stats send-active-configs [--uid=UID] [--configs] "
+ "[NAME1] [NAME2] [NAME3..]\n");
+ dprintf(out, " Send a broadcast that informs the subscriber of the current active configs.\n");
+ dprintf(out, " --uid=UID The uid of the configurations. It is only possible to pass\n");
+ dprintf(out, " the UID parameter on eng builds. If UID is omitted the\n");
+ dprintf(out, " calling uid is used.\n");
+ dprintf(out, " --configs Send the list of configs in the name list instead of\n");
+ dprintf(out, " the currently active configs\n");
+ dprintf(out, " NAME LIST List of configuration names to be included in the broadcast.\n");
+
+ dprintf(out, "\n");
+ dprintf(out, "\n");
dprintf(out, "usage: adb shell cmd stats print-stats\n");
dprintf(out, " Prints some basic stats.\n");
dprintf(out, " --proto Print proto binary instead of string format.\n");
@@ -499,6 +530,59 @@
return NO_ERROR;
}
+status_t StatsService::cmd_trigger_active_config_broadcast(int out, Vector<String8>& args) {
+ const int argCount = args.size();
+ int uid;
+ vector<int64_t> configIds;
+ if (argCount == 1) {
+ // Automatically pick the uid and send a broadcast that has no active configs.
+ uid = IPCThreadState::self()->getCallingUid();
+ mProcessor->GetActiveConfigs(uid, configIds);
+ } else {
+ int curArg = 1;
+ if(args[curArg].find("--uid=") == 0) {
+ string uidArgStr(args[curArg].c_str());
+ string uidStr = uidArgStr.substr(6);
+ if (!getUidFromString(uidStr.c_str(), uid)) {
+ dprintf(out, "Invalid UID. Note that the config can only be set for "
+ "other UIDs on eng or userdebug builds.\n");
+ return UNKNOWN_ERROR;
+ }
+ curArg++;
+ } else {
+ uid = IPCThreadState::self()->getCallingUid();
+ }
+ if (curArg == argCount || args[curArg] != "--configs") {
+ VLOG("Reached end of args, or specify configs not set. Sending actual active configs,");
+ mProcessor->GetActiveConfigs(uid, configIds);
+ } else {
+ // Flag specified, use the given list of configs.
+ curArg++;
+ for (int i = curArg; i < argCount; i++) {
+ char* endp;
+ int64_t configID = strtoll(args[i].c_str(), &endp, 10);
+ if (endp == args[i].c_str() || *endp != '\0') {
+ dprintf(out, "Error parsing config ID.\n");
+ return UNKNOWN_ERROR;
+ }
+ VLOG("Adding config id %ld", static_cast<long>(configID));
+ configIds.push_back(configID);
+ }
+ }
+ }
+ auto receiver = mConfigManager->GetActiveConfigsChangedReceiver(uid);
+ sp<IStatsCompanionService> sc = getStatsCompanionService();
+ if (sc == nullptr) {
+ VLOG("Could not access statsCompanion");
+ } else if (receiver == nullptr) {
+ VLOG("Could not find receiver for uid %d", uid);
+ } else {
+ sc->sendActiveConfigsChangedBroadcast(receiver, configIds);
+ VLOG("StatsService::trigger active configs changed broadcast succeeded for uid %d" , uid);
+ }
+ return NO_ERROR;
+}
+
status_t StatsService::cmd_config(int in, int out, int err, Vector<String8>& args) {
const int argCount = args.size();
if (argCount >= 2) {
@@ -762,7 +846,10 @@
}
bool StatsService::getUidFromArgs(const Vector<String8>& args, size_t uidArgIndex, int32_t& uid) {
- const char* s = args[uidArgIndex].c_str();
+ return getUidFromString(args[uidArgIndex].c_str(), uid);
+}
+
+bool StatsService::getUidFromString(const char* s, int32_t& uid) {
if (*s == '\0') {
return false;
}
@@ -998,8 +1085,13 @@
ENFORCE_DUMP_AND_USAGE_STATS(packageName);
IPCThreadState* ipc = IPCThreadState::self();
- mConfigManager->SetActiveConfigsChangedReceiver(ipc->getCallingUid(), intentSender);
- //TODO: Return the list of configs that are already active
+ int uid = ipc->getCallingUid();
+ mConfigManager->SetActiveConfigsChangedReceiver(uid, intentSender);
+ if (output != nullptr) {
+ mProcessor->GetActiveConfigs(uid, *output);
+ } else {
+ ALOGW("StatsService::setActiveConfigsChanged output was nullptr");
+ }
return Status::ok();
}
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 941ed46..7f10d74 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -275,6 +275,12 @@
*/
status_t cmd_trigger_broadcast(int outFd, Vector<String8>& args);
+
+ /**
+ * Trigger an active configs changed broadcast.
+ */
+ status_t cmd_trigger_active_config_broadcast(int outFd, Vector<String8>& args);
+
/**
* Handle the config sub-command.
*/
@@ -341,6 +347,15 @@
bool getUidFromArgs(const Vector<String8>& args, size_t uidArgIndex, int32_t& uid);
/**
+ * Writes the value of uidSting into uid.
+ * Returns whether the uid is reasonable (type uid_t) and whether
+ * 1. it is equal to the calling uid, or
+ * 2. the device is mEngBuild, or
+ * 3. the caller is AID_ROOT and the uid is AID_SHELL (i.e. ROOT can impersonate SHELL).
+ */
+ bool getUidFromString(const char* uidString, int32_t& uid);
+
+ /**
* Adds a configuration after checking permissions and obtaining UID from binder call.
*/
bool addConfigurationChecked(int uid, int64_t key, const vector<uint8_t>& config);
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index aa22333..fc949b4 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -144,10 +144,20 @@
{
lock_guard <mutex> lock(mMutex);
- auto uidIt = mConfigs.find(key.GetUid());
+ auto uid = key.GetUid();
+ auto uidIt = mConfigs.find(uid);
if (uidIt != mConfigs.end() && uidIt->second.find(key) != uidIt->second.end()) {
// Remove from map
uidIt->second.erase(key);
+
+ // No more configs for this uid, lets remove the active configs callback.
+ if (uidIt->second.empty()) {
+ auto itActiveConfigsChangedReceiver = mActiveConfigsChangedReceivers.find(uid);
+ if (itActiveConfigsChangedReceiver != mActiveConfigsChangedReceivers.end()) {
+ mActiveConfigsChangedReceivers.erase(itActiveConfigsChangedReceiver);
+ }
+ }
+
for (const sp<ConfigListener>& listener : mListeners) {
broadcastList.push_back(listener);
}
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index 40329b7..b433c41 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -82,6 +82,8 @@
const int FIELD_ID_CONFIG_STATS_ALERT_STATS = 16;
const int FIELD_ID_CONFIG_STATS_METRIC_DIMENSION_IN_CONDITION_STATS = 17;
const int FIELD_ID_CONFIG_STATS_ANNOTATION = 18;
+const int FIELD_ID_CONFIG_STATS_ACTIVATION = 22;
+const int FIELD_ID_CONFIG_STATS_DEACTIVATION = 23;
const int FIELD_ID_CONFIG_STATS_ANNOTATION_INT64 = 1;
const int FIELD_ID_CONFIG_STATS_ANNOTATION_INT32 = 2;
@@ -206,6 +208,25 @@
it->second->broadcast_sent_time_sec.push_back(timeSec);
}
+void StatsdStats::noteActiveStatusChanged(const ConfigKey& key, bool activated) {
+ noteActiveStatusChanged(key, activated, getWallClockSec());
+}
+
+void StatsdStats::noteActiveStatusChanged(const ConfigKey& key, bool activated, int32_t timeSec) {
+ lock_guard<std::mutex> lock(mLock);
+ auto it = mConfigStats.find(key);
+ if (it == mConfigStats.end()) {
+ ALOGE("Config key %s not found!", key.ToString().c_str());
+ return;
+ }
+ auto& vec = activated ? it->second->activation_time_sec
+ : it->second->deactivation_time_sec;
+ if (vec.size() == kMaxTimestampCount) {
+ vec.pop_front();
+ }
+ vec.push_back(timeSec);
+}
+
void StatsdStats::noteDataDropped(const ConfigKey& key, const size_t totalBytes) {
noteDataDropped(key, totalBytes, getWallClockSec());
}
@@ -501,6 +522,8 @@
mLogLossStats.clear();
for (auto& config : mConfigStats) {
config.second->broadcast_sent_time_sec.clear();
+ config.second->activation_time_sec.clear();
+ config.second->deactivation_time_sec.clear();
config.second->data_drop_time_sec.clear();
config.second->data_drop_bytes.clear();
config.second->dump_report_stats.clear();
@@ -558,6 +581,14 @@
dprintf(out, "\tbroadcast time: %d\n", broadcastTime);
}
+ for (const int& activationTime : configStats->activation_time_sec) {
+ dprintf(out, "\tactivation time: %d\n", activationTime);
+ }
+
+ for (const int& deactivationTime : configStats->deactivation_time_sec) {
+ dprintf(out, "\tdeactivation time: %d\n", deactivationTime);
+ }
+
auto dropTimePtr = configStats->data_drop_time_sec.begin();
auto dropBytesPtr = configStats->data_drop_bytes.begin();
for (int i = 0; i < (int)configStats->data_drop_time_sec.size();
@@ -586,6 +617,14 @@
(long long)broadcastTime);
}
+ for (const int& activationTime : configStats->activation_time_sec) {
+ dprintf(out, "\tactivation time: %d\n", activationTime);
+ }
+
+ for (const int& deactivationTime : configStats->deactivation_time_sec) {
+ dprintf(out, "\tdeactivation time: %d\n", deactivationTime);
+ }
+
auto dropTimePtr = configStats->data_drop_time_sec.begin();
auto dropBytesPtr = configStats->data_drop_bytes.begin();
for (int i = 0; i < (int)configStats->data_drop_time_sec.size();
@@ -696,6 +735,16 @@
broadcast);
}
+ for (const auto& activation : configStats.activation_time_sec) {
+ proto->write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_ACTIVATION | FIELD_COUNT_REPEATED,
+ activation);
+ }
+
+ for (const auto& deactivation : configStats.deactivation_time_sec) {
+ proto->write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_DEACTIVATION | FIELD_COUNT_REPEATED,
+ deactivation);
+ }
+
for (const auto& drop_time : configStats.data_drop_time_sec) {
proto->write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_DATA_DROP_TIME | FIELD_COUNT_REPEATED,
drop_time);
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 65e8a32..5275c8f 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -42,6 +42,13 @@
bool is_valid;
std::list<int32_t> broadcast_sent_time_sec;
+
+ // Times at which this config is activated.
+ std::list<int32_t> activation_time_sec;
+
+ // Times at which this config is deactivated.
+ std::list<int32_t> deactivation_time_sec;
+
std::list<int32_t> data_drop_time_sec;
// Number of bytes dropped at corresponding time.
std::list<int64_t> data_drop_bytes;
@@ -132,6 +139,9 @@
/* Min period between two checks of byte size per config key in nanoseconds. */
static const int64_t kMinByteSizeCheckPeriodNs = 60 * NS_PER_SEC;
+ /* Minimum period between two activation broadcasts in nanoseconds. */
+ static const int64_t kMinActivationBroadcastPeriodNs = 10 * NS_PER_SEC;
+
// Maximum age (30 days) that files on disk can exist in seconds.
static const int kMaxAgeSecond = 60 * 60 * 24 * 30;
@@ -175,6 +185,13 @@
void noteBroadcastSent(const ConfigKey& key);
/**
+ * Report that a config has become activated or deactivated.
+ * This can be different from whether or not a broadcast is sent if the
+ * guardrail prevented the broadcast from being sent.
+ */
+ void noteActiveStatusChanged(const ConfigKey& key, bool activate);
+
+ /**
* Report a config's metrics data has been dropped.
*/
void noteDataDropped(const ConfigKey& key, const size_t totalBytes);
@@ -507,6 +524,8 @@
void noteBroadcastSent(const ConfigKey& key, int32_t timeSec);
+ void noteActiveStatusChanged(const ConfigKey& key, bool activate, int32_t timeSec);
+
void addToIceBoxLocked(std::shared_ptr<ConfigStats>& stats);
/**
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index 495138e..1107568 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -94,7 +94,7 @@
void MetricProducer::addActivation(int activationTrackerIndex, int64_t ttl_seconds) {
std::lock_guard<std::mutex> lock(mMutex);
// When a metric producer does not depend on any activation, its mIsActive is true.
- // Therefor, if this is the 1st activation, mIsActive will turn to false. Otherwise it does not
+ // Therefore, if this is the 1st activation, mIsActive will turn to false. Otherwise it does not
// change.
if (mEventActivationMap.empty()) {
mIsActive = false;
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 6ed6ab50..4851a8d 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -118,6 +118,16 @@
ALOGE("This config has too many alerts! Reject!");
mConfigValid = false;
}
+
+ mIsAlwaysActive = (mMetricIndexesWithActivation.size() != mAllMetricProducers.size()) ||
+ (mAllMetricProducers.size() == 0);
+ bool isActive = mIsAlwaysActive;
+ for (int metric : mMetricIndexesWithActivation) {
+ isActive |= mAllMetricProducers[metric]->isActive();
+ }
+ mIsActive = isActive;
+ VLOG("mIsActive is initialized to %d", mIsActive)
+
// no matter whether this config is valid, log it in the stats.
StatsdStats::getInstance().noteConfigReceived(
key, mAllMetricProducers.size(), mAllConditionTrackers.size(), mAllAtomMatchers.size(),
@@ -332,12 +342,14 @@
int tagId = event.GetTagId();
int64_t eventTimeNs = event.GetElapsedTimestampNs();
- bool isActive = false;
+ bool isActive = mIsAlwaysActive;
for (int metric : mMetricIndexesWithActivation) {
mAllMetricProducers[metric]->flushIfExpire(eventTimeNs);
isActive |= mAllMetricProducers[metric]->isActive();
}
+ mIsActive = isActive;
+
if (mTagIds.find(tagId) == mTagIds.end()) {
// not interesting...
return;
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index cb1cefb..eab1f76 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -128,6 +128,8 @@
// Does not change the state.
virtual size_t byteSize();
+ // Returns whether or not this config is active.
+ // The config is active if any metric in the config is active.
inline bool isActive() const {
return mIsActive;
}
@@ -241,9 +243,12 @@
// The metrics that don't need to be uploaded or even reported.
std::set<int64_t> mNoReportMetricIds;
- // Any metric active means the config is active.
+ // The config is active if any metric in the config is active.
bool mIsActive;
+ // The config is always active if any metric in the config does not have an activation signal.
+ bool mIsAlwaysActive;
+
FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensions);
FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks);
FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid);
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 863261a..f7428a5 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -367,6 +367,8 @@
optional int32 field_int32 = 2;
}
repeated Annotation annotation = 18;
+ repeated int32 activation_time_sec = 22;
+ repeated int32 deactivation_time_sec = 23;
}
repeated ConfigStats config_stats = 3;