diff options
| -rw-r--r-- | cmds/statsd/benchmark/metric_util.cpp | 5 | ||||
| -rw-r--r-- | cmds/statsd/src/StatsLogProcessor.cpp | 79 | ||||
| -rw-r--r-- | cmds/statsd/src/StatsLogProcessor.h | 15 | ||||
| -rw-r--r-- | cmds/statsd/src/StatsService.cpp | 98 | ||||
| -rw-r--r-- | cmds/statsd/src/StatsService.h | 15 | ||||
| -rw-r--r-- | cmds/statsd/src/config/ConfigManager.cpp | 12 | ||||
| -rw-r--r-- | cmds/statsd/src/guardrail/StatsdStats.cpp | 49 | ||||
| -rw-r--r-- | cmds/statsd/src/guardrail/StatsdStats.h | 19 | ||||
| -rw-r--r-- | cmds/statsd/src/metrics/MetricProducer.cpp | 2 | ||||
| -rw-r--r-- | cmds/statsd/src/metrics/MetricsManager.cpp | 14 | ||||
| -rw-r--r-- | cmds/statsd/src/metrics/MetricsManager.h | 7 | ||||
| -rw-r--r-- | cmds/statsd/src/stats_log.proto | 2 | ||||
| -rw-r--r-- | cmds/statsd/tests/StatsLogProcessor_test.cpp | 18 | ||||
| -rw-r--r-- | cmds/statsd/tests/UidMap_test.cpp | 3 | ||||
| -rw-r--r-- | cmds/statsd/tests/guardrail/StatsdStats_test.cpp | 23 | ||||
| -rw-r--r-- | cmds/statsd/tests/statsd_test_util.cpp | 5 | ||||
| -rw-r--r-- | core/java/android/os/IStatsCompanionService.aidl | 6 | ||||
| -rw-r--r-- | services/core/java/com/android/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<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) { |