Implement restricted metrics changed operation
Very generally follows the pattern of active configs/data fetch
broadcasts.
A few things are still todo:
- tests
- resending all pending intents on statsd restart
- returning the current
- code optimizations/cleanups
Test: m
Test: atest statsd_test
Bug: 268141944
Ignore-AOSP-First: U feature
Change-Id: I1f8c52c6dc0570630c92d29adb6ce8b14c08c3e7
diff --git a/statsd/src/StatsLogProcessor.cpp b/statsd/src/StatsLogProcessor.cpp
index 106f0f4..4a4a469 100644
--- a/statsd/src/StatsLogProcessor.cpp
+++ b/statsd/src/StatsLogProcessor.cpp
@@ -91,7 +91,9 @@
const sp<UidMap>& uidMap, const sp<StatsPullerManager>& pullerManager,
const sp<AlarmMonitor>& anomalyAlarmMonitor, const sp<AlarmMonitor>& periodicAlarmMonitor,
const int64_t timeBaseNs, const std::function<bool(const ConfigKey&)>& sendBroadcast,
- const std::function<bool(const int&, const vector<int64_t>&)>& activateBroadcast)
+ const std::function<bool(const int&, const vector<int64_t>&)>& activateBroadcast,
+ const std::function<void(const ConfigKey&, const string&, const vector<int64_t>&)>&
+ sendRestrictedMetricsBroadcast)
: mLastTtlTime(0),
mUidMap(uidMap),
mPullerManager(pullerManager),
@@ -99,6 +101,7 @@
mPeriodicAlarmMonitor(periodicAlarmMonitor),
mSendBroadcast(sendBroadcast),
mSendActivationBroadcast(activateBroadcast),
+ mSendRestrictedMetricsBroadcast(sendRestrictedMetricsBroadcast),
mTimeBaseNs(timeBaseNs),
mLargestTimestampSeen(0),
mLastTimestampSeen(0) {
@@ -564,6 +567,17 @@
newMetricsManager->init();
mUidMap->OnConfigUpdated(key);
newMetricsManager->refreshTtl(timestampNs);
+ if (mIsRestrictedMetricsEnabled) {
+ if (newMetricsManager->hasRestrictedMetricsDelegate()) {
+ mSendRestrictedMetricsBroadcast(
+ key, newMetricsManager->getRestrictedMetricsDelegate(),
+ newMetricsManager->getAllMetricIds());
+ } else if (it != mMetricsManagers.end() &&
+ it->second->hasRestrictedMetricsDelegate()) {
+ mSendRestrictedMetricsBroadcast(key, it->second->getRestrictedMetricsDelegate(),
+ {});
+ }
+ }
mMetricsManagers[key] = newMetricsManager;
VLOG("StatsdConfig valid");
}
@@ -573,12 +587,21 @@
mAnomalyAlarmMonitor, mPeriodicAlarmMonitor);
if (configValid) {
mUidMap->OnConfigUpdated(key);
+ if (mIsRestrictedMetricsEnabled && it->second->hasRestrictedMetricsDelegate()) {
+ mSendRestrictedMetricsBroadcast(key, it->second->getRestrictedMetricsDelegate(),
+ it->second->getAllMetricIds());
+ }
}
}
if (!configValid) {
// If there is any error in the config, don't use it.
// Remove any existing config with the same key.
ALOGE("StatsdConfig NOT valid");
+ // Send an empty restricted metrics broadcast if the previous config was restricted.
+ if (mIsRestrictedMetricsEnabled && it != mMetricsManagers.end() &&
+ it->second->hasRestrictedMetricsDelegate()) {
+ mSendRestrictedMetricsBroadcast(key, it->second->getRestrictedMetricsDelegate(), {});
+ }
mMetricsManagers.erase(key);
}
}
@@ -800,6 +823,9 @@
}
WriteDataToDiskLocked(key, getElapsedRealtimeNs(), getWallClockNs(), CONFIG_REMOVED,
NO_TIME_CONSTRAINTS);
+ if (mIsRestrictedMetricsEnabled && it->second->hasRestrictedMetricsDelegate()) {
+ mSendRestrictedMetricsBroadcast(key, it->second->getRestrictedMetricsDelegate(), {});
+ }
mMetricsManagers.erase(it);
mUidMap->OnConfigRemoved(key);
}
diff --git a/statsd/src/StatsLogProcessor.h b/statsd/src/StatsLogProcessor.h
index f08ebf9..cc7ef6d 100644
--- a/statsd/src/StatsLogProcessor.h
+++ b/statsd/src/StatsLogProcessor.h
@@ -36,13 +36,15 @@
class StatsLogProcessor : public ConfigListener, public virtual PackageInfoListener {
public:
- StatsLogProcessor(const sp<UidMap>& uidMap, const sp<StatsPullerManager>& pullerManager,
- const sp<AlarmMonitor>& anomalyAlarmMonitor,
- const sp<AlarmMonitor>& subscriberTriggerAlarmMonitor,
- const int64_t timeBaseNs,
- const std::function<bool(const ConfigKey&)>& sendBroadcast,
- const std::function<bool(const int&,
- const vector<int64_t>&)>& sendActivationBroadcast);
+ StatsLogProcessor(
+ const sp<UidMap>& uidMap, const sp<StatsPullerManager>& pullerManager,
+ const sp<AlarmMonitor>& anomalyAlarmMonitor,
+ const sp<AlarmMonitor>& subscriberTriggerAlarmMonitor, const int64_t timeBaseNs,
+ const std::function<bool(const ConfigKey&)>& sendBroadcast,
+ const std::function<bool(const int&, const vector<int64_t>&)>& sendActivationBroadcast,
+ const std::function<void(const ConfigKey&, const string&, const vector<int64_t>&)>&
+ sendRestrictedMetricsBroadcast);
+
virtual ~StatsLogProcessor();
void OnLogEvent(LogEvent* event);
@@ -297,6 +299,12 @@
// are currently active.
std::function<bool(const int& uid, const vector<int64_t>& configIds)> mSendActivationBroadcast;
+ // Function used to send a broadcast if necessary so the receiver can be notified of the
+ // restricted metrics for the given config.
+ std::function<void(const ConfigKey& key, const string& delegatePackage,
+ const vector<int64_t>& restrictedMetricIds)>
+ mSendRestrictedMetricsBroadcast;
+
const int64_t mTimeBaseNs;
// Largest timestamp of the events that we have processed.
diff --git a/statsd/src/StatsService.cpp b/statsd/src/StatsService.cpp
index 724cc04..10a958e 100644
--- a/statsd/src/StatsService.cpp
+++ b/statsd/src/StatsService.cpp
@@ -35,6 +35,7 @@
#include "android-base/stringprintf.h"
#include "config/ConfigKey.h"
#include "config/ConfigManager.h"
+#include "flags/FlagProvider.h"
#include "guardrail/StatsdStats.h"
#include "stats_log_util.h"
#include "storage/StorageManager.h"
@@ -163,6 +164,13 @@
}
VLOG("StatsService::active configs broadcast failed for uid %d", uid);
return false;
+ },
+ [this](const ConfigKey& key, const string& delegatePackage,
+ const vector<int64_t>& restrictedMetrics) {
+ set<string> configPackages = mUidMap->getAppNamesFromUid(key.GetUid(), true);
+ set<int32_t> delegateUids = mUidMap->getAppUid(delegatePackage);
+ mConfigManager->SendRestrictedMetricsBroadcast(configPackages, key.GetId(),
+ delegateUids, restrictedMetrics);
});
mUidMap->setListener(mProcessor);
@@ -1350,11 +1358,32 @@
mPullerManager->SetStatsCompanionService(nullptr);
}
-Status StatsService::setRestrictedMetricsChangedOperation(const int64_t configKey,
+Status StatsService::setRestrictedMetricsChangedOperation(const int64_t configId,
const string& configPackage,
+ const shared_ptr<IPendingIntentRef>& pir,
+ const int32_t callingUid,
vector<int64_t>* output) {
ENFORCE_UID(AID_SYSTEM);
- // query db using configKey and populate output.
+ if (!FlagProvider::getInstance().getBootFlagBool(RESTRICTED_METRICS_FLAG, FLAG_FALSE)) {
+ return Status::ok();
+ }
+ mConfigManager->SetRestrictedMetricsChangedReceiver(configPackage, configId, callingUid, pir);
+ if (output != nullptr) {
+ // TODO(b/269419485): implement getting the current restricted metrics.
+ } else {
+ ALOGW("StatsService::setRestrictedMetricsChangedOperation output was nullptr");
+ }
+ return Status::ok();
+}
+
+Status StatsService::removeRestrictedMetricsChangedOperation(const int64_t configId,
+ const string& configPackage,
+ const int32_t callingUid) {
+ ENFORCE_UID(AID_SYSTEM);
+ if (!FlagProvider::getInstance().getBootFlagBool(RESTRICTED_METRICS_FLAG, FLAG_FALSE)) {
+ return Status::ok();
+ }
+ mConfigManager->RemoveRestrictedMetricsChangedReceiver(configPackage, configId, callingUid);
return Status::ok();
}
diff --git a/statsd/src/StatsService.h b/statsd/src/StatsService.h
index af94603..1d67633 100644
--- a/statsd/src/StatsService.h
+++ b/statsd/src/StatsService.h
@@ -210,13 +210,24 @@
virtual Status updateProperties(const std::vector<PropertyParcel>& properties);
/**
- * Binder call to let clients register the active configs changed operation.
+ * Binder call to let clients register the restricted metrics changed operation for the given
+ * config and calling uid.
*/
virtual Status setRestrictedMetricsChangedOperation(const int64_t configKey,
const string& configPackage,
+ const shared_ptr<IPendingIntentRef>& pir,
+ const int32_t callingUid,
vector<int64_t>* output);
/**
+ * Binder call to remove the restricted metrics changed operation for the specified config
+ * and calling uid.
+ */
+ virtual Status removeRestrictedMetricsChangedOperation(const int64_t configKey,
+ const string& configPackage,
+ const int32_t callingUid);
+
+ /**
* Binder call to query data in statsd sql store.
*/
virtual Status querySql(const string& sqlQuery, const int32_t minSqlClientVersion,
diff --git a/statsd/src/config/ConfigKeyWithPackage.h b/statsd/src/config/ConfigKeyWithPackage.h
new file mode 100644
index 0000000..85e95d5
--- /dev/null
+++ b/statsd/src/config/ConfigKeyWithPackage.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using std::hash;
+using std::string;
+
+/**
+ * A config key that uses a package name instead of a uid. Generally, ConfigKey which uses a uid
+ * should be used. This is currently only used for restricted metrics changed operation.
+ */
+class ConfigKeyWithPackage {
+public:
+ ConfigKeyWithPackage(const string& package, const int64_t id) : mPackage(package), mId(id) {
+ }
+
+ inline string GetPackage() const {
+ return mPackage;
+ }
+ inline int64_t GetId() const {
+ return mId;
+ }
+
+ inline bool operator<(const ConfigKeyWithPackage& that) const {
+ if (mPackage != that.mPackage) {
+ return mPackage < that.mPackage;
+ }
+ return mId < that.mId;
+ };
+
+ inline bool operator==(const ConfigKeyWithPackage& that) const {
+ return mPackage == that.mPackage && mId == that.mId;
+ };
+
+private:
+ string mPackage;
+ int64_t mId;
+};
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/statsd/src/config/ConfigManager.cpp b/statsd/src/config/ConfigManager.cpp
index 570cd45..3a9c69c 100644
--- a/statsd/src/config/ConfigManager.cpp
+++ b/statsd/src/config/ConfigManager.cpp
@@ -37,6 +37,8 @@
using std::string;
using std::vector;
+using Status = ::ndk::ScopedAStatus;
+
#define STATS_SERVICE_DIR "/data/misc/stats-service"
using android::base::StringPrintf;
@@ -152,6 +154,61 @@
}
}
+void ConfigManager::SetRestrictedMetricsChangedReceiver(const string& configPackage,
+ const int64_t configId,
+ const int32_t callingUid,
+ const shared_ptr<IPendingIntentRef>& pir) {
+ lock_guard<mutex> lock(mMutex);
+ ConfigKeyWithPackage configKey(configPackage, configId);
+ mRestrictedMetricsChangedReceivers[configKey][callingUid] = pir;
+}
+
+void ConfigManager::RemoveRestrictedMetricsChangedReceiver(const string& configPackage,
+ const int64_t configId,
+ const int32_t callingUid) {
+ lock_guard<mutex> lock(mMutex);
+ ConfigKeyWithPackage configKey(configPackage, configId);
+ const auto& it = mRestrictedMetricsChangedReceivers.find(configKey);
+ if (it != mRestrictedMetricsChangedReceivers.end()) {
+ it->second.erase(callingUid);
+ if (it->second.empty()) {
+ mRestrictedMetricsChangedReceivers.erase(it);
+ }
+ }
+}
+
+void ConfigManager::SendRestrictedMetricsBroadcast(const set<string>& configPackages,
+ const int64_t configId,
+ const set<int32_t>& delegateUids,
+ const vector<int64_t>& metricIds) {
+ set<shared_ptr<IPendingIntentRef>> intentsToSend;
+ {
+ lock_guard<mutex> lock(mMutex);
+ // Invoke the pending intent for all matching configs, as long as the listening delegates
+ // match the allowed delegate uids specified by the config.
+ for (const string& configPackage : configPackages) {
+ ConfigKeyWithPackage key(configPackage, configId);
+ const auto& it = mRestrictedMetricsChangedReceivers.find(key);
+ if (it != mRestrictedMetricsChangedReceivers.end()) {
+ for (const auto& [delegateUid, pir] : it->second) {
+ if (delegateUids.find(delegateUid) != delegateUids.end()) {
+ intentsToSend.insert(pir);
+ }
+ }
+ }
+ }
+ }
+
+ // Invoke the pending intents without holding the lock.
+ for (const shared_ptr<IPendingIntentRef>& pir : intentsToSend) {
+ Status status = pir->sendRestrictedMetricsChangedBroadcast(metricIds);
+ if (status.isOk()) {
+ VLOG("ConfigManager::SendRestrictedMetricsBroadcast succeeded");
+ }
+ // TODO (b/269419485): handle failures.
+ }
+}
+
void ConfigManager::RemoveConfig(const ConfigKey& key) {
vector<sp<ConfigListener>> broadcastList;
{
@@ -181,6 +238,7 @@
StorageManager::deleteSuffixedFiles(STATS_SERVICE_DIR, suffix.c_str());
}
+// TODO(b/xxx): consider removing all receivers associated with this uid.
void ConfigManager::RemoveConfigs(int uid) {
vector<ConfigKey> removed;
vector<sp<ConfigListener>> broadcastList;
diff --git a/statsd/src/config/ConfigManager.h b/statsd/src/config/ConfigManager.h
index 9a0f504..57ca00d 100644
--- a/statsd/src/config/ConfigManager.h
+++ b/statsd/src/config/ConfigManager.h
@@ -16,14 +16,15 @@
#pragma once
-#include "config/ConfigKey.h"
-#include "config/ConfigListener.h"
-
#include <aidl/android/os/IPendingIntentRef.h>
+#include <stdio.h>
+
#include <mutex>
#include <string>
-#include <stdio.h>
+#include "config/ConfigKey.h"
+#include "config/ConfigKeyWithPackage.h"
+#include "config/ConfigListener.h"
using aidl::android::os::IPendingIntentRef;
using std::shared_ptr;
@@ -113,6 +114,27 @@
const shared_ptr<IPendingIntentRef>& pir);
/**
+ * Sets the pending intent that is notified whenever the list of restricted metrics changes
+ */
+ void SetRestrictedMetricsChangedReceiver(const string& configPackage, const int64_t configId,
+ const int32_t callingUid,
+ const shared_ptr<IPendingIntentRef>& pir);
+
+ /**
+ * Erase any restricted metrics changed pending intents associated with this config key & uid.
+ */
+ void RemoveRestrictedMetricsChangedReceiver(const string& configPackage, const int64_t configId,
+ const int32_t callingUid);
+
+ /**
+ * Sends a restricted metrics broadcast for the valid config keys and delegate package
+ */
+ void SendRestrictedMetricsBroadcast(const std::set<string>& configPackages,
+ const int64_t configId,
+ const std::set<int32_t>& delegateUids,
+ const std::vector<int64_t>& metricIds);
+
+ /**
* A configuration was removed.
*
* Reports this to listeners.
@@ -166,6 +188,13 @@
std::map<int, shared_ptr<IPendingIntentRef>> mActiveConfigsChangedReceivers;
/**
+ * Each uid can subscribe up to one receiver for a particular config to receive the restricted
+ * metrics for that config. The receiver is specified as IPendingIntentRef.
+ */
+ std::map<ConfigKeyWithPackage, std::map<int32_t, shared_ptr<IPendingIntentRef>>>
+ mRestrictedMetricsChangedReceivers;
+
+ /**
* The ConfigListeners that will be told about changes.
*/
std::vector<sp<ConfigListener>> mListeners;
diff --git a/statsd/src/metrics/MetricsManager.cpp b/statsd/src/metrics/MetricsManager.cpp
index b725f72..6c699b7 100644
--- a/statsd/src/metrics/MetricsManager.cpp
+++ b/statsd/src/metrics/MetricsManager.cpp
@@ -839,6 +839,15 @@
return possibleUids.find(callingUid) != possibleUids.end();
}
+vector<int64_t> MetricsManager::getAllMetricIds() const {
+ vector<int64_t> metricIds;
+ metricIds.reserve(mMetricProducerMap.size());
+ for (const auto& [metricId, _] : mMetricProducerMap) {
+ metricIds.push_back(metricId);
+ }
+ return metricIds;
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/statsd/src/metrics/MetricsManager.h b/statsd/src/metrics/MetricsManager.h
index 7062b34..d336db5 100644
--- a/statsd/src/metrics/MetricsManager.h
+++ b/statsd/src/metrics/MetricsManager.h
@@ -168,10 +168,17 @@
return mRestrictedMetricsDelegatePackageName.has_value();
}
+ inline string getRestrictedMetricsDelegate() const {
+ return hasRestrictedMetricsDelegate() ? mRestrictedMetricsDelegatePackageName.value() : "";
+ }
+
void enforceRestrictedDataTtls(const int64_t wallClockNs);
bool validateRestrictedMetricsDelegate(const int32_t callingUid);
+ // Slow, should not be called in a hotpath.
+ vector<int64_t> getAllMetricIds() const;
+
private:
// For test only.
inline int64_t getTtlEndNs() const { return mTtlEndNs; }