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;
 }
diff --git a/cmds/statsd/tests/ConfigManager_test.cpp b/cmds/statsd/tests/ConfigManager_test.cpp
index b1924ea..3d923e2 100644
--- a/cmds/statsd/tests/ConfigManager_test.cpp
+++ b/cmds/statsd/tests/ConfigManager_test.cpp
@@ -62,8 +62,8 @@
 }
 
 TEST(ConfigManagerTest, TestFakeConfig) {
-    auto metricsManager =
-            std::make_unique<MetricsManager>(ConfigKey(0, "test"), build_fake_config(), 1000);
+    auto metricsManager = std::make_unique<MetricsManager>(ConfigKey(0, "test"),
+                                                           build_fake_config(), 1000, new UidMap());
     EXPECT_TRUE(metricsManager->isConfigValid());
 }
 
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index a5c8875..9b96bb7 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -41,7 +41,7 @@
  */
 class MockMetricsManager : public MetricsManager {
 public:
-    MockMetricsManager() : MetricsManager(ConfigKey(1, "key"), StatsdConfig(), 1000) {
+    MockMetricsManager() : MetricsManager(ConfigKey(1, "key"), StatsdConfig(), 1000, new UidMap()) {
     }
 
     MOCK_METHOD0(byteSize, size_t());
diff --git a/cmds/statsd/tools/dogfood/Android.mk b/cmds/statsd/tools/dogfood/Android.mk
index 6b0531d..7bd15d7 100644
--- a/cmds/statsd/tools/dogfood/Android.mk
+++ b/cmds/statsd/tools/dogfood/Android.mk
@@ -21,12 +21,12 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_SRC_FILES += ../../src/stats_log.proto \
                    ../../src/atoms.proto
+
 LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/../../src/
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 LOCAL_STATIC_JAVA_LIBRARIES := platformprotoslite
 
 LOCAL_PROTOC_OPTIMIZE_TYPE := lite
-LOCAL_CERTIFICATE := platform
 LOCAL_PRIVILEGED_MODULE := true
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
diff --git a/cmds/statsd/tools/dogfood/AndroidManifest.xml b/cmds/statsd/tools/dogfood/AndroidManifest.xml
index cd76c9d..7bfde40 100644
--- a/cmds/statsd/tools/dogfood/AndroidManifest.xml
+++ b/cmds/statsd/tools/dogfood/AndroidManifest.xml
@@ -18,7 +18,6 @@
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.statsd.dogfood"
-    android:sharedUserId="android.uid.system"
     android:versionCode="1"
     android:versionName="1.0" >
 
diff --git a/cmds/statsd/tools/dogfood/res/raw/statsd_baseline_config b/cmds/statsd/tools/dogfood/res/raw/statsd_baseline_config
index d5b8fed..0329992 100644
--- a/cmds/statsd/tools/dogfood/res/raw/statsd_baseline_config
+++ b/cmds/statsd/tools/dogfood/res/raw/statsd_baseline_config
Binary files differ