Add log source filtering in statsd to filter out spams.
+ Add log source whitelist in StatsdConfig
+ Some changes in UidMap API. Listener needs to be wp instead of sp.
+ Update dogfood app config to have log source
+ Increase the stats service thread pool size to 10 (9+1).
TODO: add unit tests(b/70805664). This unit test takes some time to write.
Test: statsd_test & manual
Change-Id: I129b1cc13db5114db7417580962bd7cc4438519d
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index f6caca8..0c078d5 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -114,7 +114,8 @@
void StatsLogProcessor::OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config) {
ALOGD("Updated configuration for key %s", key.ToString().c_str());
- unique_ptr<MetricsManager> newMetricsManager = std::make_unique<MetricsManager>(key, config, mTimeBaseSec);
+
+ sp<MetricsManager> newMetricsManager = new MetricsManager(key, config, mTimeBaseSec, mUidMap);
auto it = mMetricsManagers.find(key);
if (it == mMetricsManagers.end() && mMetricsManagers.size() > StatsdStats::kMaxConfigCount) {
@@ -125,7 +126,12 @@
if (newMetricsManager->isConfigValid()) {
mUidMap->OnConfigUpdated(key);
newMetricsManager->setAnomalyMonitor(mAnomalyMonitor);
- mMetricsManagers[key] = std::move(newMetricsManager);
+ if (config.log_source().package().size() > 0) {
+ // We have to add listener after the MetricsManager is constructed because it's
+ // not safe to create wp or sp from this pointer inside its constructor.
+ mUidMap->addListener(newMetricsManager.get());
+ }
+ mMetricsManagers[key] = newMetricsManager;
// Why doesn't this work? mMetricsManagers.insert({key, std::move(newMetricsManager)});
VLOG("StatsdConfig valid");
} else {
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 7ec4e4b..1e5c426 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -56,7 +56,7 @@
private:
mutable mutex mBroadcastTimesMutex;
- std::unordered_map<ConfigKey, std::unique_ptr<MetricsManager>> mMetricsManagers;
+ std::unordered_map<ConfigKey, sp<MetricsManager>> mMetricsManagers;
std::unordered_map<ConfigKey, long> mLastBroadcastTimes;
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 4dd2539..dab3880 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -201,7 +201,7 @@
}
if (!args[0].compare(String8("print-uid-map"))) {
- return cmd_print_uid_map(out);
+ return cmd_print_uid_map(out, args);
}
if (!args[0].compare(String8("dump-report"))) {
@@ -248,9 +248,10 @@
fprintf(out, " # adb shell start\n");
fprintf(out, "\n");
fprintf(out, "\n");
- fprintf(out, "usage: adb shell cmd stats print-uid-map \n");
+ fprintf(out, "usage: adb shell cmd stats print-uid-map [PKG]\n");
fprintf(out, "\n");
fprintf(out, " Prints the UID, app name, version mapping.\n");
+ fprintf(out, " PKG Optional package name to print the uids of the package\n");
fprintf(out, "\n");
fprintf(out, "\n");
fprintf(out, "usage: adb shell cmd stats pull-source [int] \n");
@@ -497,8 +498,19 @@
return NO_ERROR;
}
-status_t StatsService::cmd_print_uid_map(FILE* out) {
- mUidMap->printUidMap(out);
+status_t StatsService::cmd_print_uid_map(FILE* out, const Vector<String8>& args) {
+ if (args.size() > 1) {
+ string pkg;
+ pkg.assign(args[1].c_str(), args[1].size());
+ auto uids = mUidMap->getAppUid(pkg);
+ fprintf(out, "%s -> [ ", pkg.c_str());
+ for (const auto& uid : uids) {
+ fprintf(out, "%d ", uid);
+ }
+ fprintf(out, "]\n");
+ } else {
+ mUidMap->printUidMap(out);
+ }
return NO_ERROR;
}
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index e434f65..08fcdac 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -158,7 +158,7 @@
/**
* Print the mapping of uids to package names.
*/
- status_t cmd_print_uid_map(FILE* out);
+ status_t cmd_print_uid_map(FILE* out, const Vector<String8>& args);
/**
* Flush the data to disk.
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index a6d2719..cb3f3d6 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -248,6 +248,12 @@
details->add_section(12);
details->add_section(13);*/
+ AllowedLogSource* logSource = config.mutable_log_source();
+ logSource->add_uid(1000);
+ logSource->add_uid(0);
+ logSource->add_package("com.android.statsd.dogfood");
+ logSource->add_package("com.android.bluetooth");
+
// Count process state changes, slice by uid.
metric = config.add_count_metric();
metric->set_name("METRIC_2");
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 4cf168e..cb868e1f 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -46,6 +46,8 @@
const static int kMaxTimestampCount = 20;
+ const static int kMaxLogSourceCount = 50;
+
// Max memory allowed for storing metrics per configuration. When this limit is approached,
// statsd will send a broadcast so that the client can fetch the data and clear this memory.
static const size_t kMaxMetricsBytesPerConfig = 128 * 1024;
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 01487f0..d660b5f 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -33,6 +33,7 @@
mContext =
create_android_log_parser(msg.msg() + sizeof(uint32_t), msg.len() - sizeof(uint32_t));
mTimestampNs = msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec;
+ mLogUid = msg.entry_v4.uid;
init(mContext);
}
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 6ff6b87..d3f38de 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -62,6 +62,10 @@
*/
int GetTagId() const { return mTagId; }
+ uint32_t GetUid() const {
+ return mLogUid;
+ }
+
/**
* Get the nth value, starting at 1.
*
@@ -133,6 +137,8 @@
uint64_t mTimestampNs;
int mTagId;
+
+ uint32_t mLogUid;
};
} // namespace statsd
diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp
index 41b24bc..4ce4768 100644
--- a/cmds/statsd/src/main.cpp
+++ b/cmds/statsd/src/main.cpp
@@ -105,7 +105,7 @@
// Set up the binder
sp<ProcessState> ps(ProcessState::self());
- ps->setThreadPoolMaxThreadCount(1); // everything is oneway, let it queue and save ram
+ ps->setThreadPoolMaxThreadCount(9);
ps->startThreadPool();
ps->giveThreadPoolName();
IPCThreadState::self()->disableBackgroundScheduling(true);
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index 59995d2..e32fc06 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -48,12 +48,6 @@
virtual ~CountMetricProducer();
- // TODO: Implement this later.
- virtual void notifyAppUpgrade(const string& apk, const int uid, const int64_t version)
- override{};
- // TODO: Implement this later.
- virtual void notifyAppRemoved(const string& apk, const int uid) override{};
-
protected:
void onMatchedLogEventInternalLocked(
const size_t matcherIndex, const HashableDimensionKey& eventKey,
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index e7aca7f..7044b4b 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -47,12 +47,6 @@
virtual sp<AnomalyTracker> createAnomalyTracker(const Alert &alert) override;
- // TODO: Implement this later.
- virtual void notifyAppUpgrade(const string& apk, const int uid, const int64_t version)
- override{};
- // TODO: Implement this later.
- virtual void notifyAppRemoved(const string& apk, const int uid) override{};
-
protected:
void onMatchedLogEventInternalLocked(
const size_t matcherIndex, const HashableDimensionKey& eventKey,
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index d720ead..6120ad8 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -40,12 +40,6 @@
virtual ~EventMetricProducer();
- // TODO: Implement this later.
- virtual void notifyAppUpgrade(const string& apk, const int uid, const int64_t version)
- override{};
- // TODO: Implement this later.
- virtual void notifyAppRemoved(const string& apk, const int uid) override{};
-
protected:
void startNewProtoOutputStreamLocked();
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index 4a037ff..19d51e8 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -45,8 +45,6 @@
// producer always reports the guage at the earliest time of the bucket when the condition is met.
class GaugeMetricProducer : public virtual MetricProducer, public virtual PullDataReceiver {
public:
- // TODO: Pass in the start time from MetricsManager, it should be consistent
- // for all metrics.
GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& countMetric,
const int conditionIndex, const sp<ConditionWizard>& wizard,
const int pullTagId, const int atomTagId, const int64_t startTimeNs);
@@ -56,12 +54,6 @@
// Handles when the pulled data arrives.
void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data) override;
- // TODO: Implement this later.
- virtual void notifyAppUpgrade(const string& apk, const int uid, const int64_t version)
- override{};
- // TODO: Implement this later.
- virtual void notifyAppRemoved(const string& apk, const int uid) override{};
-
protected:
void onMatchedLogEventInternalLocked(
const size_t matcherIndex, const HashableDimensionKey& eventKey,
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index d4a2195..7bd274d 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -27,6 +27,7 @@
#include <log/logprint.h>
#include <utils/RefBase.h>
+#include <unordered_map>
namespace android {
namespace os {
@@ -54,6 +55,18 @@
};
virtual ~MetricProducer(){};
+ void notifyAppUpgrade(const string& apk, const int uid, const int64_t version) override{
+ // TODO: Implement me.
+ };
+
+ void notifyAppRemoved(const string& apk, const int uid) override{
+ // TODO: Implement me.
+ };
+
+ void onUidMapReceived() override{
+ // TODO: Implement me.
+ };
+
// Consume the parsed stats log entry that already matched the "what" of the metric.
void onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event) {
std::lock_guard<std::mutex> lock(mMutex);
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index a5900f4..231bd8e 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -16,6 +16,7 @@
#define DEBUG true // STOPSHIP if true
#include "Log.h"
#include "MetricsManager.h"
+#include "statslog.h"
#include "CountMetricProducer.h"
#include "condition/CombinationConditionTracker.h"
@@ -44,12 +45,37 @@
const int FIELD_ID_METRICS = 1;
-MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config, const long timeBaseSec) : mConfigKey(key) {
+MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
+ const long timeBaseSec, sp<UidMap> uidMap)
+ : mConfigKey(key), mUidMap(uidMap) {
mConfigValid =
initStatsdConfig(key, config, timeBaseSec, mTagIds, mAllAtomMatchers, mAllConditionTrackers,
mAllMetricProducers, mAllAnomalyTrackers, mConditionToMetricMap,
mTrackerToMetricMap, mTrackerToConditionMap);
+ if (!config.has_log_source()) {
+ // TODO(b/70794411): uncomment the following line and remove the hard coded log source
+ // after all configs have the log source added.
+ // mConfigValid = false;
+ // ALOGE("Log source white list is empty! This config won't get any data.");
+
+ mAllowedUid.push_back(1000);
+ mAllowedUid.push_back(0);
+ mAllowedLogSources.insert(mAllowedUid.begin(), mAllowedUid.end());
+ } else {
+ mAllowedUid.insert(mAllowedUid.begin(), config.log_source().uid().begin(),
+ config.log_source().uid().end());
+ mAllowedPkg.insert(mAllowedPkg.begin(), config.log_source().package().begin(),
+ config.log_source().package().end());
+
+ if (mAllowedUid.size() + mAllowedPkg.size() > StatsdStats::kMaxLogSourceCount) {
+ ALOGE("Too many log sources. This is likely to be an error in the config.");
+ mConfigValid = false;
+ } else {
+ initLogSourceWhiteList();
+ }
+ }
+
// Guardrail. Reject the config if it's too big.
if (mAllMetricProducers.size() > StatsdStats::kMaxMetricCountPerConfig ||
mAllConditionTrackers.size() > StatsdStats::kMaxConditionCountPerConfig ||
@@ -69,10 +95,53 @@
VLOG("~MetricsManager()");
}
+void MetricsManager::initLogSourceWhiteList() {
+ std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex);
+ mAllowedLogSources.clear();
+ mAllowedLogSources.insert(mAllowedUid.begin(), mAllowedUid.end());
+
+ for (const auto& pkg : mAllowedPkg) {
+ auto uids = mUidMap->getAppUid(pkg);
+ mAllowedLogSources.insert(uids.begin(), uids.end());
+ }
+ if (DEBUG) {
+ for (const auto& uid : mAllowedLogSources) {
+ VLOG("Allowed uid %d", uid);
+ }
+ }
+}
+
bool MetricsManager::isConfigValid() const {
return mConfigValid;
}
+void MetricsManager::notifyAppUpgrade(const string& apk, const int uid, const int64_t version) {
+ // check if we care this package
+ if (std::find(mAllowedPkg.begin(), mAllowedPkg.end(), apk) == mAllowedPkg.end()) {
+ return;
+ }
+ // We will re-initialize the whole list because we don't want to keep the multi mapping of
+ // UID<->pkg inside MetricsManager to reduce the memory usage.
+ initLogSourceWhiteList();
+}
+
+void MetricsManager::notifyAppRemoved(const string& apk, const int uid) {
+ // check if we care this package
+ if (std::find(mAllowedPkg.begin(), mAllowedPkg.end(), apk) == mAllowedPkg.end()) {
+ return;
+ }
+ // We will re-initialize the whole list because we don't want to keep the multi mapping of
+ // UID<->pkg inside MetricsManager to reduce the memory usage.
+ initLogSourceWhiteList();
+}
+
+void MetricsManager::onUidMapReceived() {
+ if (mAllowedPkg.size() == 0) {
+ return;
+ }
+ initLogSourceWhiteList();
+}
+
void MetricsManager::onDumpReport(ProtoOutputStream* protoOutput) {
VLOG("=========================Metric Reports Start==========================");
uint64_t dumpTimeStampNs = time(nullptr) * NS_PER_SEC;
@@ -92,6 +161,14 @@
return;
}
+ if (event.GetTagId() != android::util::APP_HOOK) {
+ std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex);
+ if (mAllowedLogSources.find(event.GetUid()) == mAllowedLogSources.end()) {
+ VLOG("log source %d not on the whitelist", event.GetUid());
+ return;
+ }
+ }
+
int tagId = event.GetTagId();
uint64_t eventTime = event.GetTimestampNs();
if (mTagIds.find(tagId) == mTagIds.end()) {
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 738adc9..8faa75d 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -24,6 +24,7 @@
#include "logd/LogEvent.h"
#include "matchers/LogMatchingTracker.h"
#include "metrics/MetricProducer.h"
+#include "packages/UidMap.h"
#include <unordered_map>
@@ -32,9 +33,10 @@
namespace statsd {
// A MetricsManager is responsible for managing metrics from one single config source.
-class MetricsManager {
+class MetricsManager : public PackageInfoListener {
public:
- MetricsManager(const ConfigKey& configKey, const StatsdConfig& config, const long timeBaseSec);
+ MetricsManager(const ConfigKey& configKey, const StatsdConfig& config, const long timeBaseSec,
+ sp<UidMap> uidMap);
virtual ~MetricsManager();
@@ -48,6 +50,12 @@
void setAnomalyMonitor(const sp<AnomalyMonitor>& anomalyMonitor);
+ void notifyAppUpgrade(const string& apk, const int uid, const int64_t version) override;
+
+ void notifyAppRemoved(const string& apk, const int uid) override;
+
+ void onUidMapReceived() override;
+
// Config source owner can call onDumpReport() to get all the metrics collected.
virtual void onDumpReport(android::util::ProtoOutputStream* protoOutput);
@@ -58,6 +66,23 @@
private:
const ConfigKey mConfigKey;
+ sp<UidMap> mUidMap;
+
+ bool mConfigValid = false;
+
+ // The uid log sources from StatsdConfig.
+ std::vector<int32_t> mAllowedUid;
+
+ // The pkg log sources from StatsdConfig.
+ std::vector<std::string> mAllowedPkg;
+
+ // The combined uid sources (after translating pkg name to uid).
+ // Logs from uids that are not in the list will be ignored to avoid spamming.
+ std::set<int32_t> mAllowedLogSources;
+
+ // To guard access to mAllowedLogSources
+ mutable std::mutex mAllowedLogSourcesMutex;
+
// All event tags that are interesting to my metrics.
std::set<int> mTagIds;
@@ -102,7 +127,7 @@
// maps from ConditionTracker to MetricProducer
std::unordered_map<int, std::vector<int>> mConditionToMetricMap;
- bool mConfigValid = false;
+ void initLogSourceWhiteList();
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 51af83d..2f27e4e 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -47,12 +47,6 @@
void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data) override;
- // TODO: Implement this later.
- virtual void notifyAppUpgrade(const string& apk, const int uid, const int64_t version)
- override{};
- // TODO: Implement this later.
- virtual void notifyAppRemoved(const string& apk, const int uid) override{};
-
protected:
void onMatchedLogEventInternalLocked(
const size_t matcherIndex, const HashableDimensionKey& eventKey,
diff --git a/cmds/statsd/src/packages/PackageInfoListener.h b/cmds/statsd/src/packages/PackageInfoListener.h
index bc8b0de..df29eb0 100644
--- a/cmds/statsd/src/packages/PackageInfoListener.h
+++ b/cmds/statsd/src/packages/PackageInfoListener.h
@@ -32,6 +32,9 @@
// Notify interested listeners that the given apk and uid combination no longer exits.
virtual void notifyAppRemoved(const std::string& apk, const int uid) = 0;
+
+ // Notify the listener that the UidMap snapshot is available.
+ virtual void onUidMapReceived() = 0;
};
} // namespace statsd
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index 3018be1..21a9cf3 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -87,26 +87,41 @@
void UidMap::updateMap(const int64_t& timestamp, const vector<int32_t>& uid,
const vector<int64_t>& versionCode, const vector<String16>& packageName) {
- lock_guard<mutex> lock(mMutex); // Exclusively lock for updates.
+ vector<wp<PackageInfoListener>> broadcastList;
+ {
+ lock_guard<mutex> lock(mMutex); // Exclusively lock for updates.
- mMap.clear();
- for (size_t j = 0; j < uid.size(); j++) {
- mMap.insert(make_pair(uid[j],
- AppData(string(String8(packageName[j]).string()), versionCode[j])));
- }
+ mMap.clear();
+ for (size_t j = 0; j < uid.size(); j++) {
+ mMap.insert(make_pair(
+ uid[j], AppData(string(String8(packageName[j]).string()), versionCode[j])));
+ }
- auto snapshot = mOutput.add_snapshots();
- snapshot->set_timestamp_nanos(timestamp);
- for (size_t j = 0; j < uid.size(); j++) {
- auto t = snapshot->add_package_info();
- t->set_name(string(String8(packageName[j]).string()));
- t->set_version(int(versionCode[j]));
- t->set_uid(uid[j]);
+ auto snapshot = mOutput.add_snapshots();
+ snapshot->set_timestamp_nanos(timestamp);
+ for (size_t j = 0; j < uid.size(); j++) {
+ auto t = snapshot->add_package_info();
+ t->set_name(string(String8(packageName[j]).string()));
+ t->set_version(int(versionCode[j]));
+ t->set_uid(uid[j]);
+ }
+ mBytesUsed += snapshot->ByteSize();
+ StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
+ StatsdStats::getInstance().setUidMapSnapshots(mOutput.snapshots_size());
+ ensureBytesUsedBelowLimit();
+ getListenerListCopyLocked(&broadcastList);
}
- mBytesUsed += snapshot->ByteSize();
- StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
- StatsdStats::getInstance().setUidMapSnapshots(mOutput.snapshots_size());
- ensureBytesUsedBelowLimit();
+ // To avoid invoking callback while holding the internal lock. we get a copy of the listener
+ // list and invoke the callback. It's still possible that after we copy the list, a
+ // listener removes itself before we call it. It's then the listener's job to handle it (expect
+ // the callback to be called after listener is removed, and the listener should properly
+ // ignore it).
+ for (auto weakPtr : broadcastList) {
+ auto strongPtr = weakPtr.promote();
+ if (strongPtr != NULL) {
+ strongPtr->onUidMapReceived();
+ }
+ }
}
void UidMap::updateApp(const String16& app_16, const int32_t& uid, const int64_t& versionCode) {
@@ -115,37 +130,45 @@
void UidMap::updateApp(const int64_t& timestamp, const String16& app_16, const int32_t& uid,
const int64_t& versionCode) {
- lock_guard<mutex> lock(mMutex);
-
+ vector<wp<PackageInfoListener>> broadcastList;
string appName = string(String8(app_16).string());
+ {
+ lock_guard<mutex> lock(mMutex);
- // Notify any interested producers that this app has updated
- for (auto it : mSubscribers) {
- it->notifyAppUpgrade(appName, uid, versionCode);
+ auto log = mOutput.add_changes();
+ log->set_deletion(false);
+ log->set_timestamp_nanos(timestamp);
+ log->set_app(appName);
+ log->set_uid(uid);
+ log->set_version(versionCode);
+ mBytesUsed += log->ByteSize();
+ StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
+ StatsdStats::getInstance().setUidMapChanges(mOutput.changes_size());
+ ensureBytesUsedBelowLimit();
+
+ auto range = mMap.equal_range(int(uid));
+ bool found = false;
+ for (auto it = range.first; it != range.second; ++it) {
+ // If we find the exact same app name and uid, update the app version directly.
+ if (it->second.packageName == appName) {
+ it->second.versionCode = versionCode;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ // Otherwise, we need to add an app at this uid.
+ mMap.insert(make_pair(uid, AppData(appName, versionCode)));
+ }
+ getListenerListCopyLocked(&broadcastList);
}
- auto log = mOutput.add_changes();
- log->set_deletion(false);
- log->set_timestamp_nanos(timestamp);
- log->set_app(appName);
- log->set_uid(uid);
- log->set_version(versionCode);
- mBytesUsed += log->ByteSize();
- StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
- StatsdStats::getInstance().setUidMapChanges(mOutput.changes_size());
- ensureBytesUsedBelowLimit();
-
- auto range = mMap.equal_range(int(uid));
- for (auto it = range.first; it != range.second; ++it) {
- // If we find the exact same app name and uid, update the app version directly.
- if (it->second.packageName == appName) {
- it->second.versionCode = versionCode;
- return;
+ for (auto weakPtr : broadcastList) {
+ auto strongPtr = weakPtr.promote();
+ if (strongPtr != NULL) {
+ strongPtr->notifyAppUpgrade(appName, uid, versionCode);
}
}
-
- // Otherwise, we need to add an app at this uid.
- mMap.insert(make_pair(uid, AppData(appName, versionCode)));
}
void UidMap::ensureBytesUsedBelowLimit() {
@@ -174,42 +197,59 @@
removeApp(time(nullptr) * NS_PER_SEC, app_16, uid);
}
-void UidMap::removeApp(const int64_t& timestamp, const String16& app_16, const int32_t& uid) {
- lock_guard<mutex> lock(mMutex);
-
- string app = string(String8(app_16).string());
-
- for (auto it : mSubscribers) {
- it->notifyAppRemoved(app, uid);
- }
-
- auto log = mOutput.add_changes();
- log->set_deletion(true);
- log->set_timestamp_nanos(timestamp);
- log->set_app(app);
- log->set_uid(uid);
- mBytesUsed += log->ByteSize();
- StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
- StatsdStats::getInstance().setUidMapChanges(mOutput.changes_size());
- ensureBytesUsedBelowLimit();
-
- auto range = mMap.equal_range(int(uid));
- for (auto it = range.first; it != range.second; ++it) {
- if (it->second.packageName == app) {
- mMap.erase(it);
- return;
+void UidMap::getListenerListCopyLocked(vector<wp<PackageInfoListener>>* output) {
+ for (auto weakIt = mSubscribers.begin(); weakIt != mSubscribers.end();) {
+ auto strongPtr = weakIt->promote();
+ if (strongPtr != NULL) {
+ output->push_back(*weakIt);
+ weakIt++;
+ } else {
+ weakIt = mSubscribers.erase(weakIt);
+ VLOG("The UidMap listener is gone, remove it now");
}
}
- VLOG("removeApp failed to find the app %s with uid %i to remove", app.c_str(), uid);
- return;
}
-void UidMap::addListener(sp<PackageInfoListener> producer) {
+void UidMap::removeApp(const int64_t& timestamp, const String16& app_16, const int32_t& uid) {
+ vector<wp<PackageInfoListener>> broadcastList;
+ string app = string(String8(app_16).string());
+ {
+ lock_guard<mutex> lock(mMutex);
+
+ auto log = mOutput.add_changes();
+ log->set_deletion(true);
+ log->set_timestamp_nanos(timestamp);
+ log->set_app(app);
+ log->set_uid(uid);
+ mBytesUsed += log->ByteSize();
+ StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
+ StatsdStats::getInstance().setUidMapChanges(mOutput.changes_size());
+ ensureBytesUsedBelowLimit();
+
+ auto range = mMap.equal_range(int(uid));
+ for (auto it = range.first; it != range.second; ++it) {
+ if (it->second.packageName == app) {
+ mMap.erase(it);
+ break;
+ }
+ }
+ getListenerListCopyLocked(&broadcastList);
+ }
+
+ for (auto weakPtr : broadcastList) {
+ auto strongPtr = weakPtr.promote();
+ if (strongPtr != NULL) {
+ strongPtr->notifyAppRemoved(app, uid);
+ }
+ }
+}
+
+void UidMap::addListener(wp<PackageInfoListener> producer) {
lock_guard<mutex> lock(mMutex); // Lock for updates
mSubscribers.insert(producer);
}
-void UidMap::removeListener(sp<PackageInfoListener> producer) {
+void UidMap::removeListener(wp<PackageInfoListener> producer) {
lock_guard<mutex> lock(mMutex); // Lock for updates
mSubscribers.erase(producer);
}
@@ -270,7 +310,7 @@
return m;
}
-size_t UidMap::getBytesUsed() {
+size_t UidMap::getBytesUsed() const {
return mBytesUsed;
}
@@ -316,7 +356,7 @@
return ret;
}
-void UidMap::printUidMap(FILE* out) {
+void UidMap::printUidMap(FILE* out) const {
lock_guard<mutex> lock(mMutex);
for (auto it : mMap) {
@@ -350,6 +390,18 @@
mLastUpdatePerConfigKey.erase(key);
}
+set<int32_t> UidMap::getAppUid(const string& package) const {
+ lock_guard<mutex> lock(mMutex);
+
+ set<int32_t> results;
+ for (const auto& pair : mMap) {
+ if (pair.second.packageName == package) {
+ results.insert(pair.first);
+ }
+ }
+ return results;
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index 487fdf9..a9aec94 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -72,14 +72,14 @@
// Helper for debugging contents of this uid map. Can be triggered with:
// adb shell cmd stats print-uid-map
- void printUidMap(FILE* out);
+ void printUidMap(FILE* out) const;
// Commands for indicating to the map that a producer should be notified if an app is updated.
// This allows the metric producer to distinguish when the same uid or app represents a
// different version of an app.
- void addListener(sp<PackageInfoListener> producer);
+ void addListener(wp<PackageInfoListener> producer);
// Remove the listener from the set of metric producers that subscribe to updates.
- void removeListener(sp<PackageInfoListener> producer);
+ void removeListener(wp<PackageInfoListener> producer);
// Informs uid map that a config is added/updated. Used for keeping mConfigKeys up to date.
void OnConfigUpdated(const ConfigKey& key);
@@ -102,7 +102,9 @@
void clearOutput();
// Get currently cached value of memory used by UID map.
- size_t getBytesUsed();
+ size_t getBytesUsed() const;
+
+ std::set<int32_t> getAppUid(const string& package) const;
private:
std::set<string> getAppNamesFromUidLocked(const int32_t& uid, bool returnNormalized) const;
@@ -117,6 +119,8 @@
UidMapping getOutput(const int64_t& timestamp, const ConfigKey& key);
+ void getListenerListCopyLocked(std::vector<wp<PackageInfoListener>>* output);
+
// TODO: Use shared_mutex for improved read-locking if a library can be found in Android.
mutable mutex mMutex;
mutable mutex mIsolatedMutex;
@@ -133,7 +137,7 @@
UidMapping mOutput;
// Metric producers that should be notified if there's an upgrade in any app.
- set<sp<PackageInfoListener>> mSubscribers;
+ set<wp<PackageInfoListener>> mSubscribers;
// Mapping of config keys we're aware of to the epoch time they last received an update. This
// lets us know it's safe to delete events older than the oldest update. The value is nanosec.
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index a30b5f8..4729f6a 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -222,6 +222,11 @@
optional int64 trigger_if_sum_gt = 6;
}
+message AllowedLogSource {
+ repeated int32 uid = 1;
+ repeated string package = 2;
+}
+
message StatsdConfig {
optional string name = 1;
@@ -240,4 +245,6 @@
repeated Predicate predicate = 8;
repeated Alert alert = 9;
+
+ optional AllowedLogSource log_source = 10;
}