summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author TreeHugger Robot <treehugger-gerrit@google.com> 2019-02-13 06:17:50 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2019-02-13 06:17:50 +0000
commit5dbf94cbc0c99657bcffa69b9990e52e0b76fa25 (patch)
tree6ebef97f1c604d090107a2058d342c27bcae19be
parentdc3e98eabbdb1d0e9820d77d6110f7053c35134e (diff)
parent6ede28bcb972967c1934e26fa0513ea6001b4f98 (diff)
Merge "Statsd sends active config broadcasts"
-rw-r--r--cmds/statsd/benchmark/metric_util.cpp5
-rw-r--r--cmds/statsd/src/StatsLogProcessor.cpp79
-rw-r--r--cmds/statsd/src/StatsLogProcessor.h15
-rw-r--r--cmds/statsd/src/StatsService.cpp98
-rw-r--r--cmds/statsd/src/StatsService.h15
-rw-r--r--cmds/statsd/src/config/ConfigManager.cpp12
-rw-r--r--cmds/statsd/src/guardrail/StatsdStats.cpp49
-rw-r--r--cmds/statsd/src/guardrail/StatsdStats.h19
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.cpp2
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.cpp14
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.h7
-rw-r--r--cmds/statsd/src/stats_log.proto2
-rw-r--r--cmds/statsd/tests/StatsLogProcessor_test.cpp18
-rw-r--r--cmds/statsd/tests/UidMap_test.cpp3
-rw-r--r--cmds/statsd/tests/guardrail/StatsdStats_test.cpp23
-rw-r--r--cmds/statsd/tests/statsd_test_util.cpp5
-rw-r--r--core/java/android/os/IStatsCompanionService.aidl6
-rw-r--r--services/core/java/com/android/server/stats/StatsCompanionService.java17
18 files changed, 367 insertions, 22 deletions
diff --git a/cmds/statsd/benchmark/metric_util.cpp b/cmds/statsd/benchmark/metric_util.cpp
index 067b6eddf254..cca6d525ea16 100644
--- a/cmds/statsd/benchmark/metric_util.cpp
+++ b/cmds/statsd/benchmark/metric_util.cpp
@@ -367,7 +367,8 @@ sp<StatsLogProcessor> CreateStatsLogProcessor(const long timeBaseSec, const Stat
sp<AlarmMonitor> periodicAlarmMonitor;
sp<StatsLogProcessor> processor =
new StatsLogProcessor(uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec * NS_PER_SEC, [](const ConfigKey&) { return true; });
+ timeBaseSec * NS_PER_SEC, [](const ConfigKey&) { return true; },
+ [](const int&, const vector<int64_t>&) { return true; });
processor->OnConfigUpdated(timeBaseSec * NS_PER_SEC, key, config);
return processor;
}
@@ -393,4 +394,4 @@ int64_t StringToId(const string& str) {
} // namespace statsd
} // namespace os
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index dd18bd4cc8ad..653ef2ec9869 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -88,12 +88,15 @@ StatsLogProcessor::StatsLogProcessor(const sp<UidMap>& uidMap,
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 @@ void StatsLogProcessor::OnLogEvent(LogEvent* event) {
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 @@ void StatsLogProcessor::OnConfigRemoved(const ConfigKey& key) {
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 caf1a713986d..ea9c6e704017 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -49,7 +49,9 @@ public:
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 @@ public:
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 @@ private:
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 @@ private:
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 @@ private:
// 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 bd21a955729d..b478fed49a54 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -176,6 +176,21 @@ StatsService::StatsService(const sp<Looper>& handlerLooper)
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 @@ status_t StatsService::command(int in, int out, int err, Vector<String8>& args,
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 @@ void StatsService::print_cmd_help(int out) {
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 @@ status_t StatsService::cmd_trigger_broadcast(int out, Vector<String8>& args) {
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 @@ status_t StatsService::cmd_print_logs(int out, const Vector<String8>& args) {
}
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 @@ Status StatsService::setActiveConfigsChangedOperation(const sp<android::IBinder>
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 941ed462b303..7f10d74ec7d6 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -275,6 +275,12 @@ private:
*/
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 @@ private:
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 aa22333ab26c..fc949b494194 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -144,10 +144,20 @@ void ConfigManager::RemoveConfig(const ConfigKey& key) {
{
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 40329b7c86ab..b433c41518cc 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_METRIC_STATS = 15;
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 @@ void StatsdStats::noteBroadcastSent(const ConfigKey& key, int32_t timeSec) {
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 @@ void StatsdStats::resetInternalLocked() {
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 @@ void StatsdStats::dumpStats(int out) const {
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 @@ void StatsdStats::dumpStats(int out) const {
(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 @@ void addConfigStatsToProto(const ConfigStats& configStats, ProtoOutputStream* pr
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 65e8a324d7d3..5275c8f34fd0 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -42,6 +42,13 @@ struct ConfigStats {
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 @@ public:
/* 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 @@ public:
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 @@ private:
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 495138ee9b77..11075685b7fa 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -94,7 +94,7 @@ void MetricProducer::flushIfExpire(int64_t elapsedTimestampNs) {
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 6ed6ab500597..4851a8d40baa 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -118,6 +118,16 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
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 @@ void MetricsManager::onLogEvent(const LogEvent& event) {
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 cb1cefbf2063..eab1f762b390 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -128,6 +128,8 @@ public:
// 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 @@ private:
// 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 863261ae1626..f7428a50b3da 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -367,6 +367,8 @@ message StatsdStatsReport {
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;
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index 60df165f102c..5f3aae3ab93a 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -65,7 +65,8 @@ TEST(StatsLogProcessorTest, TestRateLimitByteSize) {
sp<AlarmMonitor> periodicAlarmMonitor;
// Construct the processor with a dummy sendBroadcast function that does nothing.
StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, 0,
- [](const ConfigKey& key) { return true; });
+ [](const ConfigKey& key) { return true; },
+ [](const int&, const vector<int64_t>&) {return true;});
MockMetricsManager mockMetricsManager;
@@ -88,7 +89,8 @@ TEST(StatsLogProcessorTest, TestRateLimitBroadcast) {
[&broadcastCount](const ConfigKey& key) {
broadcastCount++;
return true;
- });
+ },
+ [](const int&, const vector<int64_t>&) {return true;});
MockMetricsManager mockMetricsManager;
@@ -118,7 +120,8 @@ TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge) {
[&broadcastCount](const ConfigKey& key) {
broadcastCount++;
return true;
- });
+ },
+ [](const int&, const vector<int64_t>&) {return true;});
MockMetricsManager mockMetricsManager;
@@ -162,7 +165,8 @@ TEST(StatsLogProcessorTest, TestUidMapHasSnapshot) {
[&broadcastCount](const ConfigKey& key) {
broadcastCount++;
return true;
- });
+ },
+ [](const int&, const vector<int64_t>&) {return true;});
ConfigKey key(3, 4);
StatsdConfig config = MakeConfig(true);
p.OnConfigUpdated(0, key, config);
@@ -192,7 +196,8 @@ TEST(StatsLogProcessorTest, TestEmptyConfigHasNoUidMap) {
[&broadcastCount](const ConfigKey& key) {
broadcastCount++;
return true;
- });
+ },
+ [](const int&, const vector<int64_t>&) {return true;});
ConfigKey key(3, 4);
StatsdConfig config = MakeConfig(false);
p.OnConfigUpdated(0, key, config);
@@ -218,7 +223,8 @@ TEST(StatsLogProcessorTest, TestReportIncludesSubConfig) {
[&broadcastCount](const ConfigKey& key) {
broadcastCount++;
return true;
- });
+ },
+ [](const int&, const vector<int64_t>&) {return true;});
ConfigKey key(3, 4);
StatsdConfig config;
auto annotation = config.add_annotation();
diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp
index f0d9cf188661..c04a40cfebd9 100644
--- a/cmds/statsd/tests/UidMap_test.cpp
+++ b/cmds/statsd/tests/UidMap_test.cpp
@@ -45,7 +45,8 @@ TEST(UidMapTest, TestIsolatedUID) {
sp<AlarmMonitor> subscriberAlarmMonitor;
// Construct the processor with a dummy sendBroadcast function that does nothing.
StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
- [](const ConfigKey& key) { return true; });
+ [](const ConfigKey& key) { return true; },
+ [](const int&, const vector<int64_t>&) {return true;});
LogEvent addEvent(android::util::ISOLATED_UID_CHANGED, 1);
addEvent.write(100); // parent UID
addEvent.write(101); // isolated UID
diff --git a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
index 44a88f049443..1ff7982e1232 100644
--- a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
+++ b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
@@ -133,6 +133,13 @@ TEST(StatsdStatsTest, TestSubStats) {
stats.noteMetricsReportSent(key, 0);
stats.noteMetricsReportSent(key, 0);
+ // activation_time_sec -> 2
+ stats.noteActiveStatusChanged(key, true);
+ stats.noteActiveStatusChanged(key, true);
+
+ // deactivation_time_sec -> 1
+ stats.noteActiveStatusChanged(key, false);
+
vector<uint8_t> output;
stats.dumpStats(&output, true); // Dump and reset stats
StatsdStatsReport report;
@@ -146,6 +153,8 @@ TEST(StatsdStatsTest, TestSubStats) {
EXPECT_EQ(123, configReport.data_drop_bytes(0));
EXPECT_EQ(3, configReport.dump_report_time_sec_size());
EXPECT_EQ(3, configReport.dump_report_data_size_size());
+ EXPECT_EQ(2, configReport.activation_time_sec_size());
+ EXPECT_EQ(1, configReport.deactivation_time_sec_size());
EXPECT_EQ(1, configReport.annotation_size());
EXPECT_EQ(123, configReport.annotation(0).field_int64());
EXPECT_EQ(456, configReport.annotation(0).field_int32());
@@ -344,6 +353,8 @@ TEST(StatsdStatsTest, TestTimestampThreshold) {
stats.noteDataDropped(key, timestamps[i]);
stats.noteBroadcastSent(key, timestamps[i]);
stats.noteMetricsReportSent(key, 0, timestamps[i]);
+ stats.noteActiveStatusChanged(key, true, timestamps[i]);
+ stats.noteActiveStatusChanged(key, false, timestamps[i]);
}
int32_t newTimestamp = 10000;
@@ -352,6 +363,8 @@ TEST(StatsdStatsTest, TestTimestampThreshold) {
stats.noteDataDropped(key, 123, 10000);
stats.noteBroadcastSent(key, 10000);
stats.noteMetricsReportSent(key, 0, 10000);
+ stats.noteActiveStatusChanged(key, true, 10000);
+ stats.noteActiveStatusChanged(key, false, 10000);
EXPECT_TRUE(stats.mConfigStats.find(key) != stats.mConfigStats.end());
const auto& configStats = stats.mConfigStats[key];
@@ -360,17 +373,23 @@ TEST(StatsdStatsTest, TestTimestampThreshold) {
EXPECT_EQ(maxCount, configStats->broadcast_sent_time_sec.size());
EXPECT_EQ(maxCount, configStats->data_drop_time_sec.size());
EXPECT_EQ(maxCount, configStats->dump_report_stats.size());
+ EXPECT_EQ(maxCount, configStats->activation_time_sec.size());
+ EXPECT_EQ(maxCount, configStats->deactivation_time_sec.size());
// the oldest timestamp is the second timestamp in history
EXPECT_EQ(1, configStats->broadcast_sent_time_sec.front());
- EXPECT_EQ(1, configStats->broadcast_sent_time_sec.front());
- EXPECT_EQ(1, configStats->broadcast_sent_time_sec.front());
+ EXPECT_EQ(1, configStats->data_drop_bytes.front());
+ EXPECT_EQ(1, configStats->dump_report_stats.front().first);
+ EXPECT_EQ(1, configStats->activation_time_sec.front());
+ EXPECT_EQ(1, configStats->deactivation_time_sec.front());
// the last timestamp is the newest timestamp.
EXPECT_EQ(newTimestamp, configStats->broadcast_sent_time_sec.back());
EXPECT_EQ(newTimestamp, configStats->data_drop_time_sec.back());
EXPECT_EQ(123, configStats->data_drop_bytes.back());
EXPECT_EQ(newTimestamp, configStats->dump_report_stats.back().first);
+ EXPECT_EQ(newTimestamp, configStats->activation_time_sec.back());
+ EXPECT_EQ(newTimestamp, configStats->deactivation_time_sec.back());
}
TEST(StatsdStatsTest, TestSystemServerCrash) {
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index b8b1a1db2c12..2c4f3c7692c9 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -461,7 +461,8 @@ sp<StatsLogProcessor> CreateStatsLogProcessor(const int64_t timeBaseNs, const in
[](const sp<IStatsCompanionService>&){});
sp<StatsLogProcessor> processor =
new StatsLogProcessor(uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseNs, [](const ConfigKey&) { return true; });
+ timeBaseNs, [](const ConfigKey&) { return true; },
+ [](const int&, const vector<int64_t>&) {return true;});
processor->OnConfigUpdated(currentTimeNs, key, config);
return processor;
}
@@ -826,4 +827,4 @@ void backfillStartEndTimestamp(ConfigMetricsReportList *config_report_list) {
} // namespace statsd
} // namespace os
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl
index dde46cd93d5f..0751b964f85e 100644
--- a/core/java/android/os/IStatsCompanionService.aidl
+++ b/core/java/android/os/IStatsCompanionService.aidl
@@ -69,6 +69,12 @@ interface IStatsCompanionService {
oneway void sendDataBroadcast(in IBinder intentSender, long lastReportTimeNs);
/**
+ * Send a broadcast to the specified PendingIntent's as IBinder notifying it that the list
+ * of active configs has changed.
+ */
+ oneway void sendActiveConfigsChangedBroadcast(in IBinder intentSender, in long[] configIds);
+
+ /**
* Requests StatsCompanionService to send a broadcast using the given intentSender
* (which should cast to an IIntentSender), along with the other information specified.
*/
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 0aa6051d67ff..f3393e2f29da 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -167,6 +167,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
public static final int CODE_DATA_BROADCAST = 1;
public static final int CODE_SUBSCRIBER_BROADCAST = 1;
+ public static final int CODE_ACTIVE_CONFIGS_BROADCAST = 1;
/**
* The last report time is provided with each intent registered to
* StatsManager#setFetchReportsOperation. This allows easy de-duping in the receiver if
@@ -356,6 +357,22 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
}
@Override
+ public void sendActiveConfigsChangedBroadcast(IBinder intentSenderBinder, long[] configIds) {
+ enforceCallingPermission();
+ IntentSender intentSender = new IntentSender(intentSenderBinder);
+ Intent intent = new Intent();
+ intent.putExtra(StatsManager.EXTRA_STATS_ACTIVE_CONFIG_KEYS, configIds);
+ try {
+ intentSender.sendIntent(mContext, CODE_ACTIVE_CONFIGS_BROADCAST, intent, null, null);
+ if (DEBUG) {
+ Slog.d(TAG, "Sent broadcast with config ids " + Arrays.toString(configIds));
+ }
+ } catch (IntentSender.SendIntentException e) {
+ Slog.w(TAG, "Unable to send active configs changed broadcast using IntentSender");
+ }
+ }
+
+ @Override
public void sendSubscriberBroadcast(IBinder intentSenderBinder, long configUid, long configKey,
long subscriptionId, long subscriptionRuleId, String[] cookies,
StatsDimensionsValue dimensionsValue) {