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/aidl/android/os/IPendingIntentRef.aidl b/aidl/android/os/IPendingIntentRef.aidl index 000a699..5a0f5d7 100644 --- a/aidl/android/os/IPendingIntentRef.aidl +++ b/aidl/android/os/IPendingIntentRef.aidl
@@ -43,4 +43,10 @@ oneway void sendSubscriberBroadcast(long configUid, long configId, long subscriptionId, long subscriptionRuleId, in String[] cookies, in StatsDimensionsValueParcel dimensionsValueParcel); + + /** + * Send a broadcast to the specified PendingIntent notifying it that the list of restricted + * metrics has changed. + */ + oneway void sendRestrictedMetricsChangedBroadcast(in long[] metricIds); }
diff --git a/aidl/android/os/IStatsManagerService.aidl b/aidl/android/os/IStatsManagerService.aidl index 4cab035..4cfef2d 100644 --- a/aidl/android/os/IStatsManagerService.aidl +++ b/aidl/android/os/IStatsManagerService.aidl
@@ -148,7 +148,16 @@ * for a specified config that are present for this client. This operation allows statsd to * inform the client about the current restricted metrics available to be queried for * the specified config. + * + * Requires Manifest.permission.READ_RESTRICTED_STATS. */ long[] setRestrictedMetricsChangedOperation(in PendingIntent pendingIntent, in long configKey, in String configPackage); + + /** + * Removes the restricted metrics changed operation for the specified config key/package. + * + * Requires Manifest.permission.READ_RESTRICTED_STATS. + */ + void removeRestrictedMetricsChangedOperation(in long configKey, in String configPackage); }
diff --git a/aidl/android/os/IStatsd.aidl b/aidl/android/os/IStatsd.aidl index 2a84515..5d4f6fd 100644 --- a/aidl/android/os/IStatsd.aidl +++ b/aidl/android/os/IStatsd.aidl
@@ -250,10 +250,22 @@ oneway void querySql(in String sqlQuery, in int minSqlClientVersion, in StatsPolicyConfigParcel policyConfig, in IStatsQueryCallback queryCallback, in long configKey, in String configPackage, in int callingUid); + /** * Registers the operation that is called whenever there is a change in the restricted metrics * for a specified config that are present for this client. This operation allows statsd to inform the * client about the current restricted metrics available to be queried for the specified config. + * + * Requires Manifest.permission.READ_RESTRICTED_STATS */ - long[] setRestrictedMetricsChangedOperation(in long configKey, in String configPackage); + long[] setRestrictedMetricsChangedOperation(in long configKey, in String configPackage, + in IPendingIntentRef pir, int callingUid); + + /** + * Removes the restricted metrics changed operation for the specified config package/id. + * + * Requires Manifest.permission.READ_RESTRICTED_STATS. + */ + void removeRestrictedMetricsChangedOperation(in long configKey, in String configPackage, + in int callingUid); }
diff --git a/framework/java/android/app/StatsManager.java b/framework/java/android/app/StatsManager.java index ebd21f2..cd9016a 100644 --- a/framework/java/android/app/StatsManager.java +++ b/framework/java/android/app/StatsManager.java
@@ -404,7 +404,7 @@ try { IStatsManagerService service = getIStatsManagerServiceLocked(); if (pendingIntent == null) { - // TODO + service.removeRestrictedMetricsChangedOperation(configKey, configPackage); return new long[0]; } else { return service.setRestrictedMetricsChangedOperation(pendingIntent,
diff --git a/service/java/com/android/server/stats/StatsCompanion.java b/service/java/com/android/server/stats/StatsCompanion.java index dc477a5..d0954ea 100644 --- a/service/java/com/android/server/stats/StatsCompanion.java +++ b/service/java/com/android/server/stats/StatsCompanion.java
@@ -112,6 +112,7 @@ private static final int CODE_DATA_BROADCAST = 1; private static final int CODE_ACTIVE_CONFIGS_BROADCAST = 1; private static final int CODE_SUBSCRIBER_BROADCAST = 1; + private static final int CODE_RESTRICTED_METRICS_BROADCAST = 1; private final PendingIntent mPendingIntent; private final Context mContext; @@ -184,5 +185,24 @@ + "; presumably it had been cancelled."); } } + + @Override + public void sendRestrictedMetricsChangedBroadcast(long[] metricIds) { + enforceStatsdCallingUid(); + Intent intent = new Intent(); + intent.putExtra(StatsManager.EXTRA_STATS_RESTRICTED_METRIC_IDS, metricIds); + try { + mPendingIntent.send(mContext, CODE_RESTRICTED_METRICS_BROADCAST, intent, null, + null); + if (DEBUG) { + Log.d(TAG, + "Sent restricted metrics broadcast with metric ids " + Arrays.toString( + metricIds)); + } + } catch (PendingIntent.CanceledException e) { + Log.w(TAG, + "Unable to send restricted metrics changed broadcast using PendingIntent"); + } + } } }
diff --git a/service/java/com/android/server/stats/StatsManagerService.java b/service/java/com/android/server/stats/StatsManagerService.java index 7cd841a..bd70ea0 100644 --- a/service/java/com/android/server/stats/StatsManagerService.java +++ b/service/java/com/android/server/stats/StatsManagerService.java
@@ -68,6 +68,9 @@ @GuardedBy("mLock") private ArrayMap<ConfigKey, ArrayMap<Long, PendingIntentRef>> mBroadcastSubscriberPirMap = new ArrayMap<>(); + @GuardedBy("mLock") + private ArrayMap<ConfigKeyWithPackage, ArrayMap<Integer, PendingIntentRef>> + mRestrictedMetricsPirMap = new ArrayMap<>(); public StatsManagerService(Context context) { super(); @@ -106,6 +109,39 @@ } } + private static class ConfigKeyWithPackage { + private final String mConfigPackage; + private final long mConfigId; + + ConfigKeyWithPackage(String configPackage, long configId) { + mConfigPackage = configPackage; + mConfigId = configId; + } + + public String getConfigPackage() { + return mConfigPackage; + } + + public long getConfigId() { + return mConfigId; + } + + @Override + public int hashCode() { + return Objects.hash(mConfigPackage, mConfigId); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ConfigKeyWithPackage) { + ConfigKeyWithPackage other = (ConfigKeyWithPackage) obj; + return this.mConfigPackage.equals(other.getConfigPackage()) + && this.mConfigId == other.getConfigId(); + } + return false; + } + } + private static class PullerKey { private final int mUid; private final int mAtomTag; @@ -481,21 +517,57 @@ @Override public long[] setRestrictedMetricsChangedOperation(PendingIntent pendingIntent, - long configKey, String configPackage) { + long configId, String configPackage) { enforceRestrictedStatsPermission(); + int callingUid = Binder.getCallingUid(); final long token = Binder.clearCallingIdentity(); - // TODO: create aidl interface for pendingIntent similar to PendingIntentRef. + PendingIntentRef pir = new PendingIntentRef(pendingIntent, mContext); + ConfigKeyWithPackage key = new ConfigKeyWithPackage(configPackage, configId); + // Add the PIR to a map so we can re-register if statsd is unavailable. + synchronized (mLock) { + ArrayMap<Integer, PendingIntentRef> innerMap = mRestrictedMetricsPirMap.getOrDefault( + key, new ArrayMap<>()); + innerMap.put(callingUid, pir); + mRestrictedMetricsPirMap.put(key, innerMap); + } try { IStatsd statsd = getStatsdNonblocking(); if (statsd != null) { - return statsd.setRestrictedMetricsChangedOperation(configKey, configPackage); + return statsd.setRestrictedMetricsChangedOperation(configId, configPackage, pir, + callingUid); } } catch (RemoteException e) { Log.e(TAG, "Failed to setRestrictedMetricsChangedOperation with statsd"); } finally { Binder.restoreCallingIdentity(token); } - return new long[] {}; + return new long[]{}; + } + + @Override + public void removeRestrictedMetricsChangedOperation(long configId, String configPackage) { + enforceRestrictedStatsPermission(); + int callingUid = Binder.getCallingUid(); + final long token = Binder.clearCallingIdentity(); + ConfigKeyWithPackage key = new ConfigKeyWithPackage(configPackage, configId); + synchronized (mLock) { + ArrayMap<Integer, PendingIntentRef> innerMap = mRestrictedMetricsPirMap.getOrDefault( + key, new ArrayMap<>()); + innerMap.remove(callingUid); + if (innerMap.isEmpty()) { + mRestrictedMetricsPirMap.remove(key); + } + } + try { + IStatsd statsd = getStatsdNonblocking(); + if (statsd != null) { + statsd.removeRestrictedMetricsChangedOperation(configId, configPackage, callingUid); + } + } catch (RemoteException e) { + Log.e(TAG, "Failed to removeRestrictedMetricsChangedOperation with statsd"); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override @@ -642,6 +714,7 @@ registerAllDataFetchOperations(statsd); registerAllActiveConfigsChangedOperations(statsd); registerAllBroadcastSubscribers(statsd); + // TODO (b/269419485): register all restricted metric operations. } catch (RemoteException e) { Log.e(TAG, "StatsManager failed to (re-)register data with statsd"); } finally {
diff --git a/statsd/benchmark/metric_util.cpp b/statsd/benchmark/metric_util.cpp index 89fd3d9..5beb06f 100644 --- a/statsd/benchmark/metric_util.cpp +++ b/statsd/benchmark/metric_util.cpp
@@ -354,10 +354,11 @@ sp<StatsPullerManager> pullerManager = new StatsPullerManager(); sp<AlarmMonitor> anomalyAlarmMonitor; sp<AlarmMonitor> periodicAlarmMonitor; - sp<StatsLogProcessor> processor = - new StatsLogProcessor(uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, - timeBaseSec * NS_PER_SEC, [](const ConfigKey&) { return true; }, - [](const int&, const vector<int64_t>&) { return true; }); + sp<StatsLogProcessor> processor = new StatsLogProcessor( + uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, + timeBaseSec * NS_PER_SEC, [](const ConfigKey&) { return true; }, + [](const int&, const vector<int64_t>&) { return true; }, + [](const ConfigKey&, const string&, const vector<int64_t>&) {}); processor->OnConfigUpdated(timeBaseSec * NS_PER_SEC, key, config); return processor; }
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; }
diff --git a/statsd/tests/StatsLogProcessor_test.cpp b/statsd/tests/StatsLogProcessor_test.cpp index 3aa142e..3cd0355 100644 --- a/statsd/tests/StatsLogProcessor_test.cpp +++ b/statsd/tests/StatsLogProcessor_test.cpp
@@ -96,9 +96,11 @@ sp<AlarmMonitor> anomalyAlarmMonitor; sp<AlarmMonitor> periodicAlarmMonitor; // Construct the processor with a no-op sendBroadcast function that does nothing. - StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, 0, - [](const ConfigKey& key) { return true; }, - [](const int&, const vector<int64_t>&) {return true;}); + StatsLogProcessor p( + m, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, 0, + [](const ConfigKey& key) { return true; }, + [](const int&, const vector<int64_t>&) { return true; }, + [](const ConfigKey&, const string&, const vector<int64_t>&) {}); MockMetricsManager mockMetricsManager; @@ -117,12 +119,14 @@ sp<AlarmMonitor> anomalyAlarmMonitor; sp<AlarmMonitor> subscriberAlarmMonitor; int broadcastCount = 0; - StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0, - [&broadcastCount](const ConfigKey& key) { - broadcastCount++; - return true; - }, - [](const int&, const vector<int64_t>&) {return true;}); + StatsLogProcessor p( + m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0, + [&broadcastCount](const ConfigKey& key) { + broadcastCount++; + return true; + }, + [](const int&, const vector<int64_t>&) { return true; }, + [](const ConfigKey&, const string&, const vector<int64_t>&) {}); MockMetricsManager mockMetricsManager; @@ -149,12 +153,14 @@ sp<AlarmMonitor> anomalyAlarmMonitor; sp<AlarmMonitor> subscriberAlarmMonitor; int broadcastCount = 0; - StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0, - [&broadcastCount](const ConfigKey& key) { - broadcastCount++; - return true; - }, - [](const int&, const vector<int64_t>&) {return true;}); + StatsLogProcessor p( + m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0, + [&broadcastCount](const ConfigKey& key) { + broadcastCount++; + return true; + }, + [](const int&, const vector<int64_t>&) { return true; }, + [](const ConfigKey&, const string&, const vector<int64_t>&) {}); MockMetricsManager mockMetricsManager; @@ -223,12 +229,14 @@ sp<AlarmMonitor> anomalyAlarmMonitor; sp<AlarmMonitor> subscriberAlarmMonitor; int broadcastCount = 0; - StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0, - [&broadcastCount](const ConfigKey& key) { - broadcastCount++; - return true; - }, - [](const int&, const vector<int64_t>&) {return true;}); + StatsLogProcessor p( + m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0, + [&broadcastCount](const ConfigKey& key) { + broadcastCount++; + return true; + }, + [](const int&, const vector<int64_t>&) { return true; }, + [](const ConfigKey&, const string&, const vector<int64_t>&) {}); ConfigKey key(3, 4); StatsdConfig config = MakeConfig(true); p.OnConfigUpdated(0, key, config); @@ -255,12 +263,14 @@ sp<AlarmMonitor> anomalyAlarmMonitor; sp<AlarmMonitor> subscriberAlarmMonitor; int broadcastCount = 0; - StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0, - [&broadcastCount](const ConfigKey& key) { - broadcastCount++; - return true; - }, - [](const int&, const vector<int64_t>&) {return true;}); + StatsLogProcessor p( + m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0, + [&broadcastCount](const ConfigKey& key) { + broadcastCount++; + return true; + }, + [](const int&, const vector<int64_t>&) { return true; }, + [](const ConfigKey&, const string&, const vector<int64_t>&) {}); ConfigKey key(3, 4); StatsdConfig config = MakeConfig(false); p.OnConfigUpdated(0, key, config); @@ -282,12 +292,14 @@ sp<AlarmMonitor> anomalyAlarmMonitor; sp<AlarmMonitor> subscriberAlarmMonitor; int broadcastCount = 0; - StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0, - [&broadcastCount](const ConfigKey& key) { - broadcastCount++; - return true; - }, - [](const int&, const vector<int64_t>&) {return true;}); + StatsLogProcessor p( + m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0, + [&broadcastCount](const ConfigKey& key) { + broadcastCount++; + return true; + }, + [](const int&, const vector<int64_t>&) { return true; }, + [](const ConfigKey&, const string&, const vector<int64_t>&) {}); ConfigKey key(3, 4); StatsdConfig config; auto annotation = config.add_annotation(); @@ -366,7 +378,8 @@ StatsLogProcessor p( m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0, [](const ConfigKey& key) { return true; }, - [](const int&, const vector<int64_t>&) { return true; }); + [](const int&, const vector<int64_t>&) { return true; }, + [](const ConfigKey&, const string&, const vector<int64_t>&) {}); ConfigKey key(3, 4); StatsdConfig config = MakeConfig(false); p.OnConfigUpdated(0, key, config); @@ -389,9 +402,11 @@ /* certificateHash */ {{}, {}}); sp<AlarmMonitor> anomalyAlarmMonitor; sp<AlarmMonitor> subscriberAlarmMonitor; - StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0, - [](const ConfigKey& key) { return true; }, - [](const int&, const vector<int64_t>&) {return true;}); + StatsLogProcessor p( + m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0, + [](const ConfigKey& key) { return true; }, + [](const int&, const vector<int64_t>&) { return true; }, + [](const ConfigKey&, const string&, const vector<int64_t>&) {}); ConfigKey key(3, 4); StatsdConfig config = MakeConfig(true); // Remove the config mConfigStats so that the Icebox starts at 0 configs. @@ -526,7 +541,8 @@ activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(), activeConfigs.end()); return true; - }); + }, + [](const ConfigKey&, const string&, const vector<int64_t>&) {}); processor.OnConfigUpdated(1, cfgKey1, config1); processor.OnConfigUpdated(2, cfgKey2, config2); @@ -2081,7 +2097,8 @@ StatsLogProcessor p( m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0, [](const ConfigKey& key) { return true; }, - [](const int&, const vector<int64_t>&) { return true; }); + [](const int&, const vector<int64_t>&) { return true; }, + [](const ConfigKey&, const string&, const vector<int64_t>&) {}); ConfigKey key(3, 4); StatsdConfig config = MakeConfig(true); config.set_restricted_metrics_delegate_package_name("rm_package");
diff --git a/statsd/tests/UidMap_test.cpp b/statsd/tests/UidMap_test.cpp index a303ac6..53bff98 100644 --- a/statsd/tests/UidMap_test.cpp +++ b/statsd/tests/UidMap_test.cpp
@@ -114,7 +114,8 @@ StatsLogProcessor p( m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0, [](const ConfigKey& key) { return true; }, - [](const int&, const vector<int64_t>&) { return true; }); + [](const int&, const vector<int64_t>&) { return true; }, + [](const ConfigKey&, const string&, const vector<int64_t>&) {}); std::unique_ptr<LogEvent> addEvent = CreateIsolatedUidChangedEvent( 1 /*timestamp*/, 100 /*hostUid*/, 101 /*isolatedUid*/, 1 /*is_create*/);
diff --git a/statsd/tests/e2e/DurationMetric_e2e_test.cpp b/statsd/tests/e2e/DurationMetric_e2e_test.cpp index 09ce418..4537854 100644 --- a/statsd/tests/e2e/DurationMetric_e2e_test.cpp +++ b/statsd/tests/e2e/DurationMetric_e2e_test.cpp
@@ -249,7 +249,8 @@ activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(), activeConfigs.end()); return true; - }); + }, + [](const ConfigKey&, const string&, const vector<int64_t>&) {}); processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config); // 0:00
diff --git a/statsd/tests/e2e/MetricActivation_e2e_test.cpp b/statsd/tests/e2e/MetricActivation_e2e_test.cpp index e320419..e77174f 100644 --- a/statsd/tests/e2e/MetricActivation_e2e_test.cpp +++ b/statsd/tests/e2e/MetricActivation_e2e_test.cpp
@@ -263,7 +263,8 @@ activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(), activeConfigs.end()); return true; - }); + }, + [](const ConfigKey&, const string&, const vector<int64_t>&) {}); processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config); @@ -474,7 +475,8 @@ activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(), activeConfigs.end()); return true; - }); + }, + [](const ConfigKey&, const string&, const vector<int64_t>&) {}); processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config); @@ -795,7 +797,8 @@ activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(), activeConfigs.end()); return true; - }); + }, + [](const ConfigKey&, const string&, const vector<int64_t>&) {}); processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config); @@ -1128,7 +1131,8 @@ activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(), activeConfigs.end()); return true; - }); + }, + [](const ConfigKey&, const string&, const vector<int64_t>&) {}); processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config); @@ -1325,7 +1329,8 @@ activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(), activeConfigs.end()); return true; - }); + }, + [](const ConfigKey&, const string&, const vector<int64_t>&) {}); processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
diff --git a/statsd/tests/statsd_test_util.cpp b/statsd/tests/statsd_test_util.cpp index 3cef2d0..aa7732e 100644 --- a/statsd/tests/statsd_test_util.cpp +++ b/statsd/tests/statsd_test_util.cpp
@@ -1391,10 +1391,11 @@ new AlarmMonitor(1, [](const shared_ptr<IStatsCompanionService>&, int64_t){}, [](const shared_ptr<IStatsCompanionService>&){}); - sp<StatsLogProcessor> processor = - new StatsLogProcessor(uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, - timeBaseNs, [](const ConfigKey&) { return true; }, - [](const int&, const vector<int64_t>&) {return true;}); + sp<StatsLogProcessor> processor = new StatsLogProcessor( + uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, timeBaseNs, + [](const ConfigKey&) { return true; }, + [](const int&, const vector<int64_t>&) { return true; }, + [](const ConfigKey&, const string&, const vector<int64_t>&) {}); processor->OnConfigUpdated(currentTimeNs, key, config); return processor; }
diff --git a/statsd/tests/statsd_test_util.h b/statsd/tests/statsd_test_util.h index a8f93b1..368f16f 100644 --- a/statsd/tests/statsd_test_util.h +++ b/statsd/tests/statsd_test_util.h
@@ -87,6 +87,7 @@ public: MOCK_METHOD1(sendDataBroadcast, Status(int64_t lastReportTimeNs)); MOCK_METHOD1(sendActiveConfigsChangedBroadcast, Status(const vector<int64_t>& configIds)); + MOCK_METHOD1(sendRestrictedMetricsChangedBroadcast, Status(const vector<int64_t>& metricIds)); MOCK_METHOD6(sendSubscriberBroadcast, Status(int64_t configUid, int64_t configId, int64_t subscriptionId, int64_t subscriptionRuleId, const vector<string>& cookies,