From 6ede28bcb972967c1934e26fa0513ea6001b4f98 Mon Sep 17 00:00:00 2001 From: Tej Singh Date: Tue, 29 Jan 2019 17:06:54 -0800 Subject: 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 --- cmds/statsd/benchmark/metric_util.cpp | 5 +- cmds/statsd/src/StatsLogProcessor.cpp | 79 ++++++++++++++++- cmds/statsd/src/StatsLogProcessor.h | 15 +++- cmds/statsd/src/StatsService.cpp | 98 +++++++++++++++++++++- cmds/statsd/src/StatsService.h | 15 ++++ cmds/statsd/src/config/ConfigManager.cpp | 12 ++- cmds/statsd/src/guardrail/StatsdStats.cpp | 49 +++++++++++ cmds/statsd/src/guardrail/StatsdStats.h | 19 +++++ cmds/statsd/src/metrics/MetricProducer.cpp | 2 +- cmds/statsd/src/metrics/MetricsManager.cpp | 14 +++- cmds/statsd/src/metrics/MetricsManager.h | 7 +- cmds/statsd/src/stats_log.proto | 2 + cmds/statsd/tests/StatsLogProcessor_test.cpp | 18 ++-- cmds/statsd/tests/UidMap_test.cpp | 3 +- cmds/statsd/tests/guardrail/StatsdStats_test.cpp | 23 ++++- cmds/statsd/tests/statsd_test_util.cpp | 5 +- core/java/android/os/IStatsCompanionService.aidl | 6 ++ .../server/stats/StatsCompanionService.java | 17 ++++ 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 CreateStatsLogProcessor(const long timeBaseSec, const Stat sp periodicAlarmMonitor; sp 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&) { 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, const sp& anomalyAlarmMonitor, const sp& periodicAlarmMonitor, const int64_t timeBaseNs, - const std::function& sendBroadcast) + const std::function& sendBroadcast, + const std::function&)>& 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 uidsWithActiveConfigsChanged; + std::unordered_map> 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 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 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& outActiveConfigs) { + std::lock_guard lock(mMetricsMutex); + GetActiveConfigsLocked(uid, outActiveConfigs); +} + +void StatsLogProcessor::GetActiveConfigsLocked(const int uid, vector& 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& anomalyAlarmMonitor, const sp& subscriberTriggerAlarmMonitor, const int64_t timeBaseNs, - const std::function& sendBroadcast); + const std::function& sendBroadcast, + const std::function&)>& 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& outActiveConfigs); + void onDumpReport(const ConfigKey& key, const int64_t dumpTimeNs, const bool include_current_partial_bucket, const bool erase_data, const DumpReportReason dumpReportReason, vector* outData); @@ -125,6 +129,9 @@ private: std::unordered_map mLastBroadcastTimes; + // Last time we sent a broadcast to this uid that the active configs had changed. + std::unordered_map mLastActivationBroadcastTimes; + // Tracks when we last checked the bytes consumed for each config key. std::unordered_map mLastByteSizeTimes; @@ -144,6 +151,8 @@ private: void OnConfigUpdatedLocked( const int64_t currentTimestampNs, const ConfigKey& key, const StatsdConfig& config); + void GetActiveConfigsLocked(const int uid, vector& 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 mSendBroadcast; + // Function used to send a broadcast so that receiver can be notified of which configs + // are currently active. + std::function& 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& handlerLooper) sc->sendDataBroadcast(receiver, mProcessor->getLastReportTimeNs(key)); return true; } + }, + [this](const int& uid, const vector& activeConfigs) { + auto receiver = mConfigManager->GetActiveConfigsChangedReceiver(uid); + sp 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& 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); @@ -447,6 +465,19 @@ void StatsService::print_cmd_help(int out) { dprintf(out, " the UID parameter on eng builds. If UID is omitted the\n"); dprintf(out, " calling uid is used.\n"); 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"); @@ -499,6 +530,59 @@ status_t StatsService::cmd_trigger_broadcast(int out, Vector& args) { return NO_ERROR; } +status_t StatsService::cmd_trigger_active_config_broadcast(int out, Vector& args) { + const int argCount = args.size(); + int uid; + vector 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(configID)); + configIds.push_back(configID); + } + } + } + auto receiver = mConfigManager->GetActiveConfigsChangedReceiver(uid); + sp 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& args) { const int argCount = args.size(); if (argCount >= 2) { @@ -762,7 +846,10 @@ status_t StatsService::cmd_print_logs(int out, const Vector& args) { } bool StatsService::getUidFromArgs(const Vector& 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 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& args); + + /** + * Trigger an active configs changed broadcast. + */ + status_t cmd_trigger_active_config_broadcast(int outFd, Vector& args); + /** * Handle the config sub-command. */ @@ -340,6 +346,15 @@ private: */ bool getUidFromArgs(const Vector& 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. */ 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 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& 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 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 broadcast_sent_time_sec; + + // Times at which this config is activated. + std::list activation_time_sec; + + // Times at which this config is deactivated. + std::list deactivation_time_sec; + std::list data_drop_time_sec; // Number of bytes dropped at corresponding time. std::list 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; @@ -174,6 +184,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. */ @@ -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& 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 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 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 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&) {return true;}); MockMetricsManager mockMetricsManager; @@ -88,7 +89,8 @@ TEST(StatsLogProcessorTest, TestRateLimitBroadcast) { [&broadcastCount](const ConfigKey& key) { broadcastCount++; return true; - }); + }, + [](const int&, const vector&) {return true;}); MockMetricsManager mockMetricsManager; @@ -118,7 +120,8 @@ TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge) { [&broadcastCount](const ConfigKey& key) { broadcastCount++; return true; - }); + }, + [](const int&, const vector&) {return true;}); MockMetricsManager mockMetricsManager; @@ -162,7 +165,8 @@ TEST(StatsLogProcessorTest, TestUidMapHasSnapshot) { [&broadcastCount](const ConfigKey& key) { broadcastCount++; return true; - }); + }, + [](const int&, const vector&) {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&) {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&) {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 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&) {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 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 CreateStatsLogProcessor(const int64_t timeBaseNs, const in [](const sp&){}); sp processor = new StatsLogProcessor(uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, - timeBaseNs, [](const ConfigKey&) { return true; }); + timeBaseNs, [](const ConfigKey&) { return true; }, + [](const int&, const vector&) {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 @@ -68,6 +68,12 @@ interface IStatsCompanionService { /** Send a broadcast to the specified PendingIntent's as IBinder that it should getData now. */ 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 @@ -355,6 +356,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, -- cgit v1.2.3-59-g8ed1b