Merge "Fix some nits while reading the code"
diff --git a/api/current.txt b/api/current.txt
index 8925846..9741fbc 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -31570,6 +31570,7 @@
     method public final boolean postAtTime(java.lang.Runnable, long);
     method public final boolean postAtTime(java.lang.Runnable, java.lang.Object, long);
     method public final boolean postDelayed(java.lang.Runnable, long);
+    method public final boolean postDelayed(java.lang.Runnable, java.lang.Object, long);
     method public final void removeCallbacks(java.lang.Runnable);
     method public final void removeCallbacks(java.lang.Runnable, java.lang.Object);
     method public final void removeCallbacksAndMessages(java.lang.Object);
diff --git a/api/system-current.txt b/api/system-current.txt
index 3e78167..02a1953 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4368,10 +4368,10 @@
   }
 
   public final class StatsManager {
-    method public boolean addConfiguration(java.lang.String, byte[], java.lang.String, java.lang.String);
-    method public byte[] getData(java.lang.String);
+    method public boolean addConfiguration(long, byte[], java.lang.String, java.lang.String);
+    method public byte[] getData(long);
     method public byte[] getMetadata();
-    method public boolean removeConfiguration(java.lang.String);
+    method public boolean removeConfiguration(long);
   }
 
 }
diff --git a/cmds/statsd/src/HashableDimensionKey.cpp b/cmds/statsd/src/HashableDimensionKey.cpp
index 6da1243..288ebe9 100644
--- a/cmds/statsd/src/HashableDimensionKey.cpp
+++ b/cmds/statsd/src/HashableDimensionKey.cpp
@@ -21,8 +21,8 @@
 namespace os {
 namespace statsd {
 
-android::hash_t hashDimensionsValue(const DimensionsValue& value) {
-    android::hash_t hash = 0;
+android::hash_t hashDimensionsValue(int64_t seed, const DimensionsValue& value) {
+    android::hash_t hash = seed;
     hash = android::JenkinsHashMix(hash, android::hash_type(value.field()));
 
     hash = android::JenkinsHashMix(hash, android::hash_type((int)value.value_case()));
@@ -63,6 +63,10 @@
     return JenkinsHashWhiten(hash);
 }
 
+android::hash_t hashDimensionsValue(const DimensionsValue& value) {
+    return hashDimensionsValue(0, value);
+}
+
 using std::string;
 
 
diff --git a/cmds/statsd/src/HashableDimensionKey.h b/cmds/statsd/src/HashableDimensionKey.h
index 3a4ffce..85c317f 100644
--- a/cmds/statsd/src/HashableDimensionKey.h
+++ b/cmds/statsd/src/HashableDimensionKey.h
@@ -53,6 +53,7 @@
     DimensionsValue mDimensionsValue;
 };
 
+android::hash_t hashDimensionsValue(int64_t seed, const DimensionsValue& value);
 android::hash_t hashDimensionsValue(const DimensionsValue& value);
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 13f332e..9678014 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -54,7 +54,7 @@
 const int FIELD_ID_REPORTS = 2;
 // for ConfigKey
 const int FIELD_ID_UID = 1;
-const int FIELD_ID_NAME = 2;
+const int FIELD_ID_ID = 2;
 // for ConfigMetricsReport
 const int FIELD_ID_METRICS = 1;
 const int FIELD_ID_UID_MAP = 2;
@@ -157,7 +157,7 @@
         return;
     }
     report->mutable_config_key()->set_uid(key.GetUid());
-    report->mutable_config_key()->set_name(key.GetName());
+    report->mutable_config_key()->set_id(key.GetId());
     ConfigMetricsReport* configMetricsReport = report->add_reports();
     it->second->onDumpReport(dumpTimeStampNs, configMetricsReport);
     // TODO: dump uid mapping.
@@ -181,7 +181,7 @@
     // Start of ConfigKey.
     long long configKeyToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_CONFIG_KEY);
     proto.write(FIELD_TYPE_INT32 | FIELD_ID_UID, key.GetUid());
-    proto.write(FIELD_TYPE_STRING | FIELD_ID_NAME, key.GetName());
+    proto.write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)key.GetId());
     proto.end(configKeyToken);
     // End of ConfigKey.
 
@@ -278,8 +278,8 @@
         vector<uint8_t> data;
         onDumpReport(key, &data);
         // TODO: Add a guardrail to prevent accumulation of file on disk.
-        string file_name = StringPrintf("%s/%d-%s-%ld", STATS_DATA_DIR, key.GetUid(),
-                                        key.GetName().c_str(), time(nullptr));
+        string file_name = StringPrintf("%s/%d-%lld-%ld", STATS_DATA_DIR, key.GetUid(),
+                                        (long long)key.GetId(), time(nullptr));
         StorageManager::writeFile(file_name.c_str(), &data[0], data.size());
     }
 }
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index e8b0bd2..45f1ea1 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -335,7 +335,7 @@
         print_cmd_help(out);
         return UNKNOWN_ERROR;
     }
-    auto receiver = mConfigManager->GetConfigReceiver(ConfigKey(uid, name));
+    auto receiver = mConfigManager->GetConfigReceiver(ConfigKey(uid, StrToInt64(name)));
     sp<IStatsCompanionService> sc = getStatsCompanionService();
     if (sc != nullptr) {
         sc->sendBroadcast(String16(receiver.first.c_str()), String16(receiver.second.c_str()));
@@ -404,13 +404,13 @@
                 }
 
                 // Add / update the config.
-                mConfigManager->UpdateConfig(ConfigKey(uid, name), config);
+                mConfigManager->UpdateConfig(ConfigKey(uid, StrToInt64(name)), config);
             } else {
                 if (argCount == 2) {
                     cmd_remove_all_configs(out);
                 } else {
                     // Remove the config.
-                    mConfigManager->RemoveConfig(ConfigKey(uid, name));
+                    mConfigManager->RemoveConfig(ConfigKey(uid, StrToInt64(name)));
                 }
             }
 
@@ -459,7 +459,7 @@
         }
         if (good) {
             vector<uint8_t> data;
-            mProcessor->onDumpReport(ConfigKey(uid, name), &data);
+            mProcessor->onDumpReport(ConfigKey(uid, StrToInt64(name)), &data);
             // TODO: print the returned StatsLogReport to file instead of printing to logcat.
             if (proto) {
                 for (size_t i = 0; i < data.size(); i ++) {
@@ -699,12 +699,11 @@
     mProcessor->OnLogEvent(event);
 }
 
-Status StatsService::getData(const String16& key, vector<uint8_t>* output) {
+Status StatsService::getData(int64_t key, vector<uint8_t>* output) {
     IPCThreadState* ipc = IPCThreadState::self();
     VLOG("StatsService::getData with Pid %i, Uid %i", ipc->getCallingPid(), ipc->getCallingUid());
     if (checkCallingPermission(String16(kPermissionDump))) {
-        string keyStr = string(String8(key).string());
-        ConfigKey configKey(ipc->getCallingUid(), keyStr);
+        ConfigKey configKey(ipc->getCallingUid(), key);
         mProcessor->onDumpReport(configKey, output);
         return Status::ok();
     } else {
@@ -724,14 +723,13 @@
     }
 }
 
-Status StatsService::addConfiguration(const String16& key,
+Status StatsService::addConfiguration(int64_t key,
                                       const vector <uint8_t>& config,
                                       const String16& package, const String16& cls,
                                       bool* success) {
     IPCThreadState* ipc = IPCThreadState::self();
     if (checkCallingPermission(String16(kPermissionDump))) {
-        string keyString = string(String8(key).string());
-        ConfigKey configKey(ipc->getCallingUid(), keyString);
+        ConfigKey configKey(ipc->getCallingUid(), key);
         StatsdConfig cfg;
         if (!cfg.ParseFromArray(&config[0], config.size())) {
             *success = false;
@@ -748,11 +746,10 @@
     }
 }
 
-Status StatsService::removeConfiguration(const String16& key, bool* success) {
+Status StatsService::removeConfiguration(int64_t key, bool* success) {
     IPCThreadState* ipc = IPCThreadState::self();
     if (checkCallingPermission(String16(kPermissionDump))) {
-        string keyStr = string(String8(key).string());
-        mConfigManager->RemoveConfig(ConfigKey(ipc->getCallingUid(), keyStr));
+        mConfigManager->RemoveConfig(ConfigKey(ipc->getCallingUid(), key));
         *success = true;
         return Status::ok();
     } else {
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 08fcdac..c0424f3 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -77,25 +77,27 @@
     /**
      * Binder call for clients to request data for this configuration key.
      */
-    virtual Status getData(const String16& key, vector<uint8_t>* output) override;
+    virtual Status getData(int64_t key, vector<uint8_t>* output) override;
+
 
     /**
      * Binder call for clients to get metadata across all configs in statsd.
      */
     virtual Status getMetadata(vector<uint8_t>* output) override;
 
+
     /**
      * Binder call to let clients send a configuration and indicate they're interested when they
      * should requestData for this configuration.
      */
-    virtual Status addConfiguration(const String16& key, const vector <uint8_t>& config,
-                                   const String16& package, const String16& cls, bool* success)
+    virtual Status addConfiguration(int64_t key, const vector <uint8_t>& config,
+                                    const String16& package, const String16& cls, bool* success)
     override;
 
     /**
      * Binder call to allow clients to remove the specified configuration.
      */
-    virtual Status removeConfiguration(const String16& key, bool* success) override;
+    virtual Status removeConfiguration(int64_t key, bool* success) override;
 
     // TODO: public for testing since statsd doesn't run when system starts. Change to private
     // later.
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index f8a9413..9c797dc 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -205,23 +205,21 @@
     // TODO: If we had access to the bucket_size_millis, consider calling resetStorage()
     // if (mAlert.refractory_period_secs() > mNumOfPastBuckets * bucketSizeNs) { resetStorage(); }
 
-    if (mAlert.has_incidentd_details()) {
-        if (mAlert.has_name()) {
-            ALOGI("An anomaly (%s) has occurred! Informing incidentd.",
-                  mAlert.name().c_str());
+    if (!mSubscriptions.empty()) {
+        if (mAlert.has_id()) {
+            ALOGI("An anomaly (%llu) has occurred! Informing subscribers.",mAlert.id());
+            informSubscribers();
         } else {
-            // TODO: Can construct a name based on the criteria (and/or relay the criteria).
-            ALOGI("An anomaly (nameless) has occurred! Informing incidentd.");
+            ALOGI("An anomaly (with no id) has occurred! Not informing any subscribers.");
         }
-        informIncidentd();
     } else {
-        ALOGI("An anomaly has occurred! (But informing incidentd not requested.)");
+        ALOGI("An anomaly has occurred! (But no subscriber for that alert.)");
     }
 
-    StatsdStats::getInstance().noteAnomalyDeclared(mConfigKey, mAlert.name());
+    StatsdStats::getInstance().noteAnomalyDeclared(mConfigKey, mAlert.id());
 
     android::util::stats_write(android::util::ANOMALY_DETECTED, mConfigKey.GetUid(),
-                               mConfigKey.GetName().c_str(), mAlert.name().c_str());
+                               mConfigKey.GetId(), mAlert.id());
 }
 
 void AnomalyTracker::detectAndDeclareAnomaly(const uint64_t& timestampNs,
@@ -246,27 +244,46 @@
             timestampNs - mLastAnomalyTimestampNs <= mAlert.refractory_period_secs() * NS_PER_SEC;
 }
 
-void AnomalyTracker::informIncidentd() {
-    VLOG("informIncidentd called.");
-    if (!mAlert.has_incidentd_details()) {
-        ALOGE("Attempted to call incidentd without any incidentd_details.");
-        return;
-    }
-    sp<IIncidentManager> service = interface_cast<IIncidentManager>(
-            defaultServiceManager()->getService(android::String16("incident")));
-    if (service == NULL) {
-        ALOGW("Couldn't get the incident service.");
+void AnomalyTracker::informSubscribers() {
+    VLOG("informSubscribers called.");
+    if (mSubscriptions.empty()) {
+        ALOGE("Attempt to call with no subscribers.");
         return;
     }
 
-    IncidentReportArgs incidentReport;
-    const Alert::IncidentdDetails& details = mAlert.incidentd_details();
-    for (int i = 0; i < details.section_size(); i++) {
-        incidentReport.addSection(details.section(i));
+    std::set<int> incidentdSections;
+    for (const Subscription& subscription : mSubscriptions) {
+        switch (subscription.subscriber_information_case()) {
+            case Subscription::SubscriberInformationCase::kIncidentdDetails:
+                for (int i = 0; i < subscription.incidentd_details().section_size(); i++) {
+                    incidentdSections.insert(subscription.incidentd_details().section(i));
+                }
+                break;
+            case Subscription::SubscriberInformationCase::kPerfettoDetails:
+                ALOGW("Perfetto reports not implemented.");
+                break;
+            default:
+                break;
+        }
     }
-    // TODO: Pass in mAlert.name() into the addHeader?
-
-    service->reportIncident(incidentReport);
+    if (!incidentdSections.empty()) {
+        sp<IIncidentManager> service = interface_cast<IIncidentManager>(
+                defaultServiceManager()->getService(android::String16("incident")));
+        if (service != NULL) {
+            IncidentReportArgs incidentReport;
+            for (const auto section : incidentdSections) {
+                incidentReport.addSection(section);
+            }
+            int64_t alertId = mAlert.id();
+            std::vector<uint8_t> header;
+            uint8_t* src = static_cast<uint8_t*>(static_cast<void*>(&alertId));
+            header.insert(header.end(), src, src + sizeof(int64_t));
+            incidentReport.addHeader(header);
+            service->reportIncident(incidentReport);
+        } else {
+            ALOGW("Couldn't get the incident service.");
+        }
+    }
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.h b/cmds/statsd/src/anomaly/AnomalyTracker.h
index 48f0203..2d5ab86 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.h
@@ -40,6 +40,11 @@
 
     virtual ~AnomalyTracker();
 
+    // Add subscriptions that depend on this alert.
+    void addSubscription(const Subscription& subscription) {
+        mSubscriptions.push_back(subscription);
+    }
+
     // Adds a bucket.
     // Bucket index starts from 0.
     void addPastBucket(std::shared_ptr<DimToValMap> bucketValues, const int64_t& bucketNum);
@@ -97,6 +102,9 @@
     // statsd_config.proto Alert message that defines this tracker.
     const Alert mAlert;
 
+    // The subscriptions that depend on this alert.
+    std::vector<Subscription> mSubscriptions;
+
     // A reference to the Alert's config key.
     const ConfigKey& mConfigKey;
 
@@ -104,7 +112,7 @@
     // for the anomaly detection (since the current bucket is not in the past).
     int mNumOfPastBuckets;
 
-    // The exisiting bucket list.
+    // The existing bucket list.
     std::vector<shared_ptr<DimToValMap>> mPastBuckets;
 
     // Sum over all existing buckets cached in mPastBuckets.
@@ -133,8 +141,8 @@
     // Resets all bucket data. For use when all the data gets stale.
     virtual void resetStorage();
 
-    // Informs the incident service that an anomaly has occurred.
-    void informIncidentd();
+    // Informs the subscribers that an anomaly has occurred.
+    void informSubscribers();
 
     FRIEND_TEST(AnomalyTrackerTest, TestConsecutiveBuckets);
     FRIEND_TEST(AnomalyTrackerTest, TestSparseBuckets);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 1ee86f0..221a554 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -845,11 +845,11 @@
     // Uid that owns the config whose anomaly detection alert fired.
     optional int32 config_uid = 1;
 
-    // Name of the config whose anomaly detection alert fired.
-    optional string config_name = 2;
+    // Id of the config whose anomaly detection alert fired.
+    optional int64 config_id = 2;
 
-    // Name of the alert (i.e. name of the anomaly that was detected).
-    optional string alert_name = 3;
+    // Id of the alert (i.e. name of the anomaly that was detected).
+    optional int64 alert_id = 3;
 }
 
 /**
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.cpp b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
index 52b83d8..afa26f6 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.cpp
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
@@ -30,20 +30,20 @@
 using std::unordered_map;
 using std::vector;
 
-CombinationConditionTracker::CombinationConditionTracker(const string& name, const int index)
-    : ConditionTracker(name, index) {
-    VLOG("creating CombinationConditionTracker %s", mName.c_str());
+CombinationConditionTracker::CombinationConditionTracker(const int64_t& id, const int index)
+    : ConditionTracker(id, index) {
+    VLOG("creating CombinationConditionTracker %lld", (long long)mConditionId);
 }
 
 CombinationConditionTracker::~CombinationConditionTracker() {
-    VLOG("~CombinationConditionTracker() %s", mName.c_str());
+    VLOG("~CombinationConditionTracker() %lld", (long long)mConditionId);
 }
 
 bool CombinationConditionTracker::init(const vector<Predicate>& allConditionConfig,
                                        const vector<sp<ConditionTracker>>& allConditionTrackers,
-                                       const unordered_map<string, int>& conditionNameIndexMap,
+                                       const unordered_map<int64_t, int>& conditionIdIndexMap,
                                        vector<bool>& stack) {
-    VLOG("Combination predicate init() %s", mName.c_str());
+    VLOG("Combination predicate init() %lld", (long long)mConditionId);
     if (mInitialized) {
         return true;
     }
@@ -62,11 +62,11 @@
         return false;
     }
 
-    for (string child : combinationCondition.predicate()) {
-        auto it = conditionNameIndexMap.find(child);
+    for (auto child : combinationCondition.predicate()) {
+        auto it = conditionIdIndexMap.find(child);
 
-        if (it == conditionNameIndexMap.end()) {
-            ALOGW("Predicate %s not found in the config", child.c_str());
+        if (it == conditionIdIndexMap.end()) {
+            ALOGW("Predicate %lld not found in the config", (long long)child);
             return false;
         }
 
@@ -79,13 +79,13 @@
         }
 
         bool initChildSucceeded = childTracker->init(allConditionConfig, allConditionTrackers,
-                                                     conditionNameIndexMap, stack);
+                                                     conditionIdIndexMap, stack);
 
         if (!initChildSucceeded) {
-            ALOGW("Child initialization failed %s ", child.c_str());
+            ALOGW("Child initialization failed %lld ", (long long)child);
             return false;
         } else {
-            ALOGW("Child initialization success %s ", child.c_str());
+            ALOGW("Child initialization success %lld ", (long long)child);
         }
 
         mChildren.push_back(childIndex);
@@ -154,8 +154,8 @@
             }
         }
         nonSlicedConditionCache[mIndex] = ConditionState::kUnknown;
-        ALOGD("CombinationPredicate %s sliced may changed? %d", mName.c_str(),
-              conditionChangedCache[mIndex] == true);
+        ALOGD("CombinationPredicate %lld sliced may changed? %d", (long long)mConditionId,
+            conditionChangedCache[mIndex] == true);
     }
 }
 
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.h b/cmds/statsd/src/condition/CombinationConditionTracker.h
index 8942833..dfd3837 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.h
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.h
@@ -26,13 +26,13 @@
 
 class CombinationConditionTracker : public virtual ConditionTracker {
 public:
-    CombinationConditionTracker(const std::string& name, const int index);
+    CombinationConditionTracker(const int64_t& id, const int index);
 
     ~CombinationConditionTracker();
 
     bool init(const std::vector<Predicate>& allConditionConfig,
               const std::vector<sp<ConditionTracker>>& allConditionTrackers,
-              const std::unordered_map<std::string, int>& conditionNameIndexMap,
+              const std::unordered_map<int64_t, int>& conditionIdIndexMap,
               std::vector<bool>& stack) override;
 
     void evaluateCondition(const LogEvent& event,
diff --git a/cmds/statsd/src/condition/ConditionTracker.h b/cmds/statsd/src/condition/ConditionTracker.h
index 1154b6f..773860f 100644
--- a/cmds/statsd/src/condition/ConditionTracker.h
+++ b/cmds/statsd/src/condition/ConditionTracker.h
@@ -32,8 +32,8 @@
 
 class ConditionTracker : public virtual RefBase {
 public:
-    ConditionTracker(const std::string& name, const int index)
-        : mName(name),
+    ConditionTracker(const int64_t& id, const int index)
+        : mConditionId(id),
           mIndex(index),
           mInitialized(false),
           mTrackerIndex(),
@@ -42,7 +42,7 @@
 
     virtual ~ConditionTracker(){};
 
-    inline const string& getName() { return mName; }
+    inline const int64_t& getId() { return mConditionId; }
 
     // Initialize this ConditionTracker. This initialization is done recursively (DFS). It can also
     // be done in the constructor, but we do it separately because (1) easy to return a bool to
@@ -50,11 +50,11 @@
     // allConditionConfig: the list of all Predicate config from statsd_config.
     // allConditionTrackers: the list of all ConditionTrackers (this is needed because we may also
     //                       need to call init() on children conditions)
-    // conditionNameIndexMap: the mapping from condition name to its index.
+    // conditionIdIndexMap: the mapping from condition id to its index.
     // stack: a bit map to keep track which nodes have been visited on the stack in the recursion.
     virtual bool init(const std::vector<Predicate>& allConditionConfig,
                       const std::vector<sp<ConditionTracker>>& allConditionTrackers,
-                      const std::unordered_map<std::string, int>& conditionNameIndexMap,
+                      const std::unordered_map<int64_t, int>& conditionIdIndexMap,
                       std::vector<bool>& stack) = 0;
 
     // evaluate current condition given the new event.
@@ -99,9 +99,7 @@
     }
 
 protected:
-    // We don't really need the string name, but having a name here makes log messages
-    // easy to debug.
-    const std::string mName;
+    const int64_t mConditionId;
 
     // the index of this condition in the manager's condition list.
     const int mIndex;
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
index 1803cbb..2525721 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
@@ -33,17 +33,17 @@
 using std::vector;
 
 SimpleConditionTracker::SimpleConditionTracker(
-        const ConfigKey& key, const string& name, const int index,
+        const ConfigKey& key, const int64_t& id, const int index,
         const SimplePredicate& simplePredicate,
-        const unordered_map<string, int>& trackerNameIndexMap)
-    : ConditionTracker(name, index), mConfigKey(key) {
-    VLOG("creating SimpleConditionTracker %s", mName.c_str());
+        const unordered_map<int64_t, int>& trackerNameIndexMap)
+    : ConditionTracker(id, index), mConfigKey(key) {
+    VLOG("creating SimpleConditionTracker %lld", (long long)mConditionId);
     mCountNesting = simplePredicate.count_nesting();
 
     if (simplePredicate.has_start()) {
         auto pair = trackerNameIndexMap.find(simplePredicate.start());
         if (pair == trackerNameIndexMap.end()) {
-            ALOGW("Start matcher %s not found in the config", simplePredicate.start().c_str());
+            ALOGW("Start matcher %lld not found in the config", (long long)simplePredicate.start());
             return;
         }
         mStartLogMatcherIndex = pair->second;
@@ -55,7 +55,7 @@
     if (simplePredicate.has_stop()) {
         auto pair = trackerNameIndexMap.find(simplePredicate.stop());
         if (pair == trackerNameIndexMap.end()) {
-            ALOGW("Stop matcher %s not found in the config", simplePredicate.stop().c_str());
+            ALOGW("Stop matcher %lld not found in the config", (long long)simplePredicate.stop());
             return;
         }
         mStopLogMatcherIndex = pair->second;
@@ -67,7 +67,7 @@
     if (simplePredicate.has_stop_all()) {
         auto pair = trackerNameIndexMap.find(simplePredicate.stop_all());
         if (pair == trackerNameIndexMap.end()) {
-            ALOGW("Stop all matcher %s not found in the config", simplePredicate.stop().c_str());
+            ALOGW("Stop all matcher %lld found in the config", (long long)simplePredicate.stop_all());
             return;
         }
         mStopAllLogMatcherIndex = pair->second;
@@ -99,15 +99,15 @@
 
 bool SimpleConditionTracker::init(const vector<Predicate>& allConditionConfig,
                                   const vector<sp<ConditionTracker>>& allConditionTrackers,
-                                  const unordered_map<string, int>& conditionNameIndexMap,
+                                  const unordered_map<int64_t, int>& conditionIdIndexMap,
                                   vector<bool>& stack) {
     // SimpleConditionTracker does not have dependency on other conditions, thus we just return
     // if the initialization was successful.
     return mInitialized;
 }
 
-void print(map<HashableDimensionKey, int>& conditions, const string& name) {
-    VLOG("%s DUMP:", name.c_str());
+void print(map<HashableDimensionKey, int>& conditions, const int64_t& id) {
+    VLOG("%lld DUMP:", (long long)id);
     for (const auto& pair : conditions) {
         VLOG("\t%s : %d", pair.first.c_str(), pair.second);
     }
@@ -135,10 +135,11 @@
     // 1. Report the tuple count if the tuple count > soft limit
     if (mSlicedConditionState.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
         size_t newTupleCount = mSlicedConditionState.size() + 1;
-        StatsdStats::getInstance().noteConditionDimensionSize(mConfigKey, mName, newTupleCount);
+        StatsdStats::getInstance().noteConditionDimensionSize(mConfigKey, mConditionId, newTupleCount);
         // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
         if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
-            ALOGE("Predicate %s dropping data for dimension key %s", mName.c_str(), newKey.c_str());
+            ALOGE("Predicate %lld dropping data for dimension key %s",
+                (long long)mConditionId, newKey.c_str());
             return true;
         }
     }
@@ -222,13 +223,13 @@
 
     // dump all dimensions for debugging
     if (DEBUG) {
-        print(mSlicedConditionState, mName);
+        print(mSlicedConditionState, mConditionId);
     }
 
     conditionChangedCache[mIndex] = changed;
     conditionCache[mIndex] = newCondition;
 
-    VLOG("SimplePredicate %s nonSlicedChange? %d", mName.c_str(),
+    VLOG("SimplePredicate %lld nonSlicedChange? %d", (long long)mConditionId,
          conditionChangedCache[mIndex] == true);
 }
 
@@ -239,7 +240,8 @@
                                                vector<bool>& conditionChangedCache) {
     if (conditionCache[mIndex] != ConditionState::kNotEvaluated) {
         // it has been evaluated.
-        VLOG("Yes, already evaluated, %s %d", mName.c_str(), conditionCache[mIndex]);
+        VLOG("Yes, already evaluated, %lld %d",
+            (long long)mConditionId, conditionCache[mIndex]);
         return;
     }
 
@@ -320,11 +322,11 @@
         const ConditionKey& conditionParameters,
         const vector<sp<ConditionTracker>>& allConditions,
         vector<ConditionState>& conditionCache) const {
-    const auto pair = conditionParameters.find(mName);
+    const auto pair = conditionParameters.find(mConditionId);
 
     if (pair == conditionParameters.end() && mOutputDimensions.child_size() > 0) {
-        ALOGE("Predicate %s output has dimension, but it's not specified in the query!",
-              mName.c_str());
+        ALOGE("Predicate %lld output has dimension, but it's not specified in the query!",
+              (long long)mConditionId);
         conditionCache[mIndex] = mInitialValue;
         return;
     }
@@ -343,7 +345,7 @@
         }
     }
     conditionCache[mIndex] = conditionState;
-    VLOG("Predicate %s return %d", mName.c_str(), conditionCache[mIndex]);
+    VLOG("Predicate %lld return %d", (long long)mConditionId, conditionCache[mIndex]);
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.h b/cmds/statsd/src/condition/SimpleConditionTracker.h
index 5048635..815b445 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.h
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.h
@@ -29,15 +29,15 @@
 
 class SimpleConditionTracker : public virtual ConditionTracker {
 public:
-    SimpleConditionTracker(const ConfigKey& key, const std::string& name, const int index,
+    SimpleConditionTracker(const ConfigKey& key, const int64_t& id, const int index,
                            const SimplePredicate& simplePredicate,
-                           const std::unordered_map<std::string, int>& trackerNameIndexMap);
+                           const std::unordered_map<int64_t, int>& trackerNameIndexMap);
 
     ~SimpleConditionTracker();
 
     bool init(const std::vector<Predicate>& allConditionConfig,
               const std::vector<sp<ConditionTracker>>& allConditionTrackers,
-              const std::unordered_map<std::string, int>& conditionNameIndexMap,
+              const std::unordered_map<int64_t, int>& conditionIdIndexMap,
               std::vector<bool>& stack) override;
 
     void evaluateCondition(const LogEvent& event,
diff --git a/cmds/statsd/src/config/ConfigKey.cpp b/cmds/statsd/src/config/ConfigKey.cpp
index a365dc0..d791f86 100644
--- a/cmds/statsd/src/config/ConfigKey.cpp
+++ b/cmds/statsd/src/config/ConfigKey.cpp
@@ -27,10 +27,10 @@
 ConfigKey::ConfigKey() {
 }
 
-ConfigKey::ConfigKey(const ConfigKey& that) : mName(that.mName), mUid(that.mUid) {
+ConfigKey::ConfigKey(const ConfigKey& that) : mId(that.mId), mUid(that.mUid) {
 }
 
-ConfigKey::ConfigKey(int uid, const string& name) : mName(name), mUid(uid) {
+ConfigKey::ConfigKey(int uid, const int64_t& id) : mId(id), mUid(uid) {
 }
 
 ConfigKey::~ConfigKey() {
@@ -38,10 +38,21 @@
 
 string ConfigKey::ToString() const {
     ostringstream out;
-    out << '(' << mUid << ',' << mName << ')';
+    out << '(' << mUid << ',' << mId << ')';
     return out.str();
 }
 
+
+int64_t StrToInt64(const string& str) {
+    char* endp;
+    int64_t value;
+    value = strtoll(str.c_str(), &endp, 0);
+    if (endp == str.c_str() || *endp != '\0') {
+        value = 0;
+    }
+    return value;
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/config/ConfigKey.h b/cmds/statsd/src/config/ConfigKey.h
index 3489c43..3ad0eed 100644
--- a/cmds/statsd/src/config/ConfigKey.h
+++ b/cmds/statsd/src/config/ConfigKey.h
@@ -37,14 +37,14 @@
 public:
     ConfigKey();
     explicit ConfigKey(const ConfigKey& that);
-    ConfigKey(int uid, const string& name);
+    ConfigKey(int uid, const int64_t& id);
     ~ConfigKey();
 
     inline int GetUid() const {
         return mUid;
     }
-    inline const string& GetName() const {
-        return mName;
+    inline const int64_t& GetId() const {
+        return mId;
     }
 
     inline bool operator<(const ConfigKey& that) const {
@@ -54,17 +54,17 @@
         if (mUid > that.mUid) {
             return false;
         }
-        return mName < that.mName;
+        return mId < that.mId;
     };
 
     inline bool operator==(const ConfigKey& that) const {
-        return mUid == that.mUid && mName == that.mName;
+        return mUid == that.mUid && mId == that.mId;
     };
 
     string ToString() const;
 
 private:
-    string mName;
+    int64_t mId;
     int mUid;
 };
 
@@ -72,6 +72,8 @@
     return os << config.ToString();
 }
 
+int64_t StrToInt64(const string& str);
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
@@ -87,7 +89,7 @@
 template <>
 struct hash<ConfigKey> {
     std::size_t operator()(const ConfigKey& key) const {
-        return (7 * key.GetUid()) ^ ((hash<string>()(key.GetName())));
+        return (7 * key.GetUid()) ^ ((hash<long long>()(key.GetId())));
     }
 };
 
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index addc111..5cf8b9b 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -103,7 +103,7 @@
 }
 
 void ConfigManager::remove_saved_configs(const ConfigKey& key) {
-    string prefix = StringPrintf("%d-%s", key.GetUid(), key.GetName().c_str());
+    string prefix = StringPrintf("%d-%lld", key.GetUid(), (long long)key.GetId());
     StorageManager::deletePrefixedFiles(STATS_SERVICE_DIR, prefix.c_str());
 }
 
@@ -173,7 +173,7 @@
     fprintf(out, "CONFIGURATIONS (%d)\n", (int)mConfigs.size());
     fprintf(out, "     uid name\n");
     for (const auto& key : mConfigs) {
-        fprintf(out, "  %6d %s\n", key.GetUid(), key.GetName().c_str());
+        fprintf(out, "  %6d %lld\n", key.GetUid(), (long long)key.GetId());
         auto receiverIt = mConfigReceivers.find(key);
         if (receiverIt != mConfigReceivers.end()) {
             fprintf(out, "    -> received by %s, %s\n", receiverIt->second.first.c_str(),
@@ -189,8 +189,8 @@
     remove_saved_configs(key);
 
     // Then we save the latest config.
-    string file_name = StringPrintf("%s/%d-%s-%ld", STATS_SERVICE_DIR, key.GetUid(),
-                                    key.GetName().c_str(), time(nullptr));
+    string file_name = StringPrintf("%s/%d-%lld-%ld", STATS_SERVICE_DIR, key.GetUid(),
+                                    (long long)key.GetId(), time(nullptr));
     const int numBytes = config.ByteSize();
     vector<uint8_t> buffer(numBytes);
     config.SerializeToArray(&buffer[0], numBytes);
@@ -200,7 +200,7 @@
 StatsdConfig build_fake_config() {
     // HACK: Hard code a test metric for counting screen on events...
     StatsdConfig config;
-    config.set_name("CONFIG_12345");
+    config.set_id(12345);
 
     int WAKE_LOCK_TAG_ID = 1111;  // put a fake id here to make testing easier.
     int WAKE_LOCK_UID_KEY_ID = 1;
@@ -232,14 +232,14 @@
 
     // Count Screen ON events.
     CountMetric* metric = config.add_count_metric();
-    metric->set_name("METRIC_1");
-    metric->set_what("SCREEN_TURNED_ON");
+    metric->set_id(1);  // METRIC_1
+    metric->set_what(102);  //  "SCREEN_TURNED_ON"
     metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
 
     // Anomaly threshold for screen-on count.
     // TODO(b/70627390): Uncomment once the bug is fixed.
     /*Alert* alert = config.add_alert();
-    alert->set_name("ALERT_1");
+    alert->set_id("ALERT_1");
     alert->set_metric_name("METRIC_1");
     alert->set_number_of_buckets(6);
     alert->set_trigger_if_sum_gt(10);
@@ -256,8 +256,8 @@
 
     // Count process state changes, slice by uid.
     metric = config.add_count_metric();
-    metric->set_name("METRIC_2");
-    metric->set_what("PROCESS_STATE_CHANGE");
+    metric->set_id(2);  // "METRIC_2"
+    metric->set_what(104);
     metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
     FieldMatcher* dimensions = metric->mutable_dimensions();
     dimensions->set_field(UID_PROCESS_STATE_TAG_ID);
@@ -267,7 +267,7 @@
     // TODO(b/70627390): Uncomment once the bug is fixed.
     /*
     alert = config.add_alert();
-    alert->set_name("ALERT_2");
+    alert->set_id("ALERT_2");
     alert->set_metric_name("METRIC_2");
     alert->set_number_of_buckets(4);
     alert->set_trigger_if_sum_gt(30);
@@ -278,28 +278,28 @@
 
     // Count process state changes, slice by uid, while SCREEN_IS_OFF
     metric = config.add_count_metric();
-    metric->set_name("METRIC_3");
-    metric->set_what("PROCESS_STATE_CHANGE");
+    metric->set_id(3);
+    metric->set_what(104);
     metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
 
     dimensions = metric->mutable_dimensions();
     dimensions->set_field(UID_PROCESS_STATE_TAG_ID);
     dimensions->add_child()->set_field(UID_PROCESS_STATE_UID_KEY);
-    metric->set_condition("SCREEN_IS_OFF");
+    metric->set_condition(202);
 
     // Count wake lock, slice by uid, while SCREEN_IS_ON and app in background
     metric = config.add_count_metric();
-    metric->set_name("METRIC_4");
-    metric->set_what("APP_GET_WL");
+    metric->set_id(4);
+    metric->set_what(107);
     metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
     dimensions = metric->mutable_dimensions();
     dimensions->set_field(WAKE_LOCK_TAG_ID);
     dimensions->add_child()->set_field(WAKE_LOCK_UID_KEY_ID);
 
 
-    metric->set_condition("APP_IS_BACKGROUND_AND_SCREEN_ON");
+    metric->set_condition(204);
     MetricConditionLink* link = metric->add_links();
-    link->set_condition("APP_IS_BACKGROUND");
+    link->set_condition(203);
     link->mutable_dimensions_in_what()->set_field(WAKE_LOCK_TAG_ID);
     link->mutable_dimensions_in_what()->add_child()->set_field(WAKE_LOCK_UID_KEY_ID);
     link->mutable_dimensions_in_condition()->set_field(APP_USAGE_TAG_ID);
@@ -307,16 +307,16 @@
 
     // Duration of an app holding any wl, while screen on and app in background, slice by uid
     DurationMetric* durationMetric = config.add_duration_metric();
-    durationMetric->set_name("METRIC_5");
+    durationMetric->set_id(5);
     durationMetric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
     durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
     dimensions = durationMetric->mutable_dimensions();
     dimensions->set_field(WAKE_LOCK_TAG_ID);
     dimensions->add_child()->set_field(WAKE_LOCK_UID_KEY_ID);
-    durationMetric->set_what("WL_HELD_PER_APP_PER_NAME");
-    durationMetric->set_condition("APP_IS_BACKGROUND_AND_SCREEN_ON");
+    durationMetric->set_what(205);
+    durationMetric->set_condition(204);
     link = durationMetric->add_links();
-    link->set_condition("APP_IS_BACKGROUND");
+    link->set_condition(203);
     link->mutable_dimensions_in_what()->set_field(WAKE_LOCK_TAG_ID);
     link->mutable_dimensions_in_what()->add_child()->set_field(WAKE_LOCK_UID_KEY_ID);
     link->mutable_dimensions_in_condition()->set_field(APP_USAGE_TAG_ID);
@@ -324,16 +324,16 @@
 
     // max Duration of an app holding any wl, while screen on and app in background, slice by uid
     durationMetric = config.add_duration_metric();
-    durationMetric->set_name("METRIC_6");
+    durationMetric->set_id(6);
     durationMetric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
     durationMetric->set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE);
     dimensions = durationMetric->mutable_dimensions();
     dimensions->set_field(WAKE_LOCK_TAG_ID);
     dimensions->add_child()->set_field(WAKE_LOCK_UID_KEY_ID);
-    durationMetric->set_what("WL_HELD_PER_APP_PER_NAME");
-    durationMetric->set_condition("APP_IS_BACKGROUND_AND_SCREEN_ON");
+    durationMetric->set_what(205);
+    durationMetric->set_condition(204);
     link = durationMetric->add_links();
-    link->set_condition("APP_IS_BACKGROUND");
+    link->set_condition(203);
     link->mutable_dimensions_in_what()->set_field(WAKE_LOCK_TAG_ID);
     link->mutable_dimensions_in_what()->add_child()->set_field(WAKE_LOCK_UID_KEY_ID);
     link->mutable_dimensions_in_condition()->set_field(APP_USAGE_TAG_ID);
@@ -341,13 +341,13 @@
 
     // Duration of an app holding any wl, while screen on and app in background
     durationMetric = config.add_duration_metric();
-    durationMetric->set_name("METRIC_7");
+    durationMetric->set_id(7);
     durationMetric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
     durationMetric->set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE);
-    durationMetric->set_what("WL_HELD_PER_APP_PER_NAME");
-    durationMetric->set_condition("APP_IS_BACKGROUND_AND_SCREEN_ON");
+    durationMetric->set_what(205);
+    durationMetric->set_condition(204);
     link = durationMetric->add_links();
-    link->set_condition("APP_IS_BACKGROUND");
+    link->set_condition(203);
     link->mutable_dimensions_in_what()->set_field(WAKE_LOCK_TAG_ID);
     link->mutable_dimensions_in_what()->add_child()->set_field(WAKE_LOCK_UID_KEY_ID);
     link->mutable_dimensions_in_condition()->set_field(APP_USAGE_TAG_ID);
@@ -356,17 +356,17 @@
 
     // Duration of screen on time.
     durationMetric = config.add_duration_metric();
-    durationMetric->set_name("METRIC_8");
+    durationMetric->set_id(8);
     durationMetric->mutable_bucket()->set_bucket_size_millis(10 * 1000L);
     durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
-    durationMetric->set_what("SCREEN_IS_ON");
+    durationMetric->set_what(201);
 
     // Anomaly threshold for background count.
     // TODO(b/70627390): Uncomment once the bug is fixed.
     /*
     alert = config.add_alert();
-    alert->set_name("ALERT_8");
-    alert->set_metric_name("METRIC_8");
+    alert->set_id(308);
+    alert->set_metric_id(8);
     alert->set_number_of_buckets(4);
     alert->set_trigger_if_sum_gt(2000000000); // 2 seconds
     alert->set_refractory_period_secs(120);
@@ -375,10 +375,10 @@
 
     // Value metric to count KERNEL_WAKELOCK when screen turned on
     ValueMetric* valueMetric = config.add_value_metric();
-    valueMetric->set_name("METRIC_6");
-    valueMetric->set_what("KERNEL_WAKELOCK");
+    valueMetric->set_id(11);
+    valueMetric->set_what(109);
     valueMetric->set_value_field(KERNEL_WAKELOCK_COUNT_KEY);
-    valueMetric->set_condition("SCREEN_IS_ON");
+    valueMetric->set_condition(201);
     dimensions = valueMetric->mutable_dimensions();
     dimensions->set_field(KERNEL_WAKELOCK_TAG_ID);
     dimensions->add_child()->set_field(KERNEL_WAKELOCK_NAME_KEY);
@@ -387,13 +387,13 @@
 
     // Add an EventMetric to log process state change events.
     EventMetric* eventMetric = config.add_event_metric();
-    eventMetric->set_name("METRIC_9");
-    eventMetric->set_what("SCREEN_TURNED_ON");
+    eventMetric->set_id(9);
+    eventMetric->set_what(102); // "SCREEN_TURNED_ON"
 
     // Add an GaugeMetric.
     GaugeMetric* gaugeMetric = config.add_gauge_metric();
-    gaugeMetric->set_name("METRIC_10");
-    gaugeMetric->set_what("DEVICE_TEMPERATURE");
+    gaugeMetric->set_id(10);
+    gaugeMetric->set_what(101);
     auto gaugeFieldMatcher = gaugeMetric->mutable_gauge_fields_filter()->mutable_fields();
     gaugeFieldMatcher->set_field(DEVICE_TEMPERATURE_TAG_ID);
     gaugeFieldMatcher->add_child()->set_field(DEVICE_TEMPERATURE_KEY);
@@ -401,12 +401,12 @@
 
     // Event matchers.
     AtomMatcher* temperatureAtomMatcher = config.add_atom_matcher();
-    temperatureAtomMatcher->set_name("DEVICE_TEMPERATURE");
+    temperatureAtomMatcher->set_id(101);  // "DEVICE_TEMPERATURE"
     temperatureAtomMatcher->mutable_simple_atom_matcher()->set_atom_id(
         DEVICE_TEMPERATURE_TAG_ID);
 
     AtomMatcher* eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_name("SCREEN_TURNED_ON");
+    eventMatcher->set_id(102);  // "SCREEN_TURNED_ON"
     SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
     simpleAtomMatcher->set_atom_id(SCREEN_EVENT_TAG_ID);
     FieldValueMatcher* fieldValueMatcher = simpleAtomMatcher->add_field_value_matcher();
@@ -414,7 +414,7 @@
     fieldValueMatcher->set_eq_int(SCREEN_EVENT_ON_VALUE);
 
     eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_name("SCREEN_TURNED_OFF");
+    eventMatcher->set_id(103);  // "SCREEN_TURNED_OFF"
     simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
     simpleAtomMatcher->set_atom_id(SCREEN_EVENT_TAG_ID);
     fieldValueMatcher = simpleAtomMatcher->add_field_value_matcher();
@@ -422,12 +422,12 @@
     fieldValueMatcher->set_eq_int(SCREEN_EVENT_OFF_VALUE);
 
     eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_name("PROCESS_STATE_CHANGE");
+    eventMatcher->set_id(104);  // "PROCESS_STATE_CHANGE"
     simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
     simpleAtomMatcher->set_atom_id(UID_PROCESS_STATE_TAG_ID);
 
     eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_name("APP_GOES_BACKGROUND");
+    eventMatcher->set_id(105);  // "APP_GOES_BACKGROUND"
     simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
     simpleAtomMatcher->set_atom_id(APP_USAGE_TAG_ID);
     fieldValueMatcher = simpleAtomMatcher->add_field_value_matcher();
@@ -435,7 +435,7 @@
     fieldValueMatcher->set_eq_int(APP_USAGE_BACKGROUND);
 
     eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_name("APP_GOES_FOREGROUND");
+    eventMatcher->set_id(106);  // "APP_GOES_FOREGROUND"
     simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
     simpleAtomMatcher->set_atom_id(APP_USAGE_TAG_ID);
     fieldValueMatcher = simpleAtomMatcher->add_field_value_matcher();
@@ -443,7 +443,7 @@
     fieldValueMatcher->set_eq_int(APP_USAGE_FOREGROUND);
 
     eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_name("APP_GET_WL");
+    eventMatcher->set_id(107);  // "APP_GET_WL"
     simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
     simpleAtomMatcher->set_atom_id(WAKE_LOCK_TAG_ID);
     fieldValueMatcher = simpleAtomMatcher->add_field_value_matcher();
@@ -451,7 +451,7 @@
     fieldValueMatcher->set_eq_int(WAKE_LOCK_ACQUIRE_VALUE);
 
     eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_name("APP_RELEASE_WL");
+    eventMatcher->set_id(108);  //"APP_RELEASE_WL"
     simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
     simpleAtomMatcher->set_atom_id(WAKE_LOCK_TAG_ID);
     fieldValueMatcher = simpleAtomMatcher->add_field_value_matcher();
@@ -460,47 +460,47 @@
 
     // pulled events
     eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_name("KERNEL_WAKELOCK");
+    eventMatcher->set_id(109);  // "KERNEL_WAKELOCK"
     simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
     simpleAtomMatcher->set_atom_id(KERNEL_WAKELOCK_TAG_ID);
 
     // Predicates.............
     Predicate* predicate = config.add_predicate();
-    predicate->set_name("SCREEN_IS_ON");
+    predicate->set_id(201);  // "SCREEN_IS_ON"
     SimplePredicate* simplePredicate = predicate->mutable_simple_predicate();
-    simplePredicate->set_start("SCREEN_TURNED_ON");
-    simplePredicate->set_stop("SCREEN_TURNED_OFF");
+    simplePredicate->set_start(102);  // "SCREEN_TURNED_ON"
+    simplePredicate->set_stop(103);
     simplePredicate->set_count_nesting(false);
 
     predicate = config.add_predicate();
-    predicate->set_name("SCREEN_IS_OFF");
+    predicate->set_id(202);  // "SCREEN_IS_OFF"
     simplePredicate = predicate->mutable_simple_predicate();
-    simplePredicate->set_start("SCREEN_TURNED_OFF");
-    simplePredicate->set_stop("SCREEN_TURNED_ON");
+    simplePredicate->set_start(103);
+    simplePredicate->set_stop(102);  // "SCREEN_TURNED_ON"
     simplePredicate->set_count_nesting(false);
 
     predicate = config.add_predicate();
-    predicate->set_name("APP_IS_BACKGROUND");
+    predicate->set_id(203);  // "APP_IS_BACKGROUND"
     simplePredicate = predicate->mutable_simple_predicate();
-    simplePredicate->set_start("APP_GOES_BACKGROUND");
-    simplePredicate->set_stop("APP_GOES_FOREGROUND");
+    simplePredicate->set_start(105);
+    simplePredicate->set_stop(106);
     FieldMatcher* predicate_dimension1 = simplePredicate->mutable_dimensions();
     predicate_dimension1->set_field(APP_USAGE_TAG_ID);
     predicate_dimension1->add_child()->set_field(APP_USAGE_UID_KEY_ID);
     simplePredicate->set_count_nesting(false);
 
     predicate = config.add_predicate();
-    predicate->set_name("APP_IS_BACKGROUND_AND_SCREEN_ON");
+    predicate->set_id(204);  // "APP_IS_BACKGROUND_AND_SCREEN_ON"
     Predicate_Combination* combination_predicate = predicate->mutable_combination();
     combination_predicate->set_operation(LogicalOperation::AND);
-    combination_predicate->add_predicate("APP_IS_BACKGROUND");
-    combination_predicate->add_predicate("SCREEN_IS_ON");
+    combination_predicate->add_predicate(203);
+    combination_predicate->add_predicate(201);
 
     predicate = config.add_predicate();
-    predicate->set_name("WL_HELD_PER_APP_PER_NAME");
+    predicate->set_id(205);  // "WL_HELD_PER_APP_PER_NAME"
     simplePredicate = predicate->mutable_simple_predicate();
-    simplePredicate->set_start("APP_GET_WL");
-    simplePredicate->set_stop("APP_RELEASE_WL");
+    simplePredicate->set_start(107);
+    simplePredicate->set_stop(108);
     FieldMatcher* predicate_dimension = simplePredicate->mutable_dimensions();
     predicate_dimension1->set_field(WAKE_LOCK_TAG_ID);
     predicate_dimension->add_child()->set_field(WAKE_LOCK_UID_KEY_ID);
@@ -508,10 +508,10 @@
     simplePredicate->set_count_nesting(true);
 
     predicate = config.add_predicate();
-    predicate->set_name("WL_HELD_PER_APP");
+    predicate->set_id(206);  // "WL_HELD_PER_APP"
     simplePredicate = predicate->mutable_simple_predicate();
-    simplePredicate->set_start("APP_GET_WL");
-    simplePredicate->set_stop("APP_RELEASE_WL");
+    simplePredicate->set_start(107);
+    simplePredicate->set_stop(108);
     simplePredicate->set_initial_value(SimplePredicate_InitialValue_FALSE);
     predicate_dimension = simplePredicate->mutable_dimensions();
     predicate_dimension->set_field(WAKE_LOCK_TAG_ID);
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index bf277f0..33927aa 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -80,7 +80,7 @@
 
     StatsdStatsReport_ConfigStats configStats;
     configStats.set_uid(key.GetUid());
-    configStats.set_name(key.GetName());
+    configStats.set_id(key.GetId());
     configStats.set_creation_time_sec(nowTimeSec);
     configStats.set_metric_count(metricsCount);
     configStats.set_condition_count(conditionsCount);
@@ -196,34 +196,34 @@
     mUidMapStats.set_bytes_used(bytes);
 }
 
-void StatsdStats::noteConditionDimensionSize(const ConfigKey& key, const string& name, int size) {
+void StatsdStats::noteConditionDimensionSize(const ConfigKey& key, const int64_t& id, int size) {
     lock_guard<std::mutex> lock(mLock);
     // if name doesn't exist before, it will create the key with count 0.
     auto& conditionSizeMap = mConditionStats[key];
-    if (size > conditionSizeMap[name]) {
-        conditionSizeMap[name] = size;
+    if (size > conditionSizeMap[id]) {
+        conditionSizeMap[id] = size;
     }
 }
 
-void StatsdStats::noteMetricDimensionSize(const ConfigKey& key, const string& name, int size) {
+void StatsdStats::noteMetricDimensionSize(const ConfigKey& key, const int64_t& id, int size) {
     lock_guard<std::mutex> lock(mLock);
     // if name doesn't exist before, it will create the key with count 0.
     auto& metricsDimensionMap = mMetricsStats[key];
-    if (size > metricsDimensionMap[name]) {
-        metricsDimensionMap[name] = size;
+    if (size > metricsDimensionMap[id]) {
+        metricsDimensionMap[id] = size;
     }
 }
 
-void StatsdStats::noteMatcherMatched(const ConfigKey& key, const string& name) {
+void StatsdStats::noteMatcherMatched(const ConfigKey& key, const int64_t& id) {
     lock_guard<std::mutex> lock(mLock);
     auto& matcherStats = mMatcherStats[key];
-    matcherStats[name]++;
+    matcherStats[id]++;
 }
 
-void StatsdStats::noteAnomalyDeclared(const ConfigKey& key, const string& name) {
+void StatsdStats::noteAnomalyDeclared(const ConfigKey& key, const int64_t& id) {
     lock_guard<std::mutex> lock(mLock);
     auto& alertStats = mAlertStats[key];
-    alertStats[name]++;
+    alertStats[id]++;
 }
 
 void StatsdStats::noteRegisteredAnomalyAlarmChanged() {
@@ -279,9 +279,10 @@
         const auto& matcherStats = mMatcherStats[key];
         for (const auto& stats : matcherStats) {
             auto output = configStats.add_matcher_stats();
-            output->set_name(stats.first);
+            output->set_id(stats.first);
             output->set_matched_times(stats.second);
-            VLOG("matcher %s matched %d times", stats.first.c_str(), stats.second);
+            VLOG("matcher %lld matched %d times",
+                (long long)stats.first, stats.second);
         }
     }
     // Add condition stats
@@ -289,9 +290,10 @@
         const auto& conditionStats = mConditionStats[key];
         for (const auto& stats : conditionStats) {
             auto output = configStats.add_condition_stats();
-            output->set_name(stats.first);
+            output->set_id(stats.first);
             output->set_max_tuple_counts(stats.second);
-            VLOG("condition %s max output tuple size %d", stats.first.c_str(), stats.second);
+            VLOG("condition %lld max output tuple size %d",
+                (long long)stats.first, stats.second);
         }
     }
     // Add metrics stats
@@ -299,9 +301,10 @@
         const auto& conditionStats = mMetricsStats[key];
         for (const auto& stats : conditionStats) {
             auto output = configStats.add_metric_stats();
-            output->set_name(stats.first);
+            output->set_id(stats.first);
             output->set_max_tuple_counts(stats.second);
-            VLOG("metrics %s max output tuple size %d", stats.first.c_str(), stats.second);
+            VLOG("metrics %lld max output tuple size %d",
+                (long long)stats.first, stats.second);
         }
     }
     // Add anomaly detection alert stats
@@ -309,9 +312,9 @@
         const auto& alertStats = mAlertStats[key];
         for (const auto& stats : alertStats) {
             auto output = configStats.add_alert_stats();
-            output->set_name(stats.first);
+            output->set_id(stats.first);
             output->set_alerted_times(stats.second);
-            VLOG("alert %s declared %d times", stats.first.c_str(), stats.second);
+            VLOG("alert %lld declared %d times", (long long)stats.first, stats.second);
         }
     }
 }
@@ -343,9 +346,9 @@
         // in production.
         if (DEBUG) {
             VLOG("*****ICEBOX*****");
-            VLOG("Config {%d-%s}: creation=%d, deletion=%d, #metric=%d, #condition=%d, "
+            VLOG("Config {%d-%lld}: creation=%d, deletion=%d, #metric=%d, #condition=%d, "
                  "#matcher=%d, #alert=%d,  #valid=%d",
-                 configStats.uid(), configStats.name().c_str(), configStats.creation_time_sec(),
+                 configStats.uid(), (long long)configStats.id(), configStats.creation_time_sec(),
                  configStats.deletion_time_sec(), configStats.metric_count(),
                  configStats.condition_count(), configStats.matcher_count(),
                  configStats.alert_count(), configStats.is_valid());
@@ -364,9 +367,9 @@
         auto& configStats = pair.second;
         if (DEBUG) {
             VLOG("********Active Configs***********");
-            VLOG("Config {%d-%s}: creation=%d, deletion=%d, #metric=%d, #condition=%d, "
+            VLOG("Config {%d-%lld}: creation=%d, deletion=%d, #metric=%d, #condition=%d, "
                  "#matcher=%d, #alert=%d,  #valid=%d",
-                 configStats.uid(), configStats.name().c_str(), configStats.creation_time_sec(),
+                 configStats.uid(), (long long)configStats.id(), configStats.creation_time_sec(),
                  configStats.deletion_time_sec(), configStats.metric_count(),
                  configStats.condition_count(), configStats.matcher_count(),
                  configStats.alert_count(), configStats.is_valid());
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index cb868e1f..45aa192 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -99,10 +99,10 @@
      * count > kDimensionKeySizeSoftLimit.
      *
      * [key]: The config key that this condition belongs to.
-     * [name]: The name of the condition.
+     * [id]: The id of the condition.
      * [size]: The output tuple size.
      */
-    void noteConditionDimensionSize(const ConfigKey& key, const std::string& name, int size);
+    void noteConditionDimensionSize(const ConfigKey& key, const int64_t& id, int size);
 
     /**
      * Report the size of output tuple of a metric.
@@ -111,26 +111,26 @@
      * count > kDimensionKeySizeSoftLimit.
      *
      * [key]: The config key that this metric belongs to.
-     * [name]: The name of the metric.
+     * [id]: The id of the metric.
      * [size]: The output tuple size.
      */
-    void noteMetricDimensionSize(const ConfigKey& key, const std::string& name, int size);
+    void noteMetricDimensionSize(const ConfigKey& key, const int64_t& id, int size);
 
     /**
      * Report a matcher has been matched.
      *
      * [key]: The config key that this matcher belongs to.
-     * [name]: The name of the matcher.
+     * [id]: The id of the matcher.
      */
-    void noteMatcherMatched(const ConfigKey& key, const std::string& name);
+    void noteMatcherMatched(const ConfigKey& key, const int64_t& id);
 
     /**
      * Report that an anomaly detection alert has been declared.
      *
      * [key]: The config key that this alert belongs to.
-     * [name]: The name of the alert.
+     * [id]: The id of the alert.
      */
-    void noteAnomalyDeclared(const ConfigKey& key, const std::string& name);
+    void noteAnomalyDeclared(const ConfigKey& key, const int64_t& id);
 
     /**
      * Report an atom event has been logged.
@@ -187,12 +187,12 @@
     // Stores the number of output tuple of condition trackers when it's bigger than
     // kDimensionKeySizeSoftLimit. When you see the number is kDimensionKeySizeHardLimit +1,
     // it means some data has been dropped.
-    std::map<const ConfigKey, std::map<const std::string, int>> mConditionStats;
+    std::map<const ConfigKey, std::map<const int64_t, int>> mConditionStats;
 
     // Stores the number of output tuple of metric producers when it's bigger than
     // kDimensionKeySizeSoftLimit. When you see the number is kDimensionKeySizeHardLimit +1,
     // it means some data has been dropped.
-    std::map<const ConfigKey, std::map<const std::string, int>> mMetricsStats;
+    std::map<const ConfigKey, std::map<const int64_t, int>> mMetricsStats;
 
     // Stores the number of times a pushed atom is logged.
     // The size of the vector is the largest pushed atom id in atoms.proto + 1. Atoms
@@ -206,10 +206,10 @@
 
     // Stores the number of times an anomaly detection alert has been declared
     // (per config, per alert name).
-    std::map<const ConfigKey, std::map<const std::string, int>> mAlertStats;
+    std::map<const ConfigKey, std::map<const int64_t, int>> mAlertStats;
 
     // Stores how many times a matcher have been matched.
-    std::map<const ConfigKey, std::map<const std::string, int>> mMatcherStats;
+    std::map<const ConfigKey, std::map<const int64_t, int>> mMatcherStats;
 
     void noteConfigRemovedInternalLocked(const ConfigKey& key);
 
diff --git a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp
index bd5e3cb..15c067e 100644
--- a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp
+++ b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp
@@ -29,8 +29,8 @@
 using std::unordered_map;
 using std::vector;
 
-CombinationLogMatchingTracker::CombinationLogMatchingTracker(const string& name, const int index)
-    : LogMatchingTracker(name, index) {
+CombinationLogMatchingTracker::CombinationLogMatchingTracker(const int64_t& id, const int index)
+    : LogMatchingTracker(id, index) {
 }
 
 CombinationLogMatchingTracker::~CombinationLogMatchingTracker() {
@@ -38,7 +38,7 @@
 
 bool CombinationLogMatchingTracker::init(const vector<AtomMatcher>& allLogMatchers,
                                          const vector<sp<LogMatchingTracker>>& allTrackers,
-                                         const unordered_map<string, int>& matcherMap,
+                                         const unordered_map<int64_t, int>& matcherMap,
                                          vector<bool>& stack) {
     if (mInitialized) {
         return true;
@@ -60,10 +60,10 @@
         return false;
     }
 
-    for (const string& child : matcher.matcher()) {
+    for (const auto& child : matcher.matcher()) {
         auto pair = matcherMap.find(child);
         if (pair == matcherMap.end()) {
-            ALOGW("Matcher %s not found in the config", child.c_str());
+            ALOGW("Matcher %lld not found in the config", (long long)child);
             return false;
         }
 
@@ -76,7 +76,7 @@
         }
 
         if (!allTrackers[childIndex]->init(allLogMatchers, allTrackers, matcherMap, stack)) {
-            ALOGW("child matcher init failed %s", child.c_str());
+            ALOGW("child matcher init failed %lld", (long long)child);
             return false;
         }
 
diff --git a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h
index 81f6e80..2a3f08d 100644
--- a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h
+++ b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h
@@ -31,11 +31,11 @@
 // Represents a AtomMatcher_Combination in the StatsdConfig.
 class CombinationLogMatchingTracker : public virtual LogMatchingTracker {
 public:
-    CombinationLogMatchingTracker(const std::string& name, const int index);
+    CombinationLogMatchingTracker(const int64_t& id, const int index);
 
     bool init(const std::vector<AtomMatcher>& allLogMatchers,
               const std::vector<sp<LogMatchingTracker>>& allTrackers,
-              const std::unordered_map<std::string, int>& matcherMap,
+              const std::unordered_map<int64_t, int>& matcherMap,
               std::vector<bool>& stack);
 
     ~CombinationLogMatchingTracker();
diff --git a/cmds/statsd/src/matchers/LogMatchingTracker.h b/cmds/statsd/src/matchers/LogMatchingTracker.h
index 567944f..4f30a04 100644
--- a/cmds/statsd/src/matchers/LogMatchingTracker.h
+++ b/cmds/statsd/src/matchers/LogMatchingTracker.h
@@ -33,8 +33,8 @@
 
 class LogMatchingTracker : public virtual RefBase {
 public:
-    LogMatchingTracker(const std::string& name, const int index)
-        : mName(name), mIndex(index), mInitialized(false){};
+    LogMatchingTracker(const int64_t& id, const int index)
+        : mId(id), mIndex(index), mInitialized(false){};
 
     virtual ~LogMatchingTracker(){};
 
@@ -48,7 +48,7 @@
     //        circle dependency.
     virtual bool init(const std::vector<AtomMatcher>& allLogMatchers,
                       const std::vector<sp<LogMatchingTracker>>& allTrackers,
-                      const std::unordered_map<std::string, int>& matcherMap,
+                      const std::unordered_map<int64_t, int>& matcherMap,
                       std::vector<bool>& stack) = 0;
 
     // Called when a log event comes.
@@ -69,13 +69,13 @@
         return mAtomIds;
     }
 
-    const std::string& getName() const {
-        return mName;
+    const int64_t& getId() const {
+        return mId;
     }
 
 protected:
     // Name of this matching. We don't really need the name, but it makes log message easy to debug.
-    const std::string mName;
+    const int64_t mId;
 
     // Index of this LogMatchingTracker in MetricsManager's container.
     const int mIndex;
diff --git a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp
index 91ef034..31b3db5 100644
--- a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp
+++ b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp
@@ -29,10 +29,10 @@
 using std::vector;
 
 
-SimpleLogMatchingTracker::SimpleLogMatchingTracker(const string& name, const int index,
+SimpleLogMatchingTracker::SimpleLogMatchingTracker(const int64_t& id, const int index,
                                                    const SimpleAtomMatcher& matcher,
                                                    const UidMap& uidMap)
-    : LogMatchingTracker(name, index), mMatcher(matcher), mUidMap(uidMap) {
+    : LogMatchingTracker(id, index), mMatcher(matcher), mUidMap(uidMap) {
     if (!matcher.has_atom_id()) {
         mInitialized = false;
     } else {
@@ -46,7 +46,7 @@
 
 bool SimpleLogMatchingTracker::init(const vector<AtomMatcher>& allLogMatchers,
                                     const vector<sp<LogMatchingTracker>>& allTrackers,
-                                    const unordered_map<string, int>& matcherMap,
+                                    const unordered_map<int64_t, int>& matcherMap,
                                     vector<bool>& stack) {
     // no need to do anything.
     return mInitialized;
@@ -56,7 +56,7 @@
                                           const vector<sp<LogMatchingTracker>>& allTrackers,
                                           vector<MatchingState>& matcherResults) {
     if (matcherResults[mIndex] != MatchingState::kNotComputed) {
-        VLOG("Matcher %s already evaluated ", mName.c_str());
+        VLOG("Matcher %lld already evaluated ", (long long)mId);
         return;
     }
 
@@ -67,7 +67,7 @@
 
     bool matched = matchesSimple(mUidMap, mMatcher, event);
     matcherResults[mIndex] = matched ? MatchingState::kMatched : MatchingState::kNotMatched;
-    VLOG("Stats SimpleLogMatcher %s matched? %d", mName.c_str(), matched);
+    VLOG("Stats SimpleLogMatcher %lld matched? %d", (long long)mId, matched);
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h
index 68518f8..28b339c 100644
--- a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h
+++ b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h
@@ -32,7 +32,7 @@
 
 class SimpleLogMatchingTracker : public virtual LogMatchingTracker {
 public:
-    SimpleLogMatchingTracker(const std::string& name, const int index,
+    SimpleLogMatchingTracker(const int64_t& id, const int index,
                              const SimpleAtomMatcher& matcher,
                              const UidMap& uidMap);
 
@@ -40,7 +40,7 @@
 
     bool init(const std::vector<AtomMatcher>& allLogMatchers,
               const std::vector<sp<LogMatchingTracker>>& allTrackers,
-              const std::unordered_map<std::string, int>& matcherMap,
+              const std::unordered_map<int64_t, int>& matcherMap,
               std::vector<bool>& stack) override;
 
     void onLogEvent(const LogEvent& event,
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 5bf3cff..a24364d 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -43,7 +43,7 @@
 namespace statsd {
 
 // for StatsLogReport
-const int FIELD_ID_NAME = 1;
+const int FIELD_ID_ID = 1;
 const int FIELD_ID_START_REPORT_NANOS = 2;
 const int FIELD_ID_END_REPORT_NANOS = 3;
 const int FIELD_ID_COUNT_METRICS = 5;
@@ -61,7 +61,7 @@
                                          const int conditionIndex,
                                          const sp<ConditionWizard>& wizard,
                                          const uint64_t startTimeNs)
-    : MetricProducer(metric.name(), key, startTimeNs, conditionIndex, wizard) {
+    : MetricProducer(metric.id(), key, startTimeNs, conditionIndex, wizard) {
     // TODO: evaluate initial conditions. and set mConditionMet.
     if (metric.has_bucket() && metric.bucket().has_bucket_size_millis()) {
         mBucketSizeNs = metric.bucket().bucket_size_millis() * 1000 * 1000;
@@ -78,7 +78,7 @@
         mConditionSliced = true;
     }
 
-    VLOG("metric %s created. bucket size %lld start_time: %lld", metric.name().c_str(),
+    VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
          (long long)mBucketSizeNs, (long long)mStartTimeNs);
 }
 
@@ -87,12 +87,12 @@
 }
 
 void CountMetricProducer::onSlicedConditionMayChangeLocked(const uint64_t eventTime) {
-    VLOG("Metric %s onSlicedConditionMayChange", mName.c_str());
+    VLOG("Metric %lld onSlicedConditionMayChange", (long long)mMetricId);
 }
 
 void CountMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs, StatsLogReport* report) {
     flushIfNeededLocked(dumpTimeNs);
-    report->set_metric_name(mName);
+    report->set_metric_id(mMetricId);
     report->set_start_report_nanos(mStartTimeNs);
 
     auto count_metrics = report->mutable_count_metrics();
@@ -112,11 +112,11 @@
                                              ProtoOutputStream* protoOutput) {
     flushIfNeededLocked(dumpTimeNs);
 
-    protoOutput->write(FIELD_TYPE_STRING | FIELD_ID_NAME, mName);
+    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, (long long)mStartTimeNs);
     long long protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_COUNT_METRICS);
 
-    VLOG("metric %s dump report now...", mName.c_str());
+    VLOG("metric %lld dump report now...",(long long)mMetricId);
 
     for (const auto& counter : mPastBuckets) {
         const HashableDimensionKey& hashableKey = counter.first;
@@ -158,7 +158,7 @@
 
 void CountMetricProducer::onConditionChangedLocked(const bool conditionMet,
                                                    const uint64_t eventTime) {
-    VLOG("Metric %s onConditionChanged", mName.c_str());
+    VLOG("Metric %lld onConditionChanged", (long long)mMetricId);
     mCondition = conditionMet;
 }
 
@@ -170,11 +170,11 @@
     // 1. Report the tuple count if the tuple count > soft limit
     if (mCurrentSlicedCounter->size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
         size_t newTupleCount = mCurrentSlicedCounter->size() + 1;
-        StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mName, newTupleCount);
+        StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetricId, newTupleCount);
         // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
         if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
-            ALOGE("CountMetric %s dropping data for dimension key %s", mName.c_str(),
-                  newKey.c_str());
+            ALOGE("CountMetric %lld dropping data for dimension key %s",
+                (long long)mMetricId, newKey.c_str());
             return true;
         }
     }
@@ -215,7 +215,7 @@
                                          mCurrentSlicedCounter->find(eventKey)->second);
     }
 
-    VLOG("metric %s %s->%lld", mName.c_str(), eventKey.c_str(),
+    VLOG("metric %lld %s->%lld", (long long)mMetricId, eventKey.c_str(),
          (long long)(*mCurrentSlicedCounter)[eventKey]);
 }
 
@@ -234,8 +234,8 @@
         info.mCount = counter.second;
         auto& bucketList = mPastBuckets[counter.first];
         bucketList.push_back(info);
-        VLOG("metric %s, dump key value: %s -> %lld", mName.c_str(), counter.first.c_str(),
-             (long long)counter.second);
+        VLOG("metric %lld, dump key value: %s -> %lld",
+            (long long)mMetricId, counter.first.c_str(), (long long)counter.second);
     }
 
     for (auto& tracker : mAnomalyTrackers) {
@@ -247,7 +247,7 @@
     uint64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs;
     mCurrentBucketStartTimeNs = mCurrentBucketStartTimeNs + numBucketsForward * mBucketSizeNs;
     mCurrentBucketNum += numBucketsForward;
-    VLOG("metric %s: new bucket start time: %lld", mName.c_str(),
+    VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId,
          (long long)mCurrentBucketStartTimeNs);
 }
 
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 30b105c..99545ae 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -42,7 +42,7 @@
 namespace statsd {
 
 // for StatsLogReport
-const int FIELD_ID_NAME = 1;
+const int FIELD_ID_ID = 1;
 const int FIELD_ID_START_REPORT_NANOS = 2;
 const int FIELD_ID_END_REPORT_NANOS = 3;
 const int FIELD_ID_DURATION_METRICS = 6;
@@ -63,7 +63,7 @@
                                                const sp<ConditionWizard>& wizard,
                                                const FieldMatcher& internalDimensions,
                                                const uint64_t startTimeNs)
-    : MetricProducer(metric.name(), key, startTimeNs, conditionIndex, wizard),
+    : MetricProducer(metric.id(), key, startTimeNs, conditionIndex, wizard),
       mAggregationType(metric.aggregation_type()),
       mStartIndex(startIndex),
       mStopIndex(stopIndex),
@@ -88,7 +88,7 @@
         mConditionSliced = true;
     }
 
-    VLOG("metric %s created. bucket size %lld start_time: %lld", metric.name().c_str(),
+    VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
          (long long)mBucketSizeNs, (long long)mStartTimeNs);
 }
 
@@ -116,17 +116,17 @@
     switch (mAggregationType) {
         case DurationMetric_AggregationType_SUM:
             return make_unique<OringDurationTracker>(
-                    mConfigKey, mName, eventKey, mWizard, mConditionTrackerIndex, mNested,
+                    mConfigKey, mMetricId, eventKey, mWizard, mConditionTrackerIndex, mNested,
                     mCurrentBucketStartTimeNs, mBucketSizeNs, mAnomalyTrackers);
         case DurationMetric_AggregationType_MAX_SPARSE:
             return make_unique<MaxDurationTracker>(
-                    mConfigKey, mName, eventKey, mWizard, mConditionTrackerIndex, mNested,
+                    mConfigKey, mMetricId, eventKey, mWizard, mConditionTrackerIndex, mNested,
                     mCurrentBucketStartTimeNs, mBucketSizeNs, mAnomalyTrackers);
     }
 }
 
 void DurationMetricProducer::onSlicedConditionMayChangeLocked(const uint64_t eventTime) {
-    VLOG("Metric %s onSlicedConditionMayChange", mName.c_str());
+    VLOG("Metric %lld onSlicedConditionMayChange", (long long)mMetricId);
     flushIfNeededLocked(eventTime);
     // Now for each of the on-going event, check if the condition has changed for them.
     for (auto& pair : mCurrentSlicedDuration) {
@@ -136,7 +136,7 @@
 
 void DurationMetricProducer::onConditionChangedLocked(const bool conditionMet,
                                                       const uint64_t eventTime) {
-    VLOG("Metric %s onConditionChanged", mName.c_str());
+    VLOG("Metric %lld onConditionChanged", (long long)mMetricId);
     mCondition = conditionMet;
     flushIfNeededLocked(eventTime);
     // TODO: need to populate the condition change time from the event which triggers the condition
@@ -148,7 +148,7 @@
 
 void DurationMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs, StatsLogReport* report) {
     flushIfNeededLocked(dumpTimeNs);
-    report->set_metric_name(mName);
+    report->set_metric_id(mMetricId);
     report->set_start_report_nanos(mStartTimeNs);
 
     auto duration_metrics = report->mutable_duration_metrics();
@@ -168,11 +168,11 @@
                                                 ProtoOutputStream* protoOutput) {
     flushIfNeededLocked(dumpTimeNs);
 
-    protoOutput->write(FIELD_TYPE_STRING | FIELD_ID_NAME, mName);
+    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, (long long)mStartTimeNs);
     long long protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DURATION_METRICS);
 
-    VLOG("metric %s dump report now...", mName.c_str());
+    VLOG("metric %lld dump report now...", (long long)mMetricId);
 
     for (const auto& pair : mPastBuckets) {
         const HashableDimensionKey& hashableKey = pair.first;
@@ -237,11 +237,11 @@
     // 1. Report the tuple count if the tuple count > soft limit
     if (mCurrentSlicedDuration.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
         size_t newTupleCount = mCurrentSlicedDuration.size() + 1;
-        StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mName, newTupleCount);
+        StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetricId, newTupleCount);
         // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
         if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
-            ALOGE("DurationMetric %s dropping data for dimension key %s", mName.c_str(),
-                  newKey.c_str());
+            ALOGE("DurationMetric %lld dropping data for dimension key %s",
+                (long long)mMetricId, newKey.c_str());
             return true;
         }
     }
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index c8138d3..821d8ea4 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -41,7 +41,7 @@
 namespace statsd {
 
 // for StatsLogReport
-const int FIELD_ID_NAME = 1;
+const int FIELD_ID_ID = 1;
 const int FIELD_ID_START_REPORT_NANOS = 2;
 const int FIELD_ID_END_REPORT_NANOS = 3;
 const int FIELD_ID_EVENT_METRICS = 4;
@@ -55,7 +55,7 @@
                                          const int conditionIndex,
                                          const sp<ConditionWizard>& wizard,
                                          const uint64_t startTimeNs)
-    : MetricProducer(metric.name(), key, startTimeNs, conditionIndex, wizard) {
+    : MetricProducer(metric.id(), key, startTimeNs, conditionIndex, wizard) {
     if (metric.links().size() > 0) {
         mConditionLinks.insert(mConditionLinks.begin(), metric.links().begin(),
                                metric.links().end());
@@ -64,7 +64,7 @@
 
     startNewProtoOutputStreamLocked();
 
-    VLOG("metric %s created. bucket size %lld start_time: %lld", metric.name().c_str(),
+    VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
          (long long)mBucketSizeNs, (long long)mStartTimeNs);
 }
 
@@ -102,12 +102,13 @@
 
 void EventMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
                                              ProtoOutputStream* protoOutput) {
-    protoOutput->write(FIELD_TYPE_STRING | FIELD_ID_NAME, mName);
+    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, (long long)mStartTimeNs);
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS, (long long)dumpTimeNs);
 
     size_t bufferSize = mProto->size();
-    VLOG("metric %s dump report now... proto size: %zu ", mName.c_str(), bufferSize);
+    VLOG("metric %lld dump report now... proto size: %zu ",
+        (long long)mMetricId, bufferSize);
     std::unique_ptr<std::vector<uint8_t>> buffer = serializeProtoLocked(*mProto);
 
     protoOutput->write(FIELD_TYPE_MESSAGE | FIELD_ID_EVENT_METRICS,
@@ -119,7 +120,7 @@
 
 void EventMetricProducer::onConditionChangedLocked(const bool conditionMet,
                                                    const uint64_t eventTime) {
-    VLOG("Metric %s onConditionChanged", mName.c_str());
+    VLOG("Metric %lld onConditionChanged", (long long)mMetricId);
     mCondition = conditionMet;
 }
 
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 51fd9fc..eaf1de2 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -44,7 +44,7 @@
 namespace statsd {
 
 // for StatsLogReport
-const int FIELD_ID_NAME = 1;
+const int FIELD_ID_ID = 1;
 const int FIELD_ID_START_REPORT_NANOS = 2;
 const int FIELD_ID_END_REPORT_NANOS = 3;
 const int FIELD_ID_GAUGE_METRICS = 8;
@@ -63,7 +63,7 @@
                                          const sp<ConditionWizard>& wizard, const int atomTagId,
                                          const int pullTagId, const uint64_t startTimeNs,
                                          shared_ptr<StatsPullerManager> statsPullerManager)
-    : MetricProducer(metric.name(), key, startTimeNs, conditionIndex, wizard),
+    : MetricProducer(metric.id(), key, startTimeNs, conditionIndex, wizard),
       mStatsPullerManager(statsPullerManager),
       mPullTagId(pullTagId),
       mAtomTagId(atomTagId) {
@@ -92,7 +92,7 @@
                                               metric.bucket().bucket_size_millis());
     }
 
-    VLOG("metric %s created. bucket size %lld start_time: %lld", metric.name().c_str(),
+    VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
          (long long)mBucketSizeNs, (long long)mStartTimeNs);
 }
 
@@ -118,11 +118,11 @@
 
 void GaugeMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
                                              ProtoOutputStream* protoOutput) {
-    VLOG("gauge metric %s dump report now...", mName.c_str());
+    VLOG("gauge metric %lld report now...", (long long)mMetricId);
 
     flushIfNeededLocked(dumpTimeNs);
 
-    protoOutput->write(FIELD_TYPE_STRING | FIELD_ID_NAME, mName);
+    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, (long long)mStartTimeNs);
     long long protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_GAUGE_METRICS);
 
@@ -166,7 +166,7 @@
 
 void GaugeMetricProducer::onConditionChangedLocked(const bool conditionMet,
                                                    const uint64_t eventTime) {
-    VLOG("Metric %s onConditionChanged", mName.c_str());
+    VLOG("Metric %lld onConditionChanged", (long long)mMetricId);
     flushIfNeededLocked(eventTime);
     mCondition = conditionMet;
 
@@ -194,7 +194,7 @@
 }
 
 void GaugeMetricProducer::onSlicedConditionMayChangeLocked(const uint64_t eventTime) {
-    VLOG("Metric %s onSlicedConditionMayChange", mName.c_str());
+    VLOG("Metric %lld onSlicedConditionMayChange", (long long)mMetricId);
 }
 
 std::shared_ptr<FieldValueMap> GaugeMetricProducer::getGaugeFields(const LogEvent& event) {
@@ -223,11 +223,11 @@
     // 1. Report the tuple count if the tuple count > soft limit
     if (mCurrentSlicedBucket->size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
         size_t newTupleCount = mCurrentSlicedBucket->size() + 1;
-        StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mName, newTupleCount);
+        StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetricId, newTupleCount);
         // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
         if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
-            ALOGE("GaugeMetric %s dropping data for dimension key %s", mName.c_str(),
-                  newKey.c_str());
+            ALOGE("GaugeMetric %lld dropping data for dimension key %s",
+                (long long)mMetricId, newKey.c_str());
             return true;
         }
     }
@@ -314,7 +314,8 @@
         info.mGaugeFields = slice.second;
         auto& bucketList = mPastBuckets[slice.first];
         bucketList.push_back(info);
-        VLOG("gauge metric %s, dump key value: %s", mName.c_str(), slice.first.c_str());
+        VLOG("gauge metric %lld, dump key value: %s",
+            (long long)mMetricId, slice.first.c_str());
     }
 
     // Reset counters
@@ -331,7 +332,7 @@
     int64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs;
     mCurrentBucketStartTimeNs = mCurrentBucketStartTimeNs + numBucketsForward * mBucketSizeNs;
     mCurrentBucketNum += numBucketsForward;
-    VLOG("metric %s: new bucket start time: %lld", mName.c_str(),
+    VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId,
          (long long)mCurrentBucketStartTimeNs);
 }
 
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index 4ed8289..d620a7e 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -29,13 +29,13 @@
     }
 
     bool condition;
-    map<string, std::vector<HashableDimensionKey>> conditionKeys;
+    ConditionKey conditionKey;
     if (mConditionSliced) {
         for (const auto& link : mConditionLinks) {
-            conditionKeys.insert(std::make_pair(link.condition(),
-                                                getDimensionKeysForCondition(event, link)));
+            conditionKey.insert(std::make_pair(link.condition(),
+                                               getDimensionKeysForCondition(event, link)));
         }
-        if (mWizard->query(mConditionTrackerIndex, conditionKeys) != ConditionState::kTrue) {
+        if (mWizard->query(mConditionTrackerIndex, conditionKey) != ConditionState::kTrue) {
             condition = false;
         } else {
             condition = true;
@@ -48,11 +48,11 @@
         vector<DimensionsValue> dimensionValues = getDimensionKeys(event, mDimensions);
         for (const DimensionsValue& dimensionValue : dimensionValues) {
             onMatchedLogEventInternalLocked(
-                matcherIndex, HashableDimensionKey(dimensionValue), conditionKeys, condition, event);
+                matcherIndex, HashableDimensionKey(dimensionValue), conditionKey, condition, event);
         }
     } else {
         onMatchedLogEventInternalLocked(
-            matcherIndex, DEFAULT_DIMENSION_KEY, conditionKeys, condition, event);
+            matcherIndex, DEFAULT_DIMENSION_KEY, conditionKey, condition, event);
     }
 }
 
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index fe1a53b..3779c44 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -39,9 +39,9 @@
 // be a no-op.
 class MetricProducer : public virtual PackageInfoListener {
 public:
-    MetricProducer(const std::string& name, const ConfigKey& key, const int64_t startTimeNs,
+    MetricProducer(const int64_t& metricId, const ConfigKey& key, const int64_t startTimeNs,
                    const int conditionIndex, const sp<ConditionWizard>& wizard)
-        : mName(name),
+        : mMetricId(metricId),
           mConfigKey(key),
           mStartTimeNs(startTimeNs),
           mCurrentBucketStartTimeNs(startTimeNs),
@@ -117,8 +117,8 @@
         return mBucketSizeNs;
     }
 
-    inline const string& getName() {
-        return mName;
+    inline const int64_t& getMetricId() {
+        return mMetricId;
     }
 
 protected:
@@ -129,7 +129,7 @@
     virtual void onDumpReportLocked(const uint64_t dumpTimeNs, StatsLogReport* report) = 0;
     virtual size_t byteSizeLocked() const = 0;
 
-    const std::string mName;
+    const int64_t mMetricId;
 
     const ConfigKey mConfigKey;
 
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 9749e0f..7f0239f 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -51,7 +51,7 @@
     mConfigValid =
             initStatsdConfig(key, config, *uidMap, timeBaseSec, mTagIds, mAllAtomMatchers, mAllConditionTrackers,
                              mAllMetricProducers, mAllAnomalyTrackers, mConditionToMetricMap,
-                             mTrackerToMetricMap, mTrackerToConditionMap);
+                             mTrackerToMetricMap, mTrackerToConditionMap, mNoReportMetricIds);
 
     if (!config.has_log_source()) {
         // TODO(b/70794411): uncomment the following line and remove the hard coded log source
@@ -143,8 +143,10 @@
 }
 
 void MetricsManager::onDumpReport(const uint64_t& dumpTimeStampNs, ConfigMetricsReport* report) {
-    for (auto& producer : mAllMetricProducers) {
-        producer->onDumpReport(dumpTimeStampNs, report->add_metrics());
+    for (const auto& producer : mAllMetricProducers) {
+        if (mNoReportMetricIds.find(producer->getMetricId()) == mNoReportMetricIds.end()) {
+            producer->onDumpReport(dumpTimeStampNs, report->add_metrics());
+        }
     }
 }
 
@@ -152,11 +154,13 @@
     VLOG("=========================Metric Reports Start==========================");
     uint64_t dumpTimeStampNs = time(nullptr) * NS_PER_SEC;
     // one StatsLogReport per MetricProduer
-    for (auto& metric : mAllMetricProducers) {
-        long long token =
-                protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_METRICS);
-        metric->onDumpReport(dumpTimeStampNs, protoOutput);
-        protoOutput->end(token);
+    for (const auto& producer : mAllMetricProducers) {
+        if (mNoReportMetricIds.find(producer->getMetricId()) == mNoReportMetricIds.end()) {
+            long long token =
+                    protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_METRICS);
+            producer->onDumpReport(dumpTimeStampNs, protoOutput);
+            protoOutput->end(token);
+        }
     }
     VLOG("=========================Metric Reports End==========================");
 }
@@ -173,6 +177,22 @@
             VLOG("log source %d not on the whitelist", event.GetUid());
             return;
         }
+    } else { // Check that app hook fields are valid.
+        // TODO: Find a way to make these checks easier to maintain if the app hooks get changed.
+
+        // Label is 2nd from last field and must be from [0, 15].
+        status_t err = NO_ERROR;
+        long label = event.GetLong(event.size()-1, &err);
+        if (err != NO_ERROR || label < 0 || label > 15) {
+            VLOG("App hook does not have valid label %ld", label);
+            return;
+        }
+        // The state must be from 0,3. This part of code must be manually updated.
+        long apphookState = event.GetLong(event.size(), &err);
+        if (err != NO_ERROR || apphookState < 0 || apphookState > 3) {
+            VLOG("App hook does not have valid state %ld", apphookState);
+            return;
+        }
     }
 
     int tagId = event.GetTagId();
@@ -240,7 +260,7 @@
     for (size_t i = 0; i < mAllAtomMatchers.size(); i++) {
         if (matcherCache[i] == MatchingState::kMatched) {
             StatsdStats::getInstance().noteMatcherMatched(mConfigKey,
-                                                          mAllAtomMatchers[i]->getName());
+                                                          mAllAtomMatchers[i]->getId());
             auto pair = mTrackerToMetricMap.find(i);
             if (pair != mTrackerToMetricMap.end()) {
                 auto& metricList = pair->second;
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 51c4c90..8175cd2 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -131,6 +131,9 @@
 
     void initLogSourceWhiteList();
 
+    // The metrics that don't need to be uploaded or even reported.
+    std::set<int64_t> mNoReportMetricIds;
+
     FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensions);
     FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks);
 };
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index b58dc68..ea90170 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -46,7 +46,7 @@
 namespace statsd {
 
 // for StatsLogReport
-const int FIELD_ID_NAME = 1;
+const int FIELD_ID_ID = 1;
 const int FIELD_ID_START_REPORT_NANOS = 2;
 const int FIELD_ID_END_REPORT_NANOS = 3;
 const int FIELD_ID_VALUE_METRICS = 7;
@@ -68,7 +68,7 @@
                                          const sp<ConditionWizard>& wizard, const int pullTagId,
                                          const uint64_t startTimeNs,
                                          shared_ptr<StatsPullerManager> statsPullerManager)
-    : MetricProducer(metric.name(), key, startTimeNs, conditionIndex, wizard),
+    : MetricProducer(metric.id(), key, startTimeNs, conditionIndex, wizard),
       mValueField(metric.value_field()),
       mStatsPullerManager(statsPullerManager),
       mPullTagId(pullTagId) {
@@ -92,8 +92,8 @@
         mStatsPullerManager->RegisterReceiver(mPullTagId, this,
                                               metric.bucket().bucket_size_millis());
     }
-    VLOG("value metric %s created. bucket size %lld start_time: %lld", metric.name().c_str(),
-         (long long)mBucketSizeNs, (long long)mStartTimeNs);
+    VLOG("value metric %lld created. bucket size %lld start_time: %lld",
+        (long long)metric.id(), (long long)mBucketSizeNs, (long long)mStartTimeNs);
 }
 
 // for testing
@@ -113,12 +113,12 @@
 }
 
 void ValueMetricProducer::onSlicedConditionMayChangeLocked(const uint64_t eventTime) {
-    VLOG("Metric %s onSlicedConditionMayChange", mName.c_str());
+    VLOG("Metric %lld onSlicedConditionMayChange", (long long)mMetricId);
 }
 
 void ValueMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs, StatsLogReport* report) {
     flushIfNeededLocked(dumpTimeNs);
-    report->set_metric_name(mName);
+    report->set_metric_id(mMetricId);
     report->set_start_report_nanos(mStartTimeNs);
     auto value_metrics = report->mutable_value_metrics();
     for (const auto& pair : mPastBuckets) {
@@ -135,9 +135,9 @@
 
 void ValueMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
                                              ProtoOutputStream* protoOutput) {
-    VLOG("metric %s dump report now...", mName.c_str());
+    VLOG("metric %lld dump report now...", (long long)mMetricId);
     flushIfNeededLocked(dumpTimeNs);
-    protoOutput->write(FIELD_TYPE_STRING | FIELD_ID_NAME, mName);
+    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, (long long)mStartTimeNs);
     long long protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_VALUE_METRICS);
 
@@ -171,7 +171,7 @@
     protoOutput->end(protoToken);
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS, (long long)dumpTimeNs);
 
-    VLOG("metric %s dump report now...", mName.c_str());
+    VLOG("metric %lld dump report now...", (long long)mMetricId);
     mPastBuckets.clear();
     mStartTimeNs = mCurrentBucketStartTimeNs;
     // TODO: Clear mDimensionKeyMap once the report is dumped.
@@ -242,11 +242,11 @@
     }
     if (mCurrentSlicedBucket.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
         size_t newTupleCount = mCurrentSlicedBucket.size() + 1;
-        StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mName, newTupleCount);
+        StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetricId, newTupleCount);
         // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
         if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
-            ALOGE("ValueMetric %s dropping data for dimension key %s", mName.c_str(),
-                  newKey.c_str());
+            ALOGE("ValueMetric %lld dropping data for dimension key %s",
+                (long long)mMetricId, newKey.c_str());
             return true;
         }
     }
@@ -346,7 +346,7 @@
     if (numBucketsForward > 1) {
         VLOG("Skipping forward %lld buckets", (long long)numBucketsForward);
     }
-    VLOG("metric %s: new bucket start time: %lld", mName.c_str(),
+    VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId,
          (long long)mCurrentBucketStartTimeNs);
 }
 
diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
index 9192d12f..842581e 100644
--- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
@@ -60,12 +60,12 @@
 
 class DurationTracker {
 public:
-    DurationTracker(const ConfigKey& key, const string& name, const HashableDimensionKey& eventKey,
+    DurationTracker(const ConfigKey& key, const int64_t& id, const HashableDimensionKey& eventKey,
                     sp<ConditionWizard> wizard, int conditionIndex, bool nesting,
                     uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
                     const std::vector<sp<DurationAnomalyTracker>>& anomalyTrackers)
         : mConfigKey(key),
-          mName(name),
+          mTrackerId(id),
           mEventKey(eventKey),
           mWizard(wizard),
           mConditionTrackerIndex(conditionIndex),
@@ -145,7 +145,7 @@
     // A reference to the DurationMetricProducer's config key.
     const ConfigKey& mConfigKey;
 
-    const std::string mName;
+    const int64_t mTrackerId;
 
     HashableDimensionKey mEventKey;
 
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
index d8a8e23..94f98ad 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
@@ -24,12 +24,12 @@
 namespace os {
 namespace statsd {
 
-MaxDurationTracker::MaxDurationTracker(const ConfigKey& key, const string& name,
+MaxDurationTracker::MaxDurationTracker(const ConfigKey& key, const int64_t& id,
                                        const HashableDimensionKey& eventKey,
                                        sp<ConditionWizard> wizard, int conditionIndex, bool nesting,
                                        uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
                                        const vector<sp<DurationAnomalyTracker>>& anomalyTrackers)
-    : DurationTracker(key, name, eventKey, wizard, conditionIndex, nesting, currentBucketStartNs,
+    : DurationTracker(key, id, eventKey, wizard, conditionIndex, nesting, currentBucketStartNs,
                       bucketSizeNs, anomalyTrackers) {
 }
 
@@ -42,12 +42,13 @@
     // 1. Report the tuple count if the tuple count > soft limit
     if (mInfos.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
         size_t newTupleCount = mInfos.size() + 1;
-        StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mName + mEventKey.toString(),
-                                                           newTupleCount);
+        StatsdStats::getInstance().noteMetricDimensionSize(
+            mConfigKey, hashDimensionsValue(mTrackerId, mEventKey.getDimensionsValue()),
+            newTupleCount);
         // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
         if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
-            ALOGE("MaxDurTracker %s dropping data for dimension key %s", mName.c_str(),
-                  newKey.c_str());
+            ALOGE("MaxDurTracker %lld dropping data for dimension key %s",
+                (long long)mTrackerId, newKey.c_str());
             return true;
         }
     }
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
index 76f486e..68c48cb1 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
@@ -28,7 +28,7 @@
 // they stop or bucket expires.
 class MaxDurationTracker : public DurationTracker {
 public:
-    MaxDurationTracker(const ConfigKey& key, const string& name,
+    MaxDurationTracker(const ConfigKey& key, const int64_t& id,
                        const HashableDimensionKey& eventKey, sp<ConditionWizard> wizard,
                        int conditionIndex, bool nesting, uint64_t currentBucketStartNs,
                        uint64_t bucketSizeNs,
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
index c347d5c..c77d0b7 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
@@ -25,11 +25,11 @@
 using std::pair;
 
 OringDurationTracker::OringDurationTracker(
-        const ConfigKey& key, const string& name, const HashableDimensionKey& eventKey,
+        const ConfigKey& key, const int64_t& id, const HashableDimensionKey& eventKey,
         sp<ConditionWizard> wizard, int conditionIndex, bool nesting, uint64_t currentBucketStartNs,
         uint64_t bucketSizeNs, const vector<sp<DurationAnomalyTracker>>& anomalyTrackers)
 
-    : DurationTracker(key, name, eventKey, wizard, conditionIndex, nesting, currentBucketStartNs,
+    : DurationTracker(key, id, eventKey, wizard, conditionIndex, nesting, currentBucketStartNs,
                       bucketSizeNs, anomalyTrackers),
       mStarted(),
       mPaused() {
@@ -44,12 +44,13 @@
     }
     if (mConditionKeyMap.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
         size_t newTupleCount = mConditionKeyMap.size() + 1;
-        StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mName + mEventKey.toString(),
-                                                           newTupleCount);
+        StatsdStats::getInstance().noteMetricDimensionSize(
+            mConfigKey, hashDimensionsValue(mTrackerId, mEventKey.getDimensionsValue()),
+            newTupleCount);
         // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
         if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
-            ALOGE("OringDurTracker %s dropping data for dimension key %s", mName.c_str(),
-                  newKey.c_str());
+            ALOGE("OringDurTracker %lld dropping data for dimension key %s",
+                (long long)mTrackerId, newKey.c_str());
             return true;
         }
     }
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
index dcf04db..7fe649c 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
@@ -27,7 +27,7 @@
 // Tracks the "Or'd" duration -- if 2 durations are overlapping, they won't be double counted.
 class OringDurationTracker : public DurationTracker {
 public:
-    OringDurationTracker(const ConfigKey& key, const string& name,
+    OringDurationTracker(const ConfigKey& key, const int64_t& id,
                          const HashableDimensionKey& eventKey, sp<ConditionWizard> wizard,
                          int conditionIndex, bool nesting, uint64_t currentBucketStartNs,
                          uint64_t bucketSizeNs,
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 97dbf7a..a4ae4d6 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -38,21 +38,21 @@
 namespace os {
 namespace statsd {
 
-bool handleMetricWithLogTrackers(const string what, const int metricIndex,
+bool handleMetricWithLogTrackers(const int64_t what, const int metricIndex,
                                  const bool usedForDimension,
                                  const vector<sp<LogMatchingTracker>>& allAtomMatchers,
-                                 const unordered_map<string, int>& logTrackerMap,
+                                 const unordered_map<int64_t, int>& logTrackerMap,
                                  unordered_map<int, std::vector<int>>& trackerToMetricMap,
                                  int& logTrackerIndex) {
     auto logTrackerIt = logTrackerMap.find(what);
     if (logTrackerIt == logTrackerMap.end()) {
-        ALOGW("cannot find the AtomMatcher \"%s\" in config", what.c_str());
+        ALOGW("cannot find the AtomMatcher \"%lld\" in config", (long long)what);
         return false;
     }
     if (usedForDimension && allAtomMatchers[logTrackerIt->second]->getAtomIds().size() > 1) {
-        ALOGE("AtomMatcher \"%s\" has more than one tag ids. When a metric has dimension, "
+        ALOGE("AtomMatcher \"%lld\" has more than one tag ids. When a metric has dimension, "
               "the \"what\" can only about one atom type.",
-              what.c_str());
+              (long long)what);
         return false;
     }
     logTrackerIndex = logTrackerIt->second;
@@ -62,22 +62,22 @@
 }
 
 bool handleMetricWithConditions(
-        const string condition, const int metricIndex,
-        const unordered_map<string, int>& conditionTrackerMap,
+        const int64_t condition, const int metricIndex,
+        const unordered_map<int64_t, int>& conditionTrackerMap,
         const ::google::protobuf::RepeatedPtrField<::android::os::statsd::MetricConditionLink>&
                 links,
         vector<sp<ConditionTracker>>& allConditionTrackers, int& conditionIndex,
         unordered_map<int, std::vector<int>>& conditionToMetricMap) {
     auto condition_it = conditionTrackerMap.find(condition);
     if (condition_it == conditionTrackerMap.end()) {
-        ALOGW("cannot find Predicate \"%s\" in the config", condition.c_str());
+        ALOGW("cannot find Predicate \"%lld\" in the config", (long long)condition);
         return false;
     }
 
     for (const auto& link : links) {
         auto it = conditionTrackerMap.find(link.condition());
         if (it == conditionTrackerMap.end()) {
-            ALOGW("cannot find Predicate \"%s\" in the config", link.condition().c_str());
+            ALOGW("cannot find Predicate \"%lld\" in the config", (long long)link.condition());
             return false;
         }
         allConditionTrackers[condition_it->second]->setSliced(true);
@@ -93,7 +93,7 @@
 }
 
 bool initLogTrackers(const StatsdConfig& config, const UidMap& uidMap,
-                     unordered_map<string, int>& logTrackerMap,
+                     unordered_map<int64_t, int>& logTrackerMap,
                      vector<sp<LogMatchingTracker>>& allAtomMatchers, set<int>& allTagIds) {
     vector<AtomMatcher> matcherConfigs;
     const int atomMatcherCount = config.atom_matcher_size();
@@ -107,22 +107,22 @@
         switch (logMatcher.contents_case()) {
             case AtomMatcher::ContentsCase::kSimpleAtomMatcher:
                 allAtomMatchers.push_back(new SimpleLogMatchingTracker(
-                        logMatcher.name(), index, logMatcher.simple_atom_matcher(), uidMap));
+                        logMatcher.id(), index, logMatcher.simple_atom_matcher(), uidMap));
                 break;
             case AtomMatcher::ContentsCase::kCombination:
                 allAtomMatchers.push_back(
-                        new CombinationLogMatchingTracker(logMatcher.name(), index));
+                        new CombinationLogMatchingTracker(logMatcher.id(), index));
                 break;
             default:
-                ALOGE("Matcher \"%s\" malformed", logMatcher.name().c_str());
+                ALOGE("Matcher \"%lld\" malformed", (long long)logMatcher.id());
                 return false;
                 // continue;
         }
-        if (logTrackerMap.find(logMatcher.name()) != logTrackerMap.end()) {
+        if (logTrackerMap.find(logMatcher.id()) != logTrackerMap.end()) {
             ALOGE("Duplicate AtomMatcher found!");
             return false;
         }
-        logTrackerMap[logMatcher.name()] = index;
+        logTrackerMap[logMatcher.id()] = index;
         matcherConfigs.push_back(logMatcher);
     }
 
@@ -139,8 +139,8 @@
 }
 
 bool initConditions(const ConfigKey& key, const StatsdConfig& config,
-                    const unordered_map<string, int>& logTrackerMap,
-                    unordered_map<string, int>& conditionTrackerMap,
+                    const unordered_map<int64_t, int>& logTrackerMap,
+                    unordered_map<int64_t, int>& conditionTrackerMap,
                     vector<sp<ConditionTracker>>& allConditionTrackers,
                     unordered_map<int, std::vector<int>>& trackerToConditionMap) {
     vector<Predicate> conditionConfigs;
@@ -154,23 +154,23 @@
         switch (condition.contents_case()) {
             case Predicate::ContentsCase::kSimplePredicate: {
                 allConditionTrackers.push_back(new SimpleConditionTracker(
-                        key, condition.name(), index, condition.simple_predicate(), logTrackerMap));
+                        key, condition.id(), index, condition.simple_predicate(), logTrackerMap));
                 break;
             }
             case Predicate::ContentsCase::kCombination: {
                 allConditionTrackers.push_back(
-                        new CombinationConditionTracker(condition.name(), index));
+                        new CombinationConditionTracker(condition.id(), index));
                 break;
             }
             default:
-                ALOGE("Predicate \"%s\" malformed", condition.name().c_str());
+                ALOGE("Predicate \"%lld\" malformed", (long long)condition.id());
                 return false;
         }
-        if (conditionTrackerMap.find(condition.name()) != conditionTrackerMap.end()) {
+        if (conditionTrackerMap.find(condition.id()) != conditionTrackerMap.end()) {
             ALOGE("Duplicate Predicate found!");
             return false;
         }
-        conditionTrackerMap[condition.name()] = index;
+        conditionTrackerMap[condition.id()] = index;
         conditionConfigs.push_back(condition);
     }
 
@@ -190,14 +190,15 @@
 }
 
 bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const long timeBaseSec,
-                 const unordered_map<string, int>& logTrackerMap,
-                 const unordered_map<string, int>& conditionTrackerMap,
+                 const unordered_map<int64_t, int>& logTrackerMap,
+                 const unordered_map<int64_t, int>& conditionTrackerMap,
                  const vector<sp<LogMatchingTracker>>& allAtomMatchers,
                  vector<sp<ConditionTracker>>& allConditionTrackers,
                  vector<sp<MetricProducer>>& allMetricProducers,
                  unordered_map<int, std::vector<int>>& conditionToMetricMap,
                  unordered_map<int, std::vector<int>>& trackerToMetricMap,
-                 unordered_map<string, int>& metricMap) {
+                 unordered_map<int64_t, int>& metricMap,
+                 std::set<int64_t> &noReportMetricIds) {
     sp<ConditionWizard> wizard = new ConditionWizard(allConditionTrackers);
     const int allMetricsCount = config.count_metric_size() + config.duration_metric_size() +
                                 config.event_metric_size() + config.value_metric_size();
@@ -219,12 +220,12 @@
     for (int i = 0; i < config.count_metric_size(); i++) {
         const CountMetric& metric = config.count_metric(i);
         if (!metric.has_what()) {
-            ALOGW("cannot find \"what\" in CountMetric \"%s\"", metric.name().c_str());
+            ALOGW("cannot find \"what\" in CountMetric \"%lld\"", (long long)metric.id());
             return false;
         }
 
         int metricIndex = allMetricProducers.size();
-        metricMap.insert({metric.name(), metricIndex});
+        metricMap.insert({metric.id(), metricIndex});
         int trackerIndex;
         if (!handleMetricWithLogTrackers(metric.what(), metricIndex, metric.has_dimensions(),
                                          allAtomMatchers, logTrackerMap, trackerToMetricMap,
@@ -256,7 +257,7 @@
     for (int i = 0; i < config.duration_metric_size(); i++) {
         int metricIndex = allMetricProducers.size();
         const DurationMetric& metric = config.duration_metric(i);
-        metricMap.insert({metric.name(), metricIndex});
+        metricMap.insert({metric.id(), metricIndex});
 
         auto what_it = conditionTrackerMap.find(metric.what());
         if (what_it == conditionTrackerMap.end()) {
@@ -327,8 +328,8 @@
     for (int i = 0; i < config.event_metric_size(); i++) {
         int metricIndex = allMetricProducers.size();
         const EventMetric& metric = config.event_metric(i);
-        metricMap.insert({metric.name(), metricIndex});
-        if (!metric.has_name() || !metric.has_what()) {
+        metricMap.insert({metric.id(), metricIndex});
+        if (!metric.has_id() || !metric.has_what()) {
             ALOGW("cannot find the metric name or what in config");
             return false;
         }
@@ -363,12 +364,12 @@
     for (int i = 0; i < config.value_metric_size(); i++) {
         const ValueMetric& metric = config.value_metric(i);
         if (!metric.has_what()) {
-            ALOGW("cannot find \"what\" in ValueMetric \"%s\"", metric.name().c_str());
+            ALOGW("cannot find \"what\" in ValueMetric \"%lld\"", (long long)metric.id());
             return false;
         }
 
         int metricIndex = allMetricProducers.size();
-        metricMap.insert({metric.name(), metricIndex});
+        metricMap.insert({metric.id(), metricIndex});
         int trackerIndex;
         if (!handleMetricWithLogTrackers(metric.what(), metricIndex, metric.has_dimensions(),
                                          allAtomMatchers, logTrackerMap, trackerToMetricMap,
@@ -408,25 +409,25 @@
     for (int i = 0; i < config.gauge_metric_size(); i++) {
         const GaugeMetric& metric = config.gauge_metric(i);
         if (!metric.has_what()) {
-            ALOGW("cannot find \"what\" in GaugeMetric \"%s\"", metric.name().c_str());
+            ALOGW("cannot find \"what\" in GaugeMetric \"%lld\"", (long long)metric.id());
             return false;
         }
 
         if ((!metric.gauge_fields_filter().has_include_all() ||
              (metric.gauge_fields_filter().include_all() == false)) &&
             !hasLeafNode(metric.gauge_fields_filter().fields())) {
-            ALOGW("Incorrect field filter setting in GaugeMetric %s", metric.name().c_str());
+            ALOGW("Incorrect field filter setting in GaugeMetric %lld", (long long)metric.id());
             return false;
         }
         if ((metric.gauge_fields_filter().has_include_all() &&
              metric.gauge_fields_filter().include_all() == true) &&
             hasLeafNode(metric.gauge_fields_filter().fields())) {
-            ALOGW("Incorrect field filter setting in GaugeMetric %s", metric.name().c_str());
+            ALOGW("Incorrect field filter setting in GaugeMetric %lld", (long long)metric.id());
             return false;
         }
 
         int metricIndex = allMetricProducers.size();
-        metricMap.insert({metric.name(), metricIndex});
+        metricMap.insert({metric.id(), metricIndex});
         int trackerIndex;
         if (!handleMetricWithLogTrackers(metric.what(), metricIndex, metric.has_dimensions(),
                                          allAtomMatchers, logTrackerMap, trackerToMetricMap,
@@ -461,19 +462,28 @@
                 key, metric, conditionIndex, wizard, pullTagId, atomTagId, startTimeNs);
         allMetricProducers.push_back(gaugeProducer);
     }
+    for (int i = 0; i < config.no_report_metric_size(); ++i) {
+        const auto no_report_metric = config.no_report_metric(i);
+        if (metricMap.find(no_report_metric) == metricMap.end()) {
+            ALOGW("no_report_metric %lld not exist", no_report_metric);
+            return false;
+        }
+        noReportMetricIds.insert(no_report_metric);
+    }
     return true;
 }
 
 bool initAlerts(const StatsdConfig& config,
-                const unordered_map<string, int>& metricProducerMap,
+                const unordered_map<int64_t, int>& metricProducerMap,
                 vector<sp<MetricProducer>>& allMetricProducers,
                 vector<sp<AnomalyTracker>>& allAnomalyTrackers) {
+    unordered_map<int64_t, int> anomalyTrackerMap;
     for (int i = 0; i < config.alert_size(); i++) {
         const Alert& alert = config.alert(i);
-        const auto& itr = metricProducerMap.find(alert.metric_name());
+        const auto& itr = metricProducerMap.find(alert.metric_id());
         if (itr == metricProducerMap.end()) {
-            ALOGW("alert \"%s\" has unknown metric name: \"%s\"", alert.name().c_str(),
-                  alert.metric_name().c_str());
+            ALOGW("alert \"%lld\" has unknown metric id: \"%lld\"", (long long)alert.id(),
+                  (long long)alert.metric_id());
             return false;
         }
         if (alert.trigger_if_sum_gt() < 0 || alert.number_of_buckets() <= 0) {
@@ -485,25 +495,44 @@
         sp<MetricProducer> metric = allMetricProducers[metricIndex];
         sp<AnomalyTracker> anomalyTracker = metric->addAnomalyTracker(alert);
         if (anomalyTracker != nullptr) {
+            anomalyTrackerMap.insert(std::make_pair(alert.id(), allAnomalyTrackers.size()));
             allAnomalyTrackers.push_back(anomalyTracker);
         }
     }
+    for (int i = 0; i < config.subscription_size(); ++i) {
+        const Subscription& subscription = config.subscription(i);
+        if (subscription.subscriber_information_case() ==
+            Subscription::SubscriberInformationCase::SUBSCRIBER_INFORMATION_NOT_SET) {
+            ALOGW("subscription \"%lld\" has no subscriber info.\"",
+                (long long)subscription.id());
+            return false;
+        }
+        const auto& itr = anomalyTrackerMap.find(subscription.rule_id());
+        if (itr == anomalyTrackerMap.end()) {
+            ALOGW("subscription \"%lld\" has unknown rule id: \"%lld\"",
+                (long long)subscription.id(), (long long)subscription.rule_id());
+            return false;
+        }
+        const int anomalyTrackerIndex = itr->second;
+        allAnomalyTrackers[anomalyTrackerIndex]->addSubscription(subscription);
+    }
     return true;
 }
 
 bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config,
-                const UidMap& uidMap,
-                        const long timeBaseSec, set<int>& allTagIds,
+                      const UidMap& uidMap,
+                      const long timeBaseSec, set<int>& allTagIds,
                       vector<sp<LogMatchingTracker>>& allAtomMatchers,
                       vector<sp<ConditionTracker>>& allConditionTrackers,
                       vector<sp<MetricProducer>>& allMetricProducers,
                       vector<sp<AnomalyTracker>>& allAnomalyTrackers,
                       unordered_map<int, std::vector<int>>& conditionToMetricMap,
                       unordered_map<int, std::vector<int>>& trackerToMetricMap,
-                      unordered_map<int, std::vector<int>>& trackerToConditionMap) {
-    unordered_map<string, int> logTrackerMap;
-    unordered_map<string, int> conditionTrackerMap;
-    unordered_map<string, int> metricProducerMap;
+                      unordered_map<int, std::vector<int>>& trackerToConditionMap,
+                      std::set<int64_t> &noReportMetricIds) {
+    unordered_map<int64_t, int> logTrackerMap;
+    unordered_map<int64_t, int> conditionTrackerMap;
+    unordered_map<int64_t, int> metricProducerMap;
 
     if (!initLogTrackers(config, uidMap, logTrackerMap, allAtomMatchers, allTagIds)) {
         ALOGE("initLogMatchingTrackers failed");
@@ -519,7 +548,7 @@
 
     if (!initMetrics(key, config, timeBaseSec, logTrackerMap, conditionTrackerMap, allAtomMatchers,
                      allConditionTrackers, allMetricProducers, conditionToMetricMap,
-                     trackerToMetricMap, metricProducerMap)) {
+                     trackerToMetricMap, metricProducerMap, noReportMetricIds)) {
         ALOGE("initMetricProducers failed");
         return false;
     }
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h
index 9ad5176..4f19ada 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.h
+++ b/cmds/statsd/src/metrics/metrics_manager_util.h
@@ -43,8 +43,8 @@
 // [allAtomMatchers]: should store the sp to all the LogMatchingTracker
 // [allTagIds]: contains the set of all interesting tag ids to this config.
 bool initLogTrackers(const StatsdConfig& config,
-                const UidMap& uidMap,
-                     std::unordered_map<std::string, int>& logTrackerMap,
+                     const UidMap& uidMap,
+                     std::unordered_map<int64_t, int>& logTrackerMap,
                      std::vector<sp<LogMatchingTracker>>& allAtomMatchers,
                      std::set<int>& allTagIds);
 
@@ -59,8 +59,8 @@
 // [trackerToConditionMap]: contain the mapping from index of
 //                        log tracker to condition trackers that use the log tracker
 bool initConditions(const ConfigKey& key, const StatsdConfig& config,
-                    const std::unordered_map<std::string, int>& logTrackerMap,
-                    std::unordered_map<std::string, int>& conditionTrackerMap,
+                    const std::unordered_map<int64_t, int>& logTrackerMap,
+                    std::unordered_map<int64_t, int>& conditionTrackerMap,
                     std::vector<sp<ConditionTracker>>& allConditionTrackers,
                     std::unordered_map<int, std::vector<int>>& trackerToConditionMap,
                     std::unordered_map<int, std::vector<MetricConditionLink>>& eventConditionLinks);
@@ -79,28 +79,29 @@
 // [trackerToMetricMap]: contains the mapping from log tracker to MetricProducer index.
 bool initMetrics(
         const ConfigKey& key, const StatsdConfig& config, const long timeBaseSec,
-        const std::unordered_map<std::string, int>& logTrackerMap,
-        const std::unordered_map<std::string, int>& conditionTrackerMap,
+        const std::unordered_map<int64_t, int>& logTrackerMap,
+        const std::unordered_map<int64_t, int>& conditionTrackerMap,
         const std::unordered_map<int, std::vector<MetricConditionLink>>& eventConditionLinks,
         const vector<sp<LogMatchingTracker>>& allAtomMatchers,
         vector<sp<ConditionTracker>>& allConditionTrackers,
         std::vector<sp<MetricProducer>>& allMetricProducers,
         std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
-        std::unordered_map<int, std::vector<int>>& trackerToMetricMap);
+        std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
+        std::set<int64_t> &noReportMetricIds);
 
 // Initialize MetricsManager from StatsdConfig.
 // Parameters are the members of MetricsManager. See MetricsManager for declaration.
 bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config,
-
-                const UidMap& uidMap,
-                const long timeBaseSec, std::set<int>& allTagIds,
+                      const UidMap& uidMap,
+                      const long timeBaseSec, std::set<int>& allTagIds,
                       std::vector<sp<LogMatchingTracker>>& allAtomMatchers,
                       std::vector<sp<ConditionTracker>>& allConditionTrackers,
                       std::vector<sp<MetricProducer>>& allMetricProducers,
                       vector<sp<AnomalyTracker>>& allAnomalyTrackers,
                       std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
                       std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
-                      std::unordered_map<int, std::vector<int>>& trackerToConditionMap);
+                      std::unordered_map<int, std::vector<int>>& trackerToConditionMap,
+                      std::set<int64_t> &noReportMetricIds);
 
 }  // namespace statsd
 }  // namespace os
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index f5282ea..0b369bb 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -137,7 +137,7 @@
 }
 
 message StatsLogReport {
-  optional string metric_name = 1;
+  optional int64 metric_id = 1;
 
   optional int64 start_report_nanos = 2;
 
@@ -178,7 +178,7 @@
 message ConfigMetricsReportList {
   message ConfigKey {
     optional int32 uid = 1;
-    optional string name = 2;
+    optional int64 id = 2;
   }
   optional ConfigKey config_key = 1;
 
@@ -191,28 +191,28 @@
     optional int32 stats_end_time_sec = 2;
 
     message MatcherStats {
-        optional string name = 1;
+        optional int64 id = 1;
         optional int32 matched_times = 2;
     }
 
     message ConditionStats {
-        optional string name = 1;
+        optional int64 id = 1;
         optional int32 max_tuple_counts = 2;
     }
 
     message MetricStats {
-        optional string name = 1;
+        optional int64 id = 1;
         optional int32 max_tuple_counts = 2;
     }
 
     message AlertStats {
-        optional string name = 1;
+        optional int64 id = 1;
         optional int32 alerted_times = 2;
     }
 
     message ConfigStats {
         optional int32 uid = 1;
-        optional string name = 2;
+        optional int64 id = 2;
         optional int32 creation_time_sec = 3;
         optional int32 deletion_time_sec = 4;
         optional int32 metric_count = 5;
diff --git a/cmds/statsd/src/stats_util.h b/cmds/statsd/src/stats_util.h
index e46b8eb..160b1f4 100644
--- a/cmds/statsd/src/stats_util.h
+++ b/cmds/statsd/src/stats_util.h
@@ -32,7 +32,7 @@
 // Minimum bucket size in seconds
 const long kMinBucketSizeSec = 5 * 60;
 
-typedef std::map<std::string, std::vector<HashableDimensionKey>> ConditionKey;
+typedef std::map<int64_t, std::vector<HashableDimensionKey>> ConditionKey;
 
 typedef std::unordered_map<HashableDimensionKey, int64_t> DimToValMap;
 
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 1ed1e05..6ac0e28 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -84,12 +84,12 @@
 }
 
 message AtomMatcher {
-    optional string name = 1;
+    optional int64 id = 1;
 
     message Combination {
         optional LogicalOperation operation = 1;
 
-        repeated string matcher = 2;
+        repeated int64 matcher = 2;
     }
     oneof contents {
         SimpleAtomMatcher simple_atom_matcher = 2;
@@ -98,13 +98,13 @@
 }
 
 message SimplePredicate {
-    optional string start = 1;
+    optional int64 start = 1;
 
-    optional string stop = 2;
+    optional int64 stop = 2;
 
     optional bool count_nesting = 3 [default = true];
 
-    optional string stop_all = 4;
+    optional int64 stop_all = 4;
 
     enum InitialValue {
         UNKNOWN = 0;
@@ -116,12 +116,12 @@
 }
 
 message Predicate {
-    optional string name = 1;
+    optional int64 id = 1;
 
     message Combination {
         optional LogicalOperation operation = 1;
 
-        repeated string predicate = 2;
+        repeated int64 predicate = 2;
     }
 
     oneof contents {
@@ -135,7 +135,7 @@
 }
 
 message MetricConditionLink {
-    optional string condition = 1;
+    optional int64 condition = 1;
 
     optional FieldMatcher dimensions_in_what = 2;
 
@@ -148,21 +148,21 @@
 }
 
 message EventMetric {
-    optional string name = 1;
+    optional int64 id = 1;
 
-    optional string what = 2;
+    optional int64 what = 2;
 
-    optional string condition = 3;
+    optional int64 condition = 3;
 
     repeated MetricConditionLink links = 4;
 }
 
 message CountMetric {
-    optional string name = 1;
+    optional int64 id = 1;
 
-    optional string what = 2;
+    optional int64 what = 2;
 
-    optional string condition = 3;
+    optional int64 condition = 3;
 
     optional FieldMatcher dimensions = 4;
 
@@ -172,11 +172,11 @@
 }
 
 message DurationMetric {
-    optional string name = 1;
+    optional int64 id = 1;
 
-    optional string what = 2;
+    optional int64 what = 2;
 
-    optional string condition = 3;
+    optional int64 condition = 3;
 
     repeated MetricConditionLink links = 4;
 
@@ -193,13 +193,13 @@
 }
 
 message GaugeMetric {
-    optional string name = 1;
+    optional int64 id = 1;
 
-    optional string what = 2;
+    optional int64 what = 2;
 
     optional FieldFilter gauge_fields_filter = 3;
 
-    optional string condition = 4;
+    optional int64 condition = 4;
 
     optional FieldMatcher dimensions = 5;
 
@@ -209,13 +209,13 @@
 }
 
 message ValueMetric {
-    optional string name = 1;
+    optional int64 id = 1;
 
-    optional string what = 2;
+    optional int64 what = 2;
 
     optional int32 value_field = 3;
 
-    optional string condition = 4;
+    optional int64 condition = 4;
 
     optional FieldMatcher dimensions = 5;
 
@@ -228,20 +228,15 @@
 }
 
 message Alert {
-    optional string name = 1;
+    optional int64 id = 1;
 
-    optional string metric_name = 2;
+    optional int64 metric_id = 2;
 
-    message IncidentdDetails {
-        repeated int32 section = 1;
-    }
-    optional IncidentdDetails incidentd_details = 3;
+    optional int32 number_of_buckets = 3;
 
-    optional int32 number_of_buckets = 4;
+    optional int32 refractory_period_secs = 4;
 
-    optional int32 refractory_period_secs = 5;
-
-    optional int64 trigger_if_sum_gt = 6;
+    optional int64 trigger_if_sum_gt = 5;
 }
 
 message AllowedLogSource {
@@ -249,8 +244,40 @@
     repeated string package = 2;
 }
 
+message Alarm {
+    optional int64 id = 1;
+    optional int64 offset_millis = 2;
+    optional int64 period_millis = 3;
+}
+
+message IncidentdDetails {
+    repeated int32 section = 1;
+}
+
+message PerfettoDetails {
+    optional int32 perfetto_stuff = 1;
+}
+
+message Subscription {
+    optional int64 id = 1;
+
+    enum RuleType {
+        RULE_TYPE_UNSPECIFIED = 0;
+        ALARM = 1;
+        ALERT = 2;
+    }
+    optional RuleType rule_type = 2;
+
+    optional int64 rule_id = 3;
+
+    oneof subscriber_information {
+        IncidentdDetails incidentd_details = 4;
+        PerfettoDetails perfetto_details = 5;
+    }
+}
+
 message StatsdConfig {
-    optional string name = 1;
+    optional int64 id = 1;
 
     repeated EventMetric event_metric = 2;
 
@@ -268,5 +295,11 @@
 
     repeated Alert alert = 9;
 
-    optional AllowedLogSource log_source = 10;
+    repeated Alarm alarm = 10;
+
+    repeated Subscription subscription = 11;
+
+    optional AllowedLogSource log_source = 12;
+
+    repeated int64 no_report_metric = 13;
 }
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index 9919abf..c542db2 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -124,7 +124,7 @@
         }
         if (index < 2) continue;
 
-        sendBroadcast(ConfigKey(uid, configName));
+        sendBroadcast(ConfigKey(uid, StrToInt64(configName)));
     }
 }
 
@@ -198,6 +198,7 @@
             index++;
         }
         if (index < 2) continue;
+
         string file_name = StringPrintf("%s/%s", STATS_SERVICE_DIR, name);
         VLOG("full file %s", file_name.c_str());
         int fd = open(file_name.c_str(), O_RDONLY | O_CLOEXEC);
@@ -206,7 +207,7 @@
             if (android::base::ReadFdToString(fd, &content)) {
                 StatsdConfig config;
                 if (config.ParseFromString(content)) {
-                    configsMap[ConfigKey(uid, configName)] = config;
+                    configsMap[ConfigKey(uid, StrToInt64(configName))] = config;
                     VLOG("map key uid=%d|name=%s", uid, name);
                 }
             }
diff --git a/cmds/statsd/tests/ConfigManager_test.cpp b/cmds/statsd/tests/ConfigManager_test.cpp
index 3d923e2..3eac5d2 100644
--- a/cmds/statsd/tests/ConfigManager_test.cpp
+++ b/cmds/statsd/tests/ConfigManager_test.cpp
@@ -14,6 +14,7 @@
 
 #include "src/config/ConfigManager.h"
 #include "src/metrics/MetricsManager.h"
+#include "statsd_test_util.h"
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -31,7 +32,7 @@
 namespace statsd {
 
 static ostream& operator<<(ostream& os, const StatsdConfig& config) {
-    return os << "StatsdConfig{name=" << config.name().c_str() << "}";
+    return os << "StatsdConfig{id=" << config.id() << "}";
 }
 
 }  // namespace statsd
@@ -50,19 +51,21 @@
 /**
  * Validate that the ConfigKey is the one we wanted.
  */
-MATCHER_P2(ConfigKeyEq, uid, name, "") {
-    return arg.GetUid() == uid && arg.GetName() == name;
+MATCHER_P2(ConfigKeyEq, uid, id, "") {
+    return arg.GetUid() == uid && (long long)arg.GetId() == (long long)id;
 }
 
 /**
  * Validate that the StatsdConfig is the one we wanted.
  */
-MATCHER_P(StatsdConfigEq, name, "") {
-    return arg.name() == name;
+MATCHER_P(StatsdConfigEq, id, 0) {
+    return (long long)arg.id() == (long long)id;
 }
 
+const int64_t testConfigId = 12345;
+
 TEST(ConfigManagerTest, TestFakeConfig) {
-    auto metricsManager = std::make_unique<MetricsManager>(ConfigKey(0, "test"),
+    auto metricsManager = std::make_unique<MetricsManager>(ConfigKey(0, testConfigId),
                                                            build_fake_config(), 1000, new UidMap());
     EXPECT_TRUE(metricsManager->isConfigValid());
 }
@@ -77,13 +80,13 @@
     manager->AddListener(listener);
 
     StatsdConfig config91;
-    config91.set_name("91");
+    config91.set_id(91);
     StatsdConfig config92;
-    config92.set_name("92");
+    config92.set_id(92);
     StatsdConfig config93;
-    config93.set_name("93");
+    config93.set_id(93);
     StatsdConfig config94;
-    config94.set_name("94");
+    config94.set_id(94);
 
     {
         InSequence s;
@@ -91,42 +94,46 @@
         manager->Startup();
 
         // Add another one
-        EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, "zzz"), StatsdConfigEq("91")))
+        EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, StringToId("zzz")),
+            StatsdConfigEq(91)))
                 .RetiresOnSaturation();
-        manager->UpdateConfig(ConfigKey(1, "zzz"), config91);
+        manager->UpdateConfig(ConfigKey(1, StringToId("zzz")), config91);
 
         // Update It
-        EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, "zzz"), StatsdConfigEq("92")))
+        EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, StringToId("zzz")),
+            StatsdConfigEq(92)))
                 .RetiresOnSaturation();
-        manager->UpdateConfig(ConfigKey(1, "zzz"), config92);
+        manager->UpdateConfig(ConfigKey(1, StringToId("zzz")), config92);
 
         // Add one with the same uid but a different name
-        EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, "yyy"), StatsdConfigEq("93")))
+        EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, StringToId("yyy")),
+            StatsdConfigEq(93)))
                 .RetiresOnSaturation();
-        manager->UpdateConfig(ConfigKey(1, "yyy"), config93);
+        manager->UpdateConfig(ConfigKey(1, StringToId("yyy")), config93);
 
         // Add one with the same name but a different uid
-        EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(2, "zzz"), StatsdConfigEq("94")))
+        EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(2, StringToId("zzz")),
+            StatsdConfigEq(94)))
                 .RetiresOnSaturation();
-        manager->UpdateConfig(ConfigKey(2, "zzz"), config94);
+        manager->UpdateConfig(ConfigKey(2, StringToId("zzz")), config94);
 
         // Remove (1,yyy)
-        EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(1, "yyy")))
+        EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(1, StringToId("yyy"))))
                 .RetiresOnSaturation();
-        manager->RemoveConfig(ConfigKey(1, "yyy"));
+        manager->RemoveConfig(ConfigKey(1, StringToId("yyy")));
 
         // Remove (2,zzz)
-        EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, "zzz")))
+        EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, StringToId("zzz"))))
                 .RetiresOnSaturation();
-        manager->RemoveConfig(ConfigKey(2, "zzz"));
+        manager->RemoveConfig(ConfigKey(2, StringToId("zzz")));
 
         // Remove (1,zzz)
-        EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(1, "zzz")))
+        EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(1, StringToId("zzz"))))
                 .RetiresOnSaturation();
-        manager->RemoveConfig(ConfigKey(1, "zzz"));
+        manager->RemoveConfig(ConfigKey(1, StringToId("zzz")));
 
         // Remove (2,zzz) again and we shouldn't get the callback
-        manager->RemoveConfig(ConfigKey(2, "zzz"));
+        manager->RemoveConfig(ConfigKey(2, StringToId("zzz")));
     }
 }
 
@@ -142,16 +149,16 @@
     StatsdConfig config;
 
     EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, _)).Times(5);
-    EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, "xxx")));
-    EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, "yyy")));
-    EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, "zzz")));
+    EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, StringToId("xxx"))));
+    EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, StringToId("yyy"))));
+    EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, StringToId("zzz"))));
 
     manager->Startup();
-    manager->UpdateConfig(ConfigKey(1, "aaa"), config);
-    manager->UpdateConfig(ConfigKey(2, "xxx"), config);
-    manager->UpdateConfig(ConfigKey(2, "yyy"), config);
-    manager->UpdateConfig(ConfigKey(2, "zzz"), config);
-    manager->UpdateConfig(ConfigKey(3, "bbb"), config);
+    manager->UpdateConfig(ConfigKey(1, StringToId("aaa")), config);
+    manager->UpdateConfig(ConfigKey(2, StringToId("xxx")), config);
+    manager->UpdateConfig(ConfigKey(2, StringToId("yyy")), config);
+    manager->UpdateConfig(ConfigKey(2, StringToId("zzz")), config);
+    manager->UpdateConfig(ConfigKey(3, StringToId("bbb")), config);
 
     manager->RemoveConfigs(2);
 }
diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp
index 6cd31dd..96ee9c5 100644
--- a/cmds/statsd/tests/MetricsManager_test.cpp
+++ b/cmds/statsd/tests/MetricsManager_test.cpp
@@ -21,6 +21,7 @@
 #include "src/metrics/MetricProducer.h"
 #include "src/metrics/ValueMetricProducer.h"
 #include "src/metrics/metrics_manager_util.h"
+#include "statsd_test_util.h"
 
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 
@@ -40,16 +41,16 @@
 
 // TODO: ADD MORE TEST CASES.
 
-const ConfigKey kConfigKey(0, "test");
+const ConfigKey kConfigKey(0, 12345);
 
 const long timeBaseSec = 1000;
 
 StatsdConfig buildGoodConfig() {
     StatsdConfig config;
-    config.set_name("12345");
+    config.set_id(12345);
 
     AtomMatcher* eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_name("SCREEN_IS_ON");
+    eventMatcher->set_id(StringToId("SCREEN_IS_ON"));
 
     SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
     simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
@@ -59,7 +60,7 @@
             2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
 
     eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_name("SCREEN_IS_OFF");
+    eventMatcher->set_id(StringToId("SCREEN_IS_OFF"));
 
     simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
     simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
@@ -69,23 +70,25 @@
             1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF*/);
 
     eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_name("SCREEN_ON_OR_OFF");
+    eventMatcher->set_id(StringToId("SCREEN_ON_OR_OFF"));
 
     AtomMatcher_Combination* combination = eventMatcher->mutable_combination();
     combination->set_operation(LogicalOperation::OR);
-    combination->add_matcher("SCREEN_IS_ON");
-    combination->add_matcher("SCREEN_IS_OFF");
+    combination->add_matcher(StringToId("SCREEN_IS_ON"));
+    combination->add_matcher(StringToId("SCREEN_IS_OFF"));
 
     CountMetric* metric = config.add_count_metric();
-    metric->set_name("3");
-    metric->set_what("SCREEN_IS_ON");
+    metric->set_id(3);
+    metric->set_what(StringToId("SCREEN_IS_ON"));
     metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
     metric->mutable_dimensions()->set_field(2 /*SCREEN_STATE_CHANGE*/);
     metric->mutable_dimensions()->add_child()->set_field(1);
 
+    config.add_no_report_metric(3);
+
     auto alert = config.add_alert();
-    alert->set_name("3");
-    alert->set_metric_name("3");
+    alert->set_id(3);
+    alert->set_metric_id(3);
     alert->set_number_of_buckets(10);
     alert->set_refractory_period_secs(100);
     alert->set_trigger_if_sum_gt(100);
@@ -94,10 +97,10 @@
 
 StatsdConfig buildCircleMatchers() {
     StatsdConfig config;
-    config.set_name("12345");
+    config.set_id(12345);
 
     AtomMatcher* eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_name("SCREEN_IS_ON");
+    eventMatcher->set_id(StringToId("SCREEN_IS_ON"));
 
     SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
     simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
@@ -107,34 +110,34 @@
             2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
 
     eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_name("SCREEN_ON_OR_OFF");
+    eventMatcher->set_id(StringToId("SCREEN_ON_OR_OFF"));
 
     AtomMatcher_Combination* combination = eventMatcher->mutable_combination();
     combination->set_operation(LogicalOperation::OR);
-    combination->add_matcher("SCREEN_IS_ON");
+    combination->add_matcher(StringToId("SCREEN_IS_ON"));
     // Circle dependency
-    combination->add_matcher("SCREEN_ON_OR_OFF");
+    combination->add_matcher(StringToId("SCREEN_ON_OR_OFF"));
 
     return config;
 }
 
 StatsdConfig buildAlertWithUnknownMetric() {
     StatsdConfig config;
-    config.set_name("12345");
+    config.set_id(12345);
 
     AtomMatcher* eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_name("SCREEN_IS_ON");
+    eventMatcher->set_id(StringToId("SCREEN_IS_ON"));
 
     CountMetric* metric = config.add_count_metric();
-    metric->set_name("3");
-    metric->set_what("SCREEN_IS_ON");
+    metric->set_id(3);
+    metric->set_what(StringToId("SCREEN_IS_ON"));
     metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
     metric->mutable_dimensions()->set_field(2 /*SCREEN_STATE_CHANGE*/);
     metric->mutable_dimensions()->add_child()->set_field(1);
 
     auto alert = config.add_alert();
-    alert->set_name("3");
-    alert->set_metric_name("2");
+    alert->set_id(3);
+    alert->set_metric_id(2);
     alert->set_number_of_buckets(10);
     alert->set_refractory_period_secs(100);
     alert->set_trigger_if_sum_gt(100);
@@ -143,10 +146,10 @@
 
 StatsdConfig buildMissingMatchers() {
     StatsdConfig config;
-    config.set_name("12345");
+    config.set_id(12345);
 
     AtomMatcher* eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_name("SCREEN_IS_ON");
+    eventMatcher->set_id(StringToId("SCREEN_IS_ON"));
 
     SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
     simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
@@ -156,29 +159,29 @@
             2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
 
     eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_name("SCREEN_ON_OR_OFF");
+    eventMatcher->set_id(StringToId("SCREEN_ON_OR_OFF"));
 
     AtomMatcher_Combination* combination = eventMatcher->mutable_combination();
     combination->set_operation(LogicalOperation::OR);
-    combination->add_matcher("SCREEN_IS_ON");
+    combination->add_matcher(StringToId("SCREEN_IS_ON"));
     // undefined matcher
-    combination->add_matcher("ABC");
+    combination->add_matcher(StringToId("ABC"));
 
     return config;
 }
 
 StatsdConfig buildMissingPredicate() {
     StatsdConfig config;
-    config.set_name("12345");
+    config.set_id(12345);
 
     CountMetric* metric = config.add_count_metric();
-    metric->set_name("3");
-    metric->set_what("SCREEN_EVENT");
+    metric->set_id(3);
+    metric->set_what(StringToId("SCREEN_EVENT"));
     metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
-    metric->set_condition("SOME_CONDITION");
+    metric->set_condition(StringToId("SOME_CONDITION"));
 
     AtomMatcher* eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_name("SCREEN_EVENT");
+    eventMatcher->set_id(StringToId("SCREEN_EVENT"));
 
     SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
     simpleAtomMatcher->set_atom_id(2);
@@ -188,37 +191,37 @@
 
 StatsdConfig buildDimensionMetricsWithMultiTags() {
     StatsdConfig config;
-    config.set_name("12345");
+    config.set_id(12345);
 
     AtomMatcher* eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_name("BATTERY_VERY_LOW");
+    eventMatcher->set_id(StringToId("BATTERY_VERY_LOW"));
     SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
     simpleAtomMatcher->set_atom_id(2);
 
     eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_name("BATTERY_VERY_VERY_LOW");
+    eventMatcher->set_id(StringToId("BATTERY_VERY_VERY_LOW"));
     simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
     simpleAtomMatcher->set_atom_id(3);
 
     eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_name("BATTERY_LOW");
+    eventMatcher->set_id(StringToId("BATTERY_LOW"));
 
     AtomMatcher_Combination* combination = eventMatcher->mutable_combination();
     combination->set_operation(LogicalOperation::OR);
-    combination->add_matcher("BATTERY_VERY_LOW");
-    combination->add_matcher("BATTERY_VERY_VERY_LOW");
+    combination->add_matcher(StringToId("BATTERY_VERY_LOW"));
+    combination->add_matcher(StringToId("BATTERY_VERY_VERY_LOW"));
 
     // Count process state changes, slice by uid, while SCREEN_IS_OFF
     CountMetric* metric = config.add_count_metric();
-    metric->set_name("3");
-    metric->set_what("BATTERY_LOW");
+    metric->set_id(3);
+    metric->set_what(StringToId("BATTERY_LOW"));
     metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
     // This case is interesting. We want to dimension across two atoms.
     metric->mutable_dimensions()->add_child()->set_field(1);
 
     auto alert = config.add_alert();
-    alert->set_name("3");
-    alert->set_metric_name("3");
+    alert->set_id(103);
+    alert->set_metric_id(3);
     alert->set_number_of_buckets(10);
     alert->set_refractory_period_secs(100);
     alert->set_trigger_if_sum_gt(100);
@@ -227,10 +230,10 @@
 
 StatsdConfig buildCirclePredicates() {
     StatsdConfig config;
-    config.set_name("12345");
+    config.set_id(12345);
 
     AtomMatcher* eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_name("SCREEN_IS_ON");
+    eventMatcher->set_id(StringToId("SCREEN_IS_ON"));
 
     SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
     simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
@@ -240,7 +243,7 @@
             2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
 
     eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_name("SCREEN_IS_OFF");
+    eventMatcher->set_id(StringToId("SCREEN_IS_OFF"));
 
     simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
     simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
@@ -250,18 +253,18 @@
             1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF*/);
 
     auto condition = config.add_predicate();
-    condition->set_name("SCREEN_IS_ON");
+    condition->set_id(StringToId("SCREEN_IS_ON"));
     SimplePredicate* simplePredicate = condition->mutable_simple_predicate();
-    simplePredicate->set_start("SCREEN_IS_ON");
-    simplePredicate->set_stop("SCREEN_IS_OFF");
+    simplePredicate->set_start(StringToId("SCREEN_IS_ON"));
+    simplePredicate->set_stop(StringToId("SCREEN_IS_OFF"));
 
     condition = config.add_predicate();
-    condition->set_name("SCREEN_IS_EITHER_ON_OFF");
+    condition->set_id(StringToId("SCREEN_IS_EITHER_ON_OFF"));
 
     Predicate_Combination* combination = condition->mutable_combination();
     combination->set_operation(LogicalOperation::OR);
-    combination->add_predicate("SCREEN_IS_ON");
-    combination->add_predicate("SCREEN_IS_EITHER_ON_OFF");
+    combination->add_predicate(StringToId("SCREEN_IS_ON"));
+    combination->add_predicate(StringToId("SCREEN_IS_EITHER_ON_OFF"));
 
     return config;
 }
@@ -277,12 +280,15 @@
     unordered_map<int, std::vector<int>> conditionToMetricMap;
     unordered_map<int, std::vector<int>> trackerToMetricMap;
     unordered_map<int, std::vector<int>> trackerToConditionMap;
+    std::set<int64_t> noReportMetricIds;
 
     EXPECT_TRUE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers,
                                  allConditionTrackers, allMetricProducers, allAnomalyTrackers,
-                                 conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
+                                 conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+                                 noReportMetricIds));
     EXPECT_EQ(1u, allMetricProducers.size());
     EXPECT_EQ(1u, allAnomalyTrackers.size());
+    EXPECT_EQ(1u, noReportMetricIds.size());
 }
 
 TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) {
@@ -296,10 +302,12 @@
     unordered_map<int, std::vector<int>> conditionToMetricMap;
     unordered_map<int, std::vector<int>> trackerToMetricMap;
     unordered_map<int, std::vector<int>> trackerToConditionMap;
+    std::set<int64_t> noReportMetricIds;
 
     EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers,
                                   allConditionTrackers, allMetricProducers, allAnomalyTrackers,
-                                  conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
+                                  conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+                                  noReportMetricIds));
 }
 
 TEST(MetricsManagerTest, TestCircleLogMatcherDependency) {
@@ -313,10 +321,12 @@
     unordered_map<int, std::vector<int>> conditionToMetricMap;
     unordered_map<int, std::vector<int>> trackerToMetricMap;
     unordered_map<int, std::vector<int>> trackerToConditionMap;
+    std::set<int64_t> noReportMetricIds;
 
     EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers,
                                   allConditionTrackers, allMetricProducers, allAnomalyTrackers,
-                                  conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
+                                  conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+                                  noReportMetricIds));
 }
 
 TEST(MetricsManagerTest, TestMissingMatchers) {
@@ -330,9 +340,11 @@
     unordered_map<int, std::vector<int>> conditionToMetricMap;
     unordered_map<int, std::vector<int>> trackerToMetricMap;
     unordered_map<int, std::vector<int>> trackerToConditionMap;
+    std::set<int64_t> noReportMetricIds;
     EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers,
                                   allConditionTrackers, allMetricProducers, allAnomalyTrackers,
-                                  conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
+                                  conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+                                  noReportMetricIds));
 }
 
 TEST(MetricsManagerTest, TestMissingPredicate) {
@@ -346,9 +358,11 @@
     unordered_map<int, std::vector<int>> conditionToMetricMap;
     unordered_map<int, std::vector<int>> trackerToMetricMap;
     unordered_map<int, std::vector<int>> trackerToConditionMap;
+    std::set<int64_t> noReportMetricIds;
     EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers,
                                   allConditionTrackers, allMetricProducers, allAnomalyTrackers,
-                                  conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
+                                  conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+                                  noReportMetricIds));
 }
 
 TEST(MetricsManagerTest, TestCirclePredicateDependency) {
@@ -362,10 +376,12 @@
     unordered_map<int, std::vector<int>> conditionToMetricMap;
     unordered_map<int, std::vector<int>> trackerToMetricMap;
     unordered_map<int, std::vector<int>> trackerToConditionMap;
+    std::set<int64_t> noReportMetricIds;
 
     EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers,
                                   allConditionTrackers, allMetricProducers, allAnomalyTrackers,
-                                  conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
+                                  conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+                                  noReportMetricIds));
 }
 
 TEST(MetricsManagerTest, testAlertWithUnknownMetric) {
@@ -379,10 +395,12 @@
     unordered_map<int, std::vector<int>> conditionToMetricMap;
     unordered_map<int, std::vector<int>> trackerToMetricMap;
     unordered_map<int, std::vector<int>> trackerToConditionMap;
+    std::set<int64_t> noReportMetricIds;
 
     EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers,
                                   allConditionTrackers, allMetricProducers, allAnomalyTrackers,
-                                  conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
+                                  conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+                                  noReportMetricIds));
 }
 
 #else
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index a27bed5..5d053e2 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, new UidMap()) {
+    MockMetricsManager() : MetricsManager(ConfigKey(1, 12345), StatsdConfig(), 1000, new UidMap()) {
     }
 
     MOCK_METHOD0(byteSize, size_t());
@@ -56,7 +56,7 @@
 
     MockMetricsManager mockMetricsManager;
 
-    ConfigKey key(100, "key");
+    ConfigKey key(100, 12345);
     // Expect only the first flush to trigger a check for byte size since the last two are
     // rate-limited.
     EXPECT_CALL(mockMetricsManager, byteSize()).Times(1);
@@ -74,7 +74,7 @@
 
     MockMetricsManager mockMetricsManager;
 
-    ConfigKey key(100, "key");
+    ConfigKey key(100, 12345);
     EXPECT_CALL(mockMetricsManager, byteSize())
             .Times(2)
             .WillRepeatedly(Return(int(StatsdStats::kMaxMetricsBytesPerConfig * .95)));
@@ -98,7 +98,7 @@
 
     MockMetricsManager mockMetricsManager;
 
-    ConfigKey key(100, "key");
+    ConfigKey key(100, 12345);
     EXPECT_CALL(mockMetricsManager, byteSize())
             .Times(1)
             .WillRepeatedly(Return(int(StatsdStats::kMaxMetricsBytesPerConfig * 1.2)));
diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp
index 8a394f7..945af27 100644
--- a/cmds/statsd/tests/UidMap_test.cpp
+++ b/cmds/statsd/tests/UidMap_test.cpp
@@ -18,6 +18,7 @@
 #include "guardrail/StatsdStats.h"
 #include "logd/LogEvent.h"
 #include "statslog.h"
+#include "statsd_test_util.h"
 
 #include <gtest/gtest.h>
 
@@ -156,8 +157,8 @@
 TEST(UidMapTest, TestClearingOutput) {
     UidMap m;
 
-    ConfigKey config1(1, "config1");
-    ConfigKey config2(1, "config2");
+    ConfigKey config1(1, StringToId("config1"));
+    ConfigKey config2(1, StringToId("config2"));
 
     m.OnConfigUpdated(config1);
 
@@ -211,7 +212,7 @@
 TEST(UidMapTest, TestMemoryComputed) {
     UidMap m;
 
-    ConfigKey config1(1, "config1");
+    ConfigKey config1(1, StringToId("config1"));
     m.OnConfigUpdated(config1);
 
     size_t startBytes = m.mBytesUsed;
@@ -241,7 +242,7 @@
     UidMap m;
     string buf;
 
-    ConfigKey config1(1, "config1");
+    ConfigKey config1(1, StringToId("config1"));
     m.OnConfigUpdated(config1);
 
     size_t startBytes = m.mBytesUsed;
diff --git a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
index da872ad..751180d 100644
--- a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
+++ b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
@@ -31,7 +31,7 @@
 namespace os {
 namespace statsd {
 
-const ConfigKey kConfigKey(0, "test");
+const ConfigKey kConfigKey(0, 12345);
 
 HashableDimensionKey getMockDimensionKey(int key, string value) {
     DimensionsValue dimensionsValue;
diff --git a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
index 705804f..819f2be 100644
--- a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
+++ b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
@@ -11,7 +11,9 @@
 // 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.
+
 #include "src/condition/SimpleConditionTracker.h"
+#include "tests/statsd_test_util.h"
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -29,7 +31,7 @@
 namespace os {
 namespace statsd {
 
-const ConfigKey kConfigKey(0, "test");
+const ConfigKey kConfigKey(0, 12345);
 
 const int ATTRIBUTION_NODE_FIELD_ID = 1;
 const int ATTRIBUTION_UID_FIELD_ID = 1;
@@ -38,9 +40,9 @@
 SimplePredicate getWakeLockHeldCondition(bool countNesting, bool defaultFalse,
                                          bool outputSlicedUid, Position position) {
     SimplePredicate simplePredicate;
-    simplePredicate.set_start("WAKE_LOCK_ACQUIRE");
-    simplePredicate.set_stop("WAKE_LOCK_RELEASE");
-    simplePredicate.set_stop_all("RELEASE_ALL");
+    simplePredicate.set_start(StringToId("WAKE_LOCK_ACQUIRE"));
+    simplePredicate.set_stop(StringToId("WAKE_LOCK_RELEASE"));
+    simplePredicate.set_stop_all(StringToId("RELEASE_ALL"));
     if (outputSlicedUid) {
         simplePredicate.mutable_dimensions()->set_field(TAG_ID);
         simplePredicate.mutable_dimensions()->add_child()->set_field(ATTRIBUTION_NODE_FIELD_ID);
@@ -73,10 +75,10 @@
     event->init();
 }
 
-std::map<string, std::vector<HashableDimensionKey>> getWakeLockQueryKey(
+std::map<int64_t, std::vector<HashableDimensionKey>> getWakeLockQueryKey(
     const Position position,
     const std::vector<int> &uids, const string& conditionName) {
-    std::map<string, std::vector<HashableDimensionKey>>  outputKeyMap;
+    std::map<int64_t, std::vector<HashableDimensionKey>>  outputKeyMap;
     std::vector<int> uid_indexes;
     switch(position) {
         case Position::FIRST:
@@ -96,28 +98,29 @@
     for (const int idx : uid_indexes) {
         DimensionsValue dimensionsValue;
         dimensionsValue.set_field(TAG_ID);
-        dimensionsValue.mutable_value_tuple()->add_dimensions_value()->set_field(ATTRIBUTION_NODE_FIELD_ID);
+        dimensionsValue.mutable_value_tuple()->add_dimensions_value()->set_field(
+            ATTRIBUTION_NODE_FIELD_ID);
         dimensionsValue.mutable_value_tuple()->mutable_dimensions_value(0)
             ->mutable_value_tuple()->add_dimensions_value()->set_field(ATTRIBUTION_NODE_FIELD_ID);
         dimensionsValue.mutable_value_tuple()->mutable_dimensions_value(0)
             ->mutable_value_tuple()->mutable_dimensions_value(0)->set_value_int(uids[idx]);
-        outputKeyMap[conditionName].push_back(HashableDimensionKey(dimensionsValue));
+        outputKeyMap[StringToId(conditionName)].push_back(HashableDimensionKey(dimensionsValue));
     }
     return outputKeyMap;
 }
 
 TEST(SimpleConditionTrackerTest, TestNonSlicedCondition) {
     SimplePredicate simplePredicate;
-    simplePredicate.set_start("SCREEN_TURNED_ON");
-    simplePredicate.set_stop("SCREEN_TURNED_OFF");
+    simplePredicate.set_start(StringToId("SCREEN_TURNED_ON"));
+    simplePredicate.set_stop(StringToId("SCREEN_TURNED_OFF"));
     simplePredicate.set_count_nesting(false);
     simplePredicate.set_initial_value(SimplePredicate_InitialValue_UNKNOWN);
 
-    unordered_map<string, int> trackerNameIndexMap;
-    trackerNameIndexMap["SCREEN_TURNED_ON"] = 0;
-    trackerNameIndexMap["SCREEN_TURNED_OFF"] = 1;
+    unordered_map<int64_t, int> trackerNameIndexMap;
+    trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0;
+    trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1;
 
-    SimpleConditionTracker conditionTracker(kConfigKey, "SCREEN_IS_ON", 0 /*tracker index*/,
+    SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), 0 /*tracker index*/,
                                             simplePredicate, trackerNameIndexMap);
 
     LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
@@ -191,15 +194,15 @@
 
 TEST(SimpleConditionTrackerTest, TestNonSlicedConditionNestCounting) {
     SimplePredicate simplePredicate;
-    simplePredicate.set_start("SCREEN_TURNED_ON");
-    simplePredicate.set_stop("SCREEN_TURNED_OFF");
+    simplePredicate.set_start(StringToId("SCREEN_TURNED_ON"));
+    simplePredicate.set_stop(StringToId("SCREEN_TURNED_OFF"));
     simplePredicate.set_count_nesting(true);
 
-    unordered_map<string, int> trackerNameIndexMap;
-    trackerNameIndexMap["SCREEN_TURNED_ON"] = 0;
-    trackerNameIndexMap["SCREEN_TURNED_OFF"] = 1;
+    unordered_map<int64_t, int> trackerNameIndexMap;
+    trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0;
+    trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1;
 
-    SimpleConditionTracker conditionTracker(kConfigKey, "SCREEN_IS_ON",
+    SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"),
                                             0 /*condition tracker index*/, simplePredicate,
                                             trackerNameIndexMap);
 
@@ -267,12 +270,12 @@
                 position);
         string conditionName = "WL_HELD_BY_UID2";
 
-        unordered_map<string, int> trackerNameIndexMap;
-        trackerNameIndexMap["WAKE_LOCK_ACQUIRE"] = 0;
-        trackerNameIndexMap["WAKE_LOCK_RELEASE"] = 1;
-        trackerNameIndexMap["RELEASE_ALL"] = 2;
+        unordered_map<int64_t, int> trackerNameIndexMap;
+        trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0;
+        trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
+        trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
 
-        SimpleConditionTracker conditionTracker(kConfigKey, conditionName,
+        SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName),
                                                 0 /*condition tracker index*/, simplePredicate,
                                                 trackerNameIndexMap);
         std::vector<int> uids = {111, 222, 333};
@@ -371,12 +374,12 @@
             Position::ANY /* position */);
     string conditionName = "WL_HELD";
 
-    unordered_map<string, int> trackerNameIndexMap;
-    trackerNameIndexMap["WAKE_LOCK_ACQUIRE"] = 0;
-    trackerNameIndexMap["WAKE_LOCK_RELEASE"] = 1;
-    trackerNameIndexMap["RELEASE_ALL"] = 2;
+    unordered_map<int64_t, int> trackerNameIndexMap;
+    trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0;
+    trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
+    trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
 
-    SimpleConditionTracker conditionTracker(kConfigKey, conditionName,
+    SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName),
                                             0 /*condition tracker index*/, simplePredicate,
                                             trackerNameIndexMap);
 
@@ -461,12 +464,12 @@
                 position);
         string conditionName = "WL_HELD_BY_UID3";
 
-        unordered_map<string, int> trackerNameIndexMap;
-        trackerNameIndexMap["WAKE_LOCK_ACQUIRE"] = 0;
-        trackerNameIndexMap["WAKE_LOCK_RELEASE"] = 1;
-        trackerNameIndexMap["RELEASE_ALL"] = 2;
+        unordered_map<int64_t, int> trackerNameIndexMap;
+        trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0;
+        trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
+        trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
 
-        SimpleConditionTracker conditionTracker(kConfigKey, conditionName,
+        SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName),
                                                 0 /*condition tracker index*/, simplePredicate,
                                                 trackerNameIndexMap);
 
diff --git a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
index c747016..b56b817 100644
--- a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
@@ -55,16 +55,16 @@
     *config.add_predicate() = isInBackgroundPredicate;
 
     auto combinationPredicate = config.add_predicate();
-    combinationPredicate->set_name("combinationPredicate");
+    combinationPredicate->set_id(StringToId("combinationPredicate"));
     combinationPredicate->mutable_combination()->set_operation(LogicalOperation::AND);
     addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
     addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
     addPredicateToPredicateCombination(isInBackgroundPredicate, combinationPredicate);
 
     auto countMetric = config.add_count_metric();
-    countMetric->set_name("AppCrashes");
-    countMetric->set_what(appCrashMatcher.name());
-    countMetric->set_condition(combinationPredicate->name());
+    countMetric->set_id(StringToId("AppCrashes"));
+    countMetric->set_what(appCrashMatcher.id());
+    countMetric->set_condition(combinationPredicate->id());
     // The metric is dimensioning by uid only.
     *countMetric->mutable_dimensions() =
         CreateDimensions(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, {1});
@@ -72,7 +72,7 @@
 
     // Links between crash atom and condition of app is in syncing.
     auto links = countMetric->add_links();
-    links->set_condition(isSyncingPredicate.name());
+    links->set_condition(isSyncingPredicate.id());
     auto dimensionWhat = links->mutable_dimensions_in_what();
     dimensionWhat->set_field(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
     dimensionWhat->add_child()->set_field(1);  // uid field.
@@ -82,7 +82,7 @@
 
     // Links between crash atom and condition of app is in background.
     links = countMetric->add_links();
-    links->set_condition(isInBackgroundPredicate.name());
+    links->set_condition(isInBackgroundPredicate.id());
     dimensionWhat = links->mutable_dimensions_in_what();
     dimensionWhat->set_field(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
     dimensionWhat->add_child()->set_field(1);  // uid field.
diff --git a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
index 8d7b2d5..ecdb002 100644
--- a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
@@ -43,9 +43,9 @@
     *config.add_predicate() = holdingWakelockPredicate;
 
     auto durationMetric = config.add_duration_metric();
-    durationMetric->set_name("WakelockDuration");
-    durationMetric->set_what(holdingWakelockPredicate.name());
-    durationMetric->set_condition(screenIsOffPredicate.name());
+    durationMetric->set_id(StringToId("WakelockDuration"));
+    durationMetric->set_what(holdingWakelockPredicate.id());
+    durationMetric->set_condition(screenIsOffPredicate.id());
     durationMetric->set_aggregation_type(aggregationType);
     // The metric is dimensioning by first attribution node and only by uid.
     *durationMetric->mutable_dimensions() =
diff --git a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
index 7658044..a134300 100644
--- a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
+++ b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
@@ -14,6 +14,7 @@
 
 #include "src/guardrail/StatsdStats.h"
 #include "statslog.h"
+#include "tests/statsd_test_util.h"
 
 #include <gtest/gtest.h>
 #include <vector>
@@ -28,8 +29,7 @@
 
 TEST(StatsdStatsTest, TestValidConfigAdd) {
     StatsdStats stats;
-    string name = "StatsdTest";
-    ConfigKey key(0, name);
+    ConfigKey key(0, 12345);
     const int metricsCount = 10;
     const int conditionsCount = 20;
     const int matchersCount = 30;
@@ -45,7 +45,7 @@
     EXPECT_EQ(1, report.config_stats_size());
     const auto& configReport = report.config_stats(0);
     EXPECT_EQ(0, configReport.uid());
-    EXPECT_EQ(name, configReport.name());
+    EXPECT_EQ(12345, configReport.id());
     EXPECT_EQ(metricsCount, configReport.metric_count());
     EXPECT_EQ(conditionsCount, configReport.condition_count());
     EXPECT_EQ(matchersCount, configReport.matcher_count());
@@ -56,8 +56,7 @@
 
 TEST(StatsdStatsTest, TestInvalidConfigAdd) {
     StatsdStats stats;
-    string name = "StatsdTest";
-    ConfigKey key(0, name);
+    ConfigKey key(0, 12345);
     const int metricsCount = 10;
     const int conditionsCount = 20;
     const int matchersCount = 30;
@@ -78,8 +77,7 @@
 
 TEST(StatsdStatsTest, TestConfigRemove) {
     StatsdStats stats;
-    string name = "StatsdTest";
-    ConfigKey key(0, name);
+    ConfigKey key(0, 12345);
     const int metricsCount = 10;
     const int conditionsCount = 20;
     const int matchersCount = 30;
@@ -105,22 +103,22 @@
 
 TEST(StatsdStatsTest, TestSubStats) {
     StatsdStats stats;
-    ConfigKey key(0, "test");
+    ConfigKey key(0, 12345);
     stats.noteConfigReceived(key, 2, 3, 4, 5, true);
 
-    stats.noteMatcherMatched(key, "matcher1");
-    stats.noteMatcherMatched(key, "matcher1");
-    stats.noteMatcherMatched(key, "matcher2");
+    stats.noteMatcherMatched(key, StringToId("matcher1"));
+    stats.noteMatcherMatched(key, StringToId("matcher1"));
+    stats.noteMatcherMatched(key, StringToId("matcher2"));
 
-    stats.noteConditionDimensionSize(key, "condition1", 250);
-    stats.noteConditionDimensionSize(key, "condition1", 240);
+    stats.noteConditionDimensionSize(key, StringToId("condition1"), 250);
+    stats.noteConditionDimensionSize(key, StringToId("condition1"), 240);
 
-    stats.noteMetricDimensionSize(key, "metric1", 201);
-    stats.noteMetricDimensionSize(key, "metric1", 202);
+    stats.noteMetricDimensionSize(key, StringToId("metric1"), 201);
+    stats.noteMetricDimensionSize(key, StringToId("metric1"), 202);
 
-    stats.noteAnomalyDeclared(key, "alert1");
-    stats.noteAnomalyDeclared(key, "alert1");
-    stats.noteAnomalyDeclared(key, "alert2");
+    stats.noteAnomalyDeclared(key, StringToId("alert1"));
+    stats.noteAnomalyDeclared(key, StringToId("alert1"));
+    stats.noteAnomalyDeclared(key, StringToId("alert2"));
 
     // broadcast-> 2
     stats.noteBroadcastSent(key);
@@ -147,39 +145,39 @@
 
     EXPECT_EQ(2, configReport.matcher_stats_size());
     // matcher1 is the first in the list
-    if (!configReport.matcher_stats(0).name().compare("matcher1")) {
+    if (configReport.matcher_stats(0).id() == StringToId("matcher1")) {
         EXPECT_EQ(2, configReport.matcher_stats(0).matched_times());
         EXPECT_EQ(1, configReport.matcher_stats(1).matched_times());
-        EXPECT_EQ("matcher2", configReport.matcher_stats(1).name());
+        EXPECT_EQ(StringToId("matcher2"), configReport.matcher_stats(1).id());
     } else {
         // matcher1 is the second in the list.
         EXPECT_EQ(1, configReport.matcher_stats(0).matched_times());
-        EXPECT_EQ("matcher2", configReport.matcher_stats(0).name());
+        EXPECT_EQ(StringToId("matcher2"), configReport.matcher_stats(0).id());
 
         EXPECT_EQ(2, configReport.matcher_stats(1).matched_times());
-        EXPECT_EQ("matcher1", configReport.matcher_stats(1).name());
+        EXPECT_EQ(StringToId("matcher1"), configReport.matcher_stats(1).id());
     }
 
     EXPECT_EQ(2, configReport.alert_stats_size());
-    bool alert1first = !configReport.alert_stats(0).name().compare("alert1");
-    EXPECT_EQ("alert1", configReport.alert_stats(alert1first ? 0 : 1).name());
+    bool alert1first = configReport.alert_stats(0).id() == StringToId("alert1");
+    EXPECT_EQ(StringToId("alert1"), configReport.alert_stats(alert1first ? 0 : 1).id());
     EXPECT_EQ(2, configReport.alert_stats(alert1first ? 0 : 1).alerted_times());
-    EXPECT_EQ("alert2", configReport.alert_stats(alert1first ? 1 : 0).name());
+    EXPECT_EQ(StringToId("alert2"), configReport.alert_stats(alert1first ? 1 : 0).id());
     EXPECT_EQ(1, configReport.alert_stats(alert1first ? 1 : 0).alerted_times());
 
     EXPECT_EQ(1, configReport.condition_stats_size());
-    EXPECT_EQ("condition1", configReport.condition_stats(0).name());
+    EXPECT_EQ(StringToId("condition1"), configReport.condition_stats(0).id());
     EXPECT_EQ(250, configReport.condition_stats(0).max_tuple_counts());
 
     EXPECT_EQ(1, configReport.metric_stats_size());
-    EXPECT_EQ("metric1", configReport.metric_stats(0).name());
+    EXPECT_EQ(StringToId("metric1"), configReport.metric_stats(0).id());
     EXPECT_EQ(202, configReport.metric_stats(0).max_tuple_counts());
 
     // after resetting the stats, some new events come
-    stats.noteMatcherMatched(key, "matcher99");
-    stats.noteConditionDimensionSize(key, "condition99", 300);
-    stats.noteMetricDimensionSize(key, "metric99", 270);
-    stats.noteAnomalyDeclared(key, "alert99");
+    stats.noteMatcherMatched(key, StringToId("matcher99"));
+    stats.noteConditionDimensionSize(key, StringToId("condition99"), 300);
+    stats.noteMetricDimensionSize(key, StringToId("metric99tion99"), 270);
+    stats.noteAnomalyDeclared(key, StringToId("alert99"));
 
     // now the config stats should only contain the stats about the new event.
     stats.dumpStats(&output, false);
@@ -188,19 +186,19 @@
     EXPECT_EQ(1, report.config_stats_size());
     const auto& configReport2 = report.config_stats(0);
     EXPECT_EQ(1, configReport2.matcher_stats_size());
-    EXPECT_EQ("matcher99", configReport2.matcher_stats(0).name());
+    EXPECT_EQ(StringToId("matcher99"), configReport2.matcher_stats(0).id());
     EXPECT_EQ(1, configReport2.matcher_stats(0).matched_times());
 
     EXPECT_EQ(1, configReport2.condition_stats_size());
-    EXPECT_EQ("condition99", configReport2.condition_stats(0).name());
+    EXPECT_EQ(StringToId("condition99"), configReport2.condition_stats(0).id());
     EXPECT_EQ(300, configReport2.condition_stats(0).max_tuple_counts());
 
     EXPECT_EQ(1, configReport2.metric_stats_size());
-    EXPECT_EQ("metric99", configReport2.metric_stats(0).name());
+    EXPECT_EQ(StringToId("metric99tion99"), configReport2.metric_stats(0).id());
     EXPECT_EQ(270, configReport2.metric_stats(0).max_tuple_counts());
 
     EXPECT_EQ(1, configReport2.alert_stats_size());
-    EXPECT_EQ("alert99", configReport2.alert_stats(0).name());
+    EXPECT_EQ(StringToId("alert99"), configReport2.alert_stats(0).id());
     EXPECT_EQ(1, configReport2.alert_stats(0).alerted_times());
 }
 
@@ -260,7 +258,7 @@
     for (int i = 0; i < StatsdStats::kMaxTimestampCount; i++) {
         timestamps.push_back(i);
     }
-    ConfigKey key(0, "test");
+    ConfigKey key(0, 12345);
     stats.noteConfigReceived(key, 2, 3, 4, 5, true);
 
     for (int i = 0; i < StatsdStats::kMaxTimestampCount; i++) {
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
index 6e114a6..4c2d472 100644
--- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -15,6 +15,7 @@
 #include "src/metrics/CountMetricProducer.h"
 #include "src/dimension.h"
 #include "metrics_test_helper.h"
+#include "tests/statsd_test_util.h"
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -33,7 +34,7 @@
 namespace os {
 namespace statsd {
 
-const ConfigKey kConfigKey(0, "test");
+const ConfigKey kConfigKey(0, 12345);
 
 TEST(CountMetricProducerTest, TestNonDimensionalEvents) {
     int64_t bucketStartTimeNs = 10000000000;
@@ -43,7 +44,7 @@
     int tagId = 1;
 
     CountMetric metric;
-    metric.set_name("1");
+    metric.set_id(1);
     metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
 
     LogEvent event1(tagId, bucketStartTimeNs + 1);
@@ -100,9 +101,9 @@
     int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
 
     CountMetric metric;
-    metric.set_name("1");
+    metric.set_id(1);
     metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
-    metric.set_condition("SCREEN_ON");
+    metric.set_condition(StringToId("SCREEN_ON"));
 
     LogEvent event1(1, bucketStartTimeNs + 1);
     LogEvent event2(1, bucketStartTimeNs + 10);
@@ -142,11 +143,11 @@
     int conditionTagId = 2;
 
     CountMetric metric;
-    metric.set_name("1");
+    metric.set_id(1);
     metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
-    metric.set_condition("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON");
+    metric.set_condition(StringToId("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON"));
     MetricConditionLink* link = metric.add_links();
-    link->set_condition("APP_IN_BACKGROUND_PER_UID");
+    link->set_condition(StringToId("APP_IN_BACKGROUND_PER_UID"));
     *link->mutable_dimensions_in_what() = buildSimpleAtomFieldMatcher(tagId, 1);
     *link->mutable_dimensions_in_condition() = buildSimpleAtomFieldMatcher(conditionTagId, 2);
 
@@ -154,13 +155,15 @@
     event1.write("111");  // uid
     event1.init();
     ConditionKey key1;
-    key1["APP_IN_BACKGROUND_PER_UID"] = {getMockedDimensionKey(conditionTagId, 2, "111")};
+    key1[StringToId("APP_IN_BACKGROUND_PER_UID")] =
+        {getMockedDimensionKey(conditionTagId, 2, "111")};
 
     LogEvent event2(tagId, bucketStartTimeNs + 10);
     event2.write("222");  // uid
     event2.init();
     ConditionKey key2;
-    key2["APP_IN_BACKGROUND_PER_UID"] = {getMockedDimensionKey(conditionTagId, 2, "222")};
+    key2[StringToId("APP_IN_BACKGROUND_PER_UID")] =
+        {getMockedDimensionKey(conditionTagId, 2, "222")};
 
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     EXPECT_CALL(*wizard, query(_, key1)).WillOnce(Return(ConditionState::kFalse));
@@ -189,8 +192,8 @@
 
 TEST(CountMetricProducerTest, TestAnomalyDetection) {
     Alert alert;
-    alert.set_name("alert");
-    alert.set_metric_name("1");
+    alert.set_id(11);
+    alert.set_metric_id(1);
     alert.set_trigger_if_sum_gt(2);
     alert.set_number_of_buckets(2);
     alert.set_refractory_period_secs(1);
@@ -201,7 +204,7 @@
     int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
 
     CountMetric metric;
-    metric.set_name("1");
+    metric.set_id(1);
     metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
 
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
diff --git a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
index 8ee94c7..a4213de 100644
--- a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
@@ -36,7 +36,7 @@
 namespace os {
 namespace statsd {
 
-const ConfigKey kConfigKey(0, "test");
+const ConfigKey kConfigKey(0, 12345);
 
 TEST(DurationMetricTrackerTest, TestNoCondition) {
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
@@ -44,7 +44,7 @@
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
 
     DurationMetric metric;
-    metric.set_name("1");
+    metric.set_id(1);
     metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
     metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
 
@@ -79,7 +79,7 @@
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
 
     DurationMetric metric;
-    metric.set_name("1");
+    metric.set_id(1);
     metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
     metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
 
diff --git a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
index 0ba1c2f..7171de9 100644
--- a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
@@ -15,6 +15,7 @@
 #include "src/metrics/EventMetricProducer.h"
 #include "src/dimension.h"
 #include "metrics_test_helper.h"
+#include "tests/statsd_test_util.h"
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -33,7 +34,7 @@
 namespace os {
 namespace statsd {
 
-const ConfigKey kConfigKey(0, "test");
+const ConfigKey kConfigKey(0, 12345);
 
 TEST(EventMetricProducerTest, TestNoCondition) {
     uint64_t bucketStartTimeNs = 10000000000;
@@ -41,7 +42,7 @@
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
 
     EventMetric metric;
-    metric.set_name("1");
+    metric.set_id(1);
 
     LogEvent event1(1 /*tag id*/, bucketStartTimeNs + 1);
     LogEvent event2(1 /*tag id*/, bucketStartTimeNs + 2);
@@ -64,8 +65,8 @@
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
 
     EventMetric metric;
-    metric.set_name("1");
-    metric.set_condition("SCREEN_ON");
+    metric.set_id(1);
+    metric.set_condition(StringToId("SCREEN_ON"));
 
     LogEvent event1(1, bucketStartTimeNs + 1);
     LogEvent event2(1, bucketStartTimeNs + 10);
@@ -93,10 +94,10 @@
     int conditionTagId = 2;
 
     EventMetric metric;
-    metric.set_name("1");
-    metric.set_condition("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON");
+    metric.set_id(1);
+    metric.set_condition(StringToId("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON"));
     MetricConditionLink* link = metric.add_links();
-    link->set_condition("APP_IN_BACKGROUND_PER_UID");
+    link->set_condition(StringToId("APP_IN_BACKGROUND_PER_UID"));
     *link->mutable_dimensions_in_what() = buildSimpleAtomFieldMatcher(tagId, 1);
     *link->mutable_dimensions_in_condition() = buildSimpleAtomFieldMatcher(conditionTagId, 2);
 
@@ -104,13 +105,13 @@
     EXPECT_TRUE(event1.write("111"));
     event1.init();
     ConditionKey key1;
-    key1["APP_IN_BACKGROUND_PER_UID"] = {getMockedDimensionKey(conditionTagId, 2, "111")};
+    key1[StringToId("APP_IN_BACKGROUND_PER_UID")] = {getMockedDimensionKey(conditionTagId, 2, "111")};
 
     LogEvent event2(tagId, bucketStartTimeNs + 10);
     EXPECT_TRUE(event2.write("222"));
     event2.init();
     ConditionKey key2;
-    key2["APP_IN_BACKGROUND_PER_UID"] = {getMockedDimensionKey(conditionTagId, 2, "222")};
+    key2[StringToId("APP_IN_BACKGROUND_PER_UID")] = {getMockedDimensionKey(conditionTagId, 2, "222")};
 
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     EXPECT_CALL(*wizard, query(_, key1)).WillOnce(Return(ConditionState::kFalse));
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index 359851f..cde50c1 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -15,6 +15,7 @@
 #include "src/metrics/GaugeMetricProducer.h"
 #include "logd/LogEvent.h"
 #include "metrics_test_helper.h"
+#include "tests/statsd_test_util.h"
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -34,9 +35,9 @@
 namespace os {
 namespace statsd {
 
-const ConfigKey kConfigKey(0, "test");
+const ConfigKey kConfigKey(0, 12345);
 const int tagId = 1;
-const string metricName = "test_metric";
+const int64_t metricId = 123;
 const int64_t bucketStartTimeNs = 10000000000;
 const int64_t bucketSizeNs = 60 * 1000 * 1000 * 1000LL;
 const int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
@@ -45,7 +46,7 @@
 
 TEST(GaugeMetricProducerTest, TestNoCondition) {
     GaugeMetric metric;
-    metric.set_name(metricName);
+    metric.set_id(metricId);
     metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
     metric.mutable_gauge_fields_filter()->set_include_all(false);
     auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
@@ -119,12 +120,12 @@
 
 TEST(GaugeMetricProducerTest, TestWithCondition) {
     GaugeMetric metric;
-    metric.set_name(metricName);
+    metric.set_id(metricId);
     metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
     auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
     gaugeFieldMatcher->set_field(tagId);
     gaugeFieldMatcher->add_child()->set_field(2);
-    metric.set_condition("SCREEN_ON");
+    metric.set_condition(StringToId("SCREEN_ON"));
 
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
 
@@ -186,7 +187,7 @@
     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
 
     GaugeMetric metric;
-    metric.set_name(metricName);
+    metric.set_id(metricId);
     metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
     auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
     gaugeFieldMatcher->set_field(tagId);
@@ -195,8 +196,8 @@
                                       tagId, tagId, bucketStartTimeNs, pullerManager);
 
     Alert alert;
-    alert.set_name("alert");
-    alert.set_metric_name(metricName);
+    alert.set_id(101);
+    alert.set_metric_id(metricId);
     alert.set_trigger_if_sum_gt(25);
     alert.set_number_of_buckets(2);
     sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert);
diff --git a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
index 7843ca0..6d32329 100644
--- a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
@@ -13,8 +13,9 @@
 // limitations under the License.
 
 #include "src/metrics/duration_helper/MaxDurationTracker.h"
-#include "metrics_test_helper.h"
 #include "src/condition/ConditionWizard.h"
+#include "metrics_test_helper.h"
+#include "tests/statsd_test_util.h"
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -36,7 +37,7 @@
 namespace os {
 namespace statsd {
 
-const ConfigKey kConfigKey(0, "test");
+const ConfigKey kConfigKey(0, 12345);
 
 const int TagId = 1;
 
@@ -50,12 +51,13 @@
 
     unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
     ConditionKey conditionKey1;
-    conditionKey1["condition"] = conditionKey;
+    conditionKey1[StringToId("condition")] = conditionKey;
 
     uint64_t bucketStartTimeNs = 10000000000;
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
 
-    MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, -1, false, bucketStartTimeNs,
+    int64_t metricId = 1;
+    MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, false, bucketStartTimeNs,
                                bucketSizeNs, {});
 
     tracker.noteStart(key1, true, bucketStartTimeNs, conditionKey1);
@@ -79,12 +81,13 @@
 
     unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
     ConditionKey conditionKey1;
-    conditionKey1["condition"] = conditionKey;
+    conditionKey1[StringToId("condition")] = conditionKey;
 
     uint64_t bucketStartTimeNs = 10000000000;
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
 
-    MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, -1, false, bucketStartTimeNs,
+    int64_t metricId = 1;
+    MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, false, bucketStartTimeNs,
                                bucketSizeNs, {});
 
     tracker.noteStart(key1, true, bucketStartTimeNs + 1, conditionKey1);
@@ -110,12 +113,13 @@
 
     unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
     ConditionKey conditionKey1;
-    conditionKey1["condition"] = conditionKey;
+    conditionKey1[StringToId("condition")] = conditionKey;
 
     uint64_t bucketStartTimeNs = 10000000000;
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
 
-    MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, -1, false, bucketStartTimeNs,
+    int64_t metricId = 1;
+    MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, false, bucketStartTimeNs,
                                bucketSizeNs, {});
 
     // The event starts.
@@ -141,12 +145,13 @@
 
     unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
     ConditionKey conditionKey1;
-    conditionKey1["condition"] = conditionKey;
+    conditionKey1[StringToId("condition")] = conditionKey;
 
     uint64_t bucketStartTimeNs = 10000000000;
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
 
-    MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, -1, true, bucketStartTimeNs,
+    int64_t metricId = 1;
+    MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, true, bucketStartTimeNs,
                                bucketSizeNs, {});
 
     // 2 starts
@@ -177,7 +182,7 @@
 
     ConditionKey conditionKey1;
     HashableDimensionKey eventKey = getMockedDimensionKey(TagId, 2, "maps");
-    conditionKey1["APP_BACKGROUND"] = conditionKey;
+    conditionKey1[StringToId("APP_BACKGROUND")] = conditionKey;
 
     EXPECT_CALL(*wizard, query(_, conditionKey1))  // #4
             .WillOnce(Return(ConditionState::kFalse));
@@ -189,7 +194,8 @@
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
     int64_t durationTimeNs = 2 * 1000;
 
-    MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, false, bucketStartTimeNs,
+    int64_t metricId = 1;
+    MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, false, bucketStartTimeNs,
                                bucketSizeNs, {});
     EXPECT_TRUE(tracker.mAnomalyTrackers.empty());
 
@@ -206,9 +212,10 @@
 }
 
 TEST(MaxDurationTrackerTest, TestAnomalyDetection) {
+    int64_t metricId = 1;
     Alert alert;
-    alert.set_name("alert");
-    alert.set_metric_name("metric");
+    alert.set_id(101);
+    alert.set_metric_id(metricId);
     alert.set_trigger_if_sum_gt(32 * NS_PER_SEC);
     alert.set_number_of_buckets(2);
     alert.set_refractory_period_secs(1);
@@ -216,13 +223,13 @@
     unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     ConditionKey conditionKey1;
-    conditionKey1["APP_BACKGROUND"] = conditionKey;
+    conditionKey1[StringToId("APP_BACKGROUND")] = conditionKey;
     uint64_t bucketStartTimeNs = 10 * NS_PER_SEC;
     uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
     uint64_t bucketSizeNs = 30 * NS_PER_SEC;
 
     sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
-    MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, -1, true, bucketStartTimeNs,
+    MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, true, bucketStartTimeNs,
                                bucketSizeNs, {anomalyTracker});
 
     tracker.noteStart(key1, true, eventStartTimeNs, conditionKey1);
diff --git a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
index 550b059..d34c85b 100644
--- a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
@@ -13,8 +13,9 @@
 // limitations under the License.
 
 #include "src/metrics/duration_helper/OringDurationTracker.h"
-#include "metrics_test_helper.h"
 #include "src/condition/ConditionWizard.h"
+#include "metrics_test_helper.h"
+#include "tests/statsd_test_util.h"
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -34,8 +35,9 @@
 namespace os {
 namespace statsd {
 
-const ConfigKey kConfigKey(0, "test");
+const ConfigKey kConfigKey(0, 12345);
 const int TagId = 1;
+const int64_t metricId = 123;
 const HashableDimensionKey eventKey = getMockedDimensionKey(TagId, 0, "event");
 
 const std::vector<HashableDimensionKey> kConditionKey1 = {getMockedDimensionKey(TagId, 1, "maps")};
@@ -46,7 +48,7 @@
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
 
     ConditionKey key1;
-    key1["APP_BACKGROUND"] = kConditionKey1;
+    key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
 
     unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
 
@@ -55,7 +57,7 @@
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
     uint64_t durationTimeNs = 2 * 1000;
 
-    OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, false,
+    OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, false,
                                  bucketStartTimeNs, bucketSizeNs, {});
 
     tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
@@ -75,7 +77,7 @@
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
 
     ConditionKey key1;
-    key1["APP_BACKGROUND"] = kConditionKey1;
+    key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
 
     unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
 
@@ -83,7 +85,7 @@
     uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
 
-    OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
+    OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, true, bucketStartTimeNs,
                                  bucketSizeNs, {});
 
     tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
@@ -102,7 +104,7 @@
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
 
     ConditionKey key1;
-    key1["APP_BACKGROUND"] = kConditionKey1;
+    key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
 
     unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
 
@@ -110,7 +112,7 @@
     uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
 
-    OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
+    OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, true, bucketStartTimeNs,
                                  bucketSizeNs, {});
 
     tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
@@ -128,7 +130,7 @@
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
 
     ConditionKey key1;
-    key1["APP_BACKGROUND"] = kConditionKey1;
+    key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
 
     unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
 
@@ -137,7 +139,7 @@
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
     uint64_t durationTimeNs = 2 * 1000;
 
-    OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
+    OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, true, bucketStartTimeNs,
                                  bucketSizeNs, {});
 
     tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
@@ -163,7 +165,7 @@
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
 
     ConditionKey key1;
-    key1["APP_BACKGROUND"] = kConditionKey1;
+    key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
 
     EXPECT_CALL(*wizard, query(_, key1))  // #4
             .WillOnce(Return(ConditionState::kFalse));
@@ -175,7 +177,7 @@
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
     uint64_t durationTimeNs = 2 * 1000;
 
-    OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, false,
+    OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, false,
                                  bucketStartTimeNs, bucketSizeNs, {});
 
     tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
@@ -194,7 +196,7 @@
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
 
     ConditionKey key1;
-    key1["APP_BACKGROUND"] = kConditionKey1;
+    key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
 
     EXPECT_CALL(*wizard, query(_, key1))
             .Times(2)
@@ -208,7 +210,7 @@
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
     uint64_t durationTimeNs = 2 * 1000;
 
-    OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, false,
+    OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, false,
                                  bucketStartTimeNs, bucketSizeNs, {});
 
     tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
@@ -229,7 +231,7 @@
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
 
     ConditionKey key1;
-    key1["APP_BACKGROUND"] = kConditionKey1;
+    key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
 
     EXPECT_CALL(*wizard, query(_, key1))  // #4
             .WillOnce(Return(ConditionState::kFalse));
@@ -240,7 +242,7 @@
     uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
 
-    OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
+    OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, true, bucketStartTimeNs,
                                  bucketSizeNs, {});
 
     tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
@@ -260,8 +262,8 @@
 
 TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp) {
     Alert alert;
-    alert.set_name("alert");
-    alert.set_metric_name("1");
+    alert.set_id(101);
+    alert.set_metric_id(1);
     alert.set_trigger_if_sum_gt(40 * NS_PER_SEC);
     alert.set_number_of_buckets(2);
     alert.set_refractory_period_secs(1);
@@ -269,13 +271,13 @@
     unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     ConditionKey key1;
-    key1["APP_BACKGROUND"] = kConditionKey1;
+    key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
     uint64_t bucketStartTimeNs = 10 * NS_PER_SEC;
     uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
     uint64_t bucketSizeNs = 30 * NS_PER_SEC;
 
     sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
-    OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
+    OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, true, bucketStartTimeNs,
                                  bucketSizeNs, {anomalyTracker});
 
     // Nothing in the past bucket.
@@ -322,8 +324,8 @@
 
 TEST(OringDurationTrackerTest, TestAnomalyDetection) {
     Alert alert;
-    alert.set_name("alert");
-    alert.set_metric_name("1");
+    alert.set_id(101);
+    alert.set_metric_id(1);
     alert.set_trigger_if_sum_gt(40 * NS_PER_SEC);
     alert.set_number_of_buckets(2);
     alert.set_refractory_period_secs(1);
@@ -331,13 +333,13 @@
     unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     ConditionKey key1;
-    key1["APP_BACKGROUND"] = kConditionKey1;
+    key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
     uint64_t bucketStartTimeNs = 10 * NS_PER_SEC;
     uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
     uint64_t bucketSizeNs = 30 * NS_PER_SEC;
 
     sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
-    OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true /*nesting*/,
+    OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, true /*nesting*/,
                                  bucketStartTimeNs, bucketSizeNs, {anomalyTracker});
 
     tracker.noteStart(DEFAULT_DIMENSION_KEY, true, eventStartTimeNs, key1);
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 12bc834..acbfbba 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -14,6 +14,7 @@
 
 #include "src/metrics/ValueMetricProducer.h"
 #include "metrics_test_helper.h"
+#include "tests/statsd_test_util.h"
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -34,9 +35,9 @@
 namespace os {
 namespace statsd {
 
-const ConfigKey kConfigKey(0, "test");
+const ConfigKey kConfigKey(0, 12345);
 const int tagId = 1;
-const string metricName = "test_metric";
+const int64_t metricId = 123;
 const int64_t bucketStartTimeNs = 10000000000;
 const int64_t bucketSizeNs = 60 * 1000 * 1000 * 1000LL;
 const int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
@@ -48,7 +49,7 @@
  */
 TEST(ValueMetricProducerTest, TestNonDimensionalEvents) {
     ValueMetric metric;
-    metric.set_name(metricName);
+    metric.set_id(metricId);
     metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
     metric.set_value_field(2);
 
@@ -124,10 +125,10 @@
  */
 TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) {
     ValueMetric metric;
-    metric.set_name(metricName);
+    metric.set_id(metricId);
     metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
     metric.set_value_field(2);
-    metric.set_condition("SCREEN_ON");
+    metric.set_condition(StringToId("SCREEN_ON"));
 
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     shared_ptr<MockStatsPullerManager> pullerManager =
@@ -200,7 +201,7 @@
 
 TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) {
     ValueMetric metric;
-    metric.set_name(metricName);
+    metric.set_id(metricId);
     metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
     metric.set_value_field(2);
 
@@ -240,14 +241,14 @@
 
 TEST(ValueMetricProducerTest, TestAnomalyDetection) {
     Alert alert;
-    alert.set_name("alert");
-    alert.set_metric_name(metricName);
+    alert.set_id(101);
+    alert.set_metric_id(metricId);
     alert.set_trigger_if_sum_gt(130);
     alert.set_number_of_buckets(2);
     alert.set_refractory_period_secs(3);
 
     ValueMetric metric;
-    metric.set_name(metricName);
+    metric.set_id(metricId);
     metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
     metric.set_value_field(2);
 
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index 39e366f..939dc1f 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -22,7 +22,7 @@
 AtomMatcher CreateWakelockStateChangedAtomMatcher(const string& name,
                                                   WakelockStateChanged::State state) {
     AtomMatcher atom_matcher;
-    atom_matcher.set_name(name);
+    atom_matcher.set_id(StringToId(name));
     auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
     simple_atom_matcher->set_atom_id(android::util::WAKELOCK_STATE_CHANGED);
     auto field_value_matcher = simple_atom_matcher->add_field_value_matcher();
@@ -42,7 +42,7 @@
 AtomMatcher CreateScreenStateChangedAtomMatcher(
     const string& name, ScreenStateChanged::State state) {
     AtomMatcher atom_matcher;
-    atom_matcher.set_name(name);
+    atom_matcher.set_id(StringToId(name));
     auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
     simple_atom_matcher->set_atom_id(android::util::SCREEN_STATE_CHANGED);
     auto field_value_matcher = simple_atom_matcher->add_field_value_matcher();
@@ -62,7 +62,7 @@
 AtomMatcher CreateSyncStateChangedAtomMatcher(
     const string& name, SyncStateChanged::State state) {
     AtomMatcher atom_matcher;
-    atom_matcher.set_name(name);
+    atom_matcher.set_id(StringToId(name));
     auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
     simple_atom_matcher->set_atom_id(android::util::SYNC_STATE_CHANGED);
     auto field_value_matcher = simple_atom_matcher->add_field_value_matcher();
@@ -82,7 +82,7 @@
 AtomMatcher CreateActivityForegroundStateChangedAtomMatcher(
     const string& name, ActivityForegroundStateChanged::Activity activity) {
     AtomMatcher atom_matcher;
-    atom_matcher.set_name(name);
+    atom_matcher.set_id(StringToId(name));
     auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
     simple_atom_matcher->set_atom_id(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED);
     auto field_value_matcher = simple_atom_matcher->add_field_value_matcher();
@@ -104,7 +104,7 @@
 AtomMatcher CreateProcessLifeCycleStateChangedAtomMatcher(
     const string& name, ProcessLifeCycleStateChanged::Event event) {
     AtomMatcher atom_matcher;
-    atom_matcher.set_name(name);
+    atom_matcher.set_id(StringToId(name));
     auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
     simple_atom_matcher->set_atom_id(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
     auto field_value_matcher = simple_atom_matcher->add_field_value_matcher();
@@ -121,47 +121,47 @@
 
 Predicate CreateScreenIsOnPredicate() {
     Predicate predicate;
-    predicate.set_name("ScreenIsOn");
-    predicate.mutable_simple_predicate()->set_start("ScreenTurnedOn");
-    predicate.mutable_simple_predicate()->set_stop("ScreenTurnedOff");
+    predicate.set_id(StringToId("ScreenIsOn"));
+    predicate.mutable_simple_predicate()->set_start(StringToId("ScreenTurnedOn"));
+    predicate.mutable_simple_predicate()->set_stop(StringToId("ScreenTurnedOff"));
     return predicate;
 }
 
 Predicate CreateScreenIsOffPredicate() {
     Predicate predicate;
-    predicate.set_name("ScreenIsOff");
-    predicate.mutable_simple_predicate()->set_start("ScreenTurnedOff");
-    predicate.mutable_simple_predicate()->set_stop("ScreenTurnedOn");
+    predicate.set_id(StringToId("ScreenIsOff"));
+    predicate.mutable_simple_predicate()->set_start(StringToId("ScreenTurnedOff"));
+    predicate.mutable_simple_predicate()->set_stop(StringToId("ScreenTurnedOn"));
     return predicate;
 }
 
 Predicate CreateHoldingWakelockPredicate() {
     Predicate predicate;
-    predicate.set_name("HoldingWakelock");
-    predicate.mutable_simple_predicate()->set_start("AcquireWakelock");
-    predicate.mutable_simple_predicate()->set_stop("ReleaseWakelock");
+    predicate.set_id(StringToId("HoldingWakelock"));
+    predicate.mutable_simple_predicate()->set_start(StringToId("AcquireWakelock"));
+    predicate.mutable_simple_predicate()->set_stop(StringToId("ReleaseWakelock"));
     return predicate;
 }
 
 Predicate CreateIsSyncingPredicate() {
     Predicate predicate;
-    predicate.set_name("IsSyncing");
-    predicate.mutable_simple_predicate()->set_start("SyncStart");
-    predicate.mutable_simple_predicate()->set_stop("SyncEnd");
+    predicate.set_id(StringToId("IsSyncing"));
+    predicate.mutable_simple_predicate()->set_start(StringToId("SyncStart"));
+    predicate.mutable_simple_predicate()->set_stop(StringToId("SyncEnd"));
     return predicate;
 }
 
 Predicate CreateIsInBackgroundPredicate() {
     Predicate predicate;
-    predicate.set_name("IsInBackground");
-    predicate.mutable_simple_predicate()->set_start("MoveToBackground");
-    predicate.mutable_simple_predicate()->set_stop("MoveToForeground");
+    predicate.set_id(StringToId("IsInBackground"));
+    predicate.mutable_simple_predicate()->set_start(StringToId("MoveToBackground"));
+    predicate.mutable_simple_predicate()->set_stop(StringToId("MoveToForeground"));
     return predicate;
 }
 
 void addPredicateToPredicateCombination(const Predicate& predicate,
                                         Predicate* combinationPredicate) {
-    combinationPredicate->mutable_combination()->add_predicate(predicate.name());
+    combinationPredicate->mutable_combination()->add_predicate(predicate.id());
 }
 
 FieldMatcher CreateAttributionUidDimensions(const int atomId,
@@ -316,6 +316,9 @@
             });
 }
 
+int64_t StringToId(const string& str) {
+    return static_cast<int64_t>(std::hash<std::string>()(str));
+}
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h
index 282e1b2..5e19da0 100644
--- a/cmds/statsd/tests/statsd_test_util.h
+++ b/cmds/statsd/tests/statsd_test_util.h
@@ -121,6 +121,8 @@
 // Util function to sort the log events by timestamp.
 void sortLogEventsByTimestamp(std::vector<std::unique_ptr<LogEvent>> *events);
 
+int64_t StringToId(const string& str);
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java b/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java
index 9294681..93dba71 100644
--- a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java
+++ b/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java
@@ -26,7 +26,7 @@
         sb.append("ConfigKey: ");
         if (reports.hasConfigKey()) {
             com.android.os.StatsLog.ConfigMetricsReportList.ConfigKey key = reports.getConfigKey();
-            sb.append("\tuid: ").append(key.getUid()).append(" name: ").append(key.getName())
+            sb.append("\tuid: ").append(key.getUid()).append(" name: ").append(key.getId())
                     .append("\n");
         }
 
@@ -34,7 +34,7 @@
             sb.append("StatsLogReport size: ").append(report.getMetricsCount()).append("\n");
             for (StatsLog.StatsLogReport log : report.getMetricsList()) {
                 sb.append("\n\n");
-                sb.append("metric id: ").append(log.getMetricName()).append("\n");
+                sb.append("metric id: ").append(log.getMetricId()).append("\n");
                 sb.append("start time:").append(getDateStr(log.getStartReportNanos())).append("\n");
                 sb.append("end time:").append(getDateStr(log.getEndReportNanos())).append("\n");
 
diff --git a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java b/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java
index 137fd4d..119d6f5 100644
--- a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java
+++ b/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java
@@ -34,6 +34,8 @@
 
 public class MainActivity extends Activity {
     private final static String TAG = "StatsdDogfood";
+    private final static long CONFIG_ID = 987654321;
+
 
     final int[] mUids = {11111111, 2222222};
     StatsManager mStatsManager;
@@ -163,7 +165,7 @@
                     return;
                 }
                 if (mStatsManager != null) {
-                    byte[] data = mStatsManager.getData("fake");
+                    byte[] data = mStatsManager.getData(CONFIG_ID);
                     if (data != null) {
                         displayData(data);
                     } else {
@@ -186,7 +188,7 @@
                     byte[] config = new byte[inputStream.available()];
                     inputStream.read(config);
                     if (mStatsManager != null) {
-                        if (mStatsManager.addConfiguration("fake",
+                        if (mStatsManager.addConfiguration(CONFIG_ID,
                                 config, getPackageName(), MainActivity.this.getClass().getName())) {
                             Toast.makeText(
                                     MainActivity.this, "Config pushed", Toast.LENGTH_LONG).show();
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java
index f516477..4bd2844 100644
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java
@@ -41,7 +41,7 @@
  * Creates StatsdConfig protos for loadtesting.
  */
 public class ConfigFactory {
-    public static final String CONFIG_NAME = "LOADTEST";
+    public static final long CONFIG_ID = 123456789;
 
     private static final String TAG = "loadtest.ConfigFactory";
 
@@ -86,7 +86,7 @@
                           boolean includeDuration, boolean includeEvent, boolean includeValue,
                           boolean includeGauge) {
         StatsdConfig.Builder config = StatsdConfig.newBuilder()
-            .setName(CONFIG_NAME);
+            .setId(CONFIG_ID);
         if (placebo) {
           replication = 0;  // Config will be empty, aside from a name.
         }
@@ -160,7 +160,7 @@
      */
     private void addEventMetric(EventMetric template, int suffix, StatsdConfig.Builder config) {
         EventMetric.Builder metric = template.toBuilder()
-            .setName(template.getName() + suffix)
+            .setId(template.getId() + suffix)
             .setWhat(template.getWhat() + suffix);
         if (template.hasCondition()) {
             metric.setCondition(template.getCondition() + suffix);
@@ -186,7 +186,7 @@
     private void addCountMetric(CountMetric template, int suffix, long bucketMillis,
         StatsdConfig.Builder config) {
         CountMetric.Builder metric = template.toBuilder()
-            .setName(template.getName() + suffix)
+            .setId(template.getId() + suffix)
             .setWhat(template.getWhat() + suffix);
         if (template.hasCondition()) {
             metric.setCondition(template.getCondition() + suffix);
@@ -207,7 +207,7 @@
     private void addDurationMetric(DurationMetric template, int suffix, long bucketMillis,
         StatsdConfig.Builder config) {
         DurationMetric.Builder metric = template.toBuilder()
-            .setName(template.getName() + suffix)
+            .setId(template.getId() + suffix)
             .setWhat(template.getWhat() + suffix);
         if (template.hasCondition()) {
             metric.setCondition(template.getCondition() + suffix);
@@ -228,7 +228,7 @@
     private void addGaugeMetric(GaugeMetric template, int suffix, long bucketMillis,
         StatsdConfig.Builder config) {
         GaugeMetric.Builder metric = template.toBuilder()
-            .setName(template.getName() + suffix)
+            .setId(template.getId() + suffix)
             .setWhat(template.getWhat() + suffix);
         if (template.hasCondition()) {
             metric.setCondition(template.getCondition() + suffix);
@@ -249,7 +249,7 @@
     private void addValueMetric(ValueMetric template, int suffix, long bucketMillis,
         StatsdConfig.Builder config) {
         ValueMetric.Builder metric = template.toBuilder()
-            .setName(template.getName() + suffix)
+            .setId(template.getId() + suffix)
             .setWhat(template.getWhat() + suffix);
         if (template.hasCondition()) {
             metric.setCondition(template.getCondition() + suffix);
@@ -269,11 +269,11 @@
      */
     private void addPredicate(Predicate template, int suffix, StatsdConfig.Builder config) {
         Predicate.Builder predicate = template.toBuilder()
-            .setName(template.getName() + suffix);
+            .setId(template.getId() + suffix);
         if (template.hasCombination()) {
             Predicate.Combination.Builder cb = template.getCombination().toBuilder()
                 .clearPredicate();
-            for (String child : template.getCombination().getPredicateList()) {
+            for (long child : template.getCombination().getPredicateList()) {
                 cb.addPredicate(child + suffix);
             }
             predicate.setCombination(cb.build());
@@ -296,11 +296,11 @@
      */
     private void addMatcher(AtomMatcher template, int suffix, StatsdConfig.Builder config) {
         AtomMatcher.Builder matcher = template.toBuilder()
-            .setName(template.getName() + suffix);
+            .setId(template.getId() + suffix);
         if (template.hasCombination()) {
             AtomMatcher.Combination.Builder cb = template.getCombination().toBuilder()
                 .clearMatcher();
-            for (String child : template.getCombination().getMatcherList()) {
+            for (long child : template.getCombination().getMatcherList()) {
                 cb.addMatcher(child + suffix);
             }
             matcher.setCombination(cb);
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java
index ba43d57..19087d8 100644
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java
@@ -26,7 +26,7 @@
         sb.append("ConfigKey: ");
         if (reports.hasConfigKey()) {
             com.android.os.StatsLog.ConfigMetricsReportList.ConfigKey key = reports.getConfigKey();
-            sb.append("\tuid: ").append(key.getUid()).append(" name: ").append(key.getName())
+            sb.append("\tuid: ").append(key.getUid()).append(" id: ").append(key.getId())
                     .append("\n");
         }
 
@@ -34,7 +34,7 @@
             sb.append("StatsLogReport size: ").append(report.getMetricsCount()).append("\n");
             for (StatsLog.StatsLogReport log : report.getMetricsList()) {
                 sb.append("\n\n");
-                sb.append("metric id: ").append(log.getMetricName()).append("\n");
+                sb.append("metric id: ").append(log.getMetricId()).append("\n");
                 sb.append("start time:").append(getDateStr(log.getStartReportNanos())).append("\n");
                 sb.append("end time:").append(getDateStr(log.getEndReportNanos())).append("\n");
 
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java
index 83f4b7b..86da16c 100644
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java
@@ -294,7 +294,7 @@
             return null;
         }
         if (mStatsManager != null) {
-            byte[] data = mStatsManager.getData(ConfigFactory.CONFIG_NAME);
+            byte[] data = mStatsManager.getData(ConfigFactory.CONFIG_ID);
             if (data != null) {
                 ConfigMetricsReportList reports = null;
                 try {
@@ -453,7 +453,7 @@
         // TODO: Clear all configs instead of specific ones.
         if (mStatsManager != null) {
             if (mStarted) {
-                if (!mStatsManager.removeConfiguration(ConfigFactory.CONFIG_NAME)) {
+                if (!mStatsManager.removeConfiguration(ConfigFactory.CONFIG_ID)) {
                     Log.d(TAG, "Removed loadtest statsd configs.");
                 } else {
                     Log.d(TAG, "Failed to remove loadtest configs.");
@@ -464,7 +464,7 @@
 
     private boolean setConfig(byte[] config) {
       if (mStatsManager != null) {
-            if (mStatsManager.addConfiguration(ConfigFactory.CONFIG_NAME,
+            if (mStatsManager.addConfiguration(ConfigFactory.CONFIG_ID,
                 config, getPackageName(), LoadtestActivity.this.getClass().getName())) {
                 Log.d(TAG, "Config pushed to statsd");
                 return true;
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ValidationRecorder.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ValidationRecorder.java
index 4b614aa..d122654 100644
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ValidationRecorder.java
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ValidationRecorder.java
@@ -59,18 +59,8 @@
             Log.d(TAG, "GOT DATA");
             for (ConfigMetricsReport report : reports) {
                 for (StatsLogReport logReport : report.getMetricsList()) {
-                    if (!logReport.hasMetricName()) {
+                    if (!logReport.hasMetricId()) {
                         Log.e(TAG, "Metric missing name.");
-                        continue;
-                    }
-                    String metricName = logReport.getMetricName();
-                    if (metricName.startsWith("EVENT_BATTERY_LEVEL_CHANGES_WHILE_SCREEN_IS_ON_")) {
-                        validateEventBatteryLevelChangesWhileScreenIsOn(logReport);
-                        continue;
-                    }
-                    if (metricName.startsWith("EVENT_BATTERY_LEVEL_CHANGES_")) {
-                        validateEventBatteryLevelChanges(logReport);
-                        continue;
                     }
                 }
             }
@@ -78,7 +68,7 @@
     }
 
     private void validateEventBatteryLevelChanges(StatsLogReport logReport) {
-        Log.d(TAG, "Validating " + logReport.getMetricName());
+        Log.d(TAG, "Validating " + logReport.getMetricId());
         if (logReport.hasEventMetrics()) {
             Log.d(TAG, "Num events captured: " + logReport.getEventMetrics().getDataCount());
             for (EventMetricData data : logReport.getEventMetrics().getDataList()) {
@@ -90,6 +80,6 @@
     }
 
     private void validateEventBatteryLevelChangesWhileScreenIsOn(StatsLogReport logReport) {
-        Log.d(TAG, "Validating " + logReport.getMetricName());
+        Log.d(TAG, "Validating " + logReport.getMetricId());
     }
 }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 1adae7a..847f91b 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -60,6 +60,7 @@
 import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.os.WorkSource;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.DisplayMetrics;
@@ -3911,10 +3912,10 @@
     /**
      * @hide
      */
-    public static void noteWakeupAlarm(PendingIntent ps, int sourceUid, String sourcePkg,
-            String tag) {
+    public static void noteWakeupAlarm(PendingIntent ps, WorkSource workSource, int sourceUid,
+            String sourcePkg, String tag) {
         try {
-            getService().noteWakeupAlarm((ps != null) ? ps.getTarget() : null,
+            getService().noteWakeupAlarm((ps != null) ? ps.getTarget() : null, workSource,
                     sourceUid, sourcePkg, tag);
         } catch (RemoteException ex) {
         }
@@ -3923,19 +3924,24 @@
     /**
      * @hide
      */
-    public static void noteAlarmStart(PendingIntent ps, int sourceUid, String tag) {
+    public static void noteAlarmStart(PendingIntent ps, WorkSource workSource, int sourceUid,
+            String tag) {
         try {
-            getService().noteAlarmStart((ps != null) ? ps.getTarget() : null, sourceUid, tag);
+            getService().noteAlarmStart((ps != null) ? ps.getTarget() : null, workSource,
+                    sourceUid, tag);
         } catch (RemoteException ex) {
         }
     }
 
+
     /**
      * @hide
      */
-    public static void noteAlarmFinish(PendingIntent ps, int sourceUid, String tag) {
+    public static void noteAlarmFinish(PendingIntent ps, WorkSource workSource, int sourceUid,
+            String tag) {
         try {
-            getService().noteAlarmFinish((ps != null) ? ps.getTarget() : null, sourceUid, tag);
+            getService().noteAlarmFinish((ps != null) ? ps.getTarget() : null, workSource,
+                    sourceUid, tag);
         } catch (RemoteException ex) {
         }
     }
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index c09403c..4c558f3 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -75,20 +75,20 @@
      */
     static public void noteWakeupAlarm(PendingIntent ps, int sourceUid, String sourcePkg,
             String tag) {
-        ActivityManager.noteWakeupAlarm(ps, sourceUid, sourcePkg, tag);
+        ActivityManager.noteWakeupAlarm(ps, null, sourceUid, sourcePkg, tag);
     }
 
     /**
      * @deprecated use ActivityManager.noteAlarmStart instead.
      */
     static public void noteAlarmStart(PendingIntent ps, int sourceUid, String tag) {
-        ActivityManager.noteAlarmStart(ps, sourceUid, tag);
+        ActivityManager.noteAlarmStart(ps, null, sourceUid, tag);
     }
 
     /**
      * @deprecated use ActivityManager.noteAlarmFinish instead.
      */
     static public void noteAlarmFinish(PendingIntent ps, int sourceUid, String tag) {
-        ActivityManager.noteAlarmFinish(ps, sourceUid, tag);
+        ActivityManager.noteAlarmFinish(ps, null, sourceUid, tag);
     }
 }
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 1278f75..a9e633f 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -63,6 +63,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.PersistableBundle;
 import android.os.StrictMode;
+import android.os.WorkSource;
 import android.service.voice.IVoiceInteractionSession;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.os.IResultReceiver;
@@ -198,7 +199,7 @@
     void enterSafeMode();
     boolean startNextMatchingActivity(in IBinder callingActivity,
             in Intent intent, in Bundle options);
-    void noteWakeupAlarm(in IIntentSender sender, int sourceUid,
+    void noteWakeupAlarm(in IIntentSender sender, in WorkSource workSource, int sourceUid,
             in String sourcePkg, in String tag);
     void removeContentProvider(in IBinder connection, boolean stable);
     void setRequestedOrientation(in IBinder token, int requestedOrientation);
@@ -468,8 +469,8 @@
     void dumpHeapFinished(in String path);
     void setVoiceKeepAwake(in IVoiceInteractionSession session, boolean keepAwake);
     void updateLockTaskPackages(int userId, in String[] packages);
-    void noteAlarmStart(in IIntentSender sender, int sourceUid, in String tag);
-    void noteAlarmFinish(in IIntentSender sender, int sourceUid, in String tag);
+    void noteAlarmStart(in IIntentSender sender, in WorkSource workSource, int sourceUid, in String tag);
+    void noteAlarmFinish(in IIntentSender sender, in WorkSource workSource, int sourceUid, in String tag);
     int getPackageProcessState(in String packageName, in String callingPackage);
     oneway void showLockTaskEscapeMessage(in IBinder token);
     void updateDeviceOwner(in String packageName);
diff --git a/core/java/android/net/NetworkWatchlistManager.java b/core/java/android/net/NetworkWatchlistManager.java
index 42e43c8..5425bf5 100644
--- a/core/java/android/net/NetworkWatchlistManager.java
+++ b/core/java/android/net/NetworkWatchlistManager.java
@@ -59,8 +59,8 @@
     /**
      * Report network watchlist records if necessary.
      *
-     * Watchlist report process will run summarize records into a single report, then the
-     * report will be processed by differential privacy framework and store it on disk.
+     * Watchlist report process will summarize records into a single report, then the
+     * report will be processed by differential privacy framework and stored on disk.
      *
      * @hide
      */
@@ -72,4 +72,18 @@
             e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Reload network watchlist.
+     *
+     * @hide
+     */
+    public void reloadWatchlist() {
+        try {
+            mNetworkWatchlistManager.reloadWatchlist();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Unable to reload watchlist");
+            e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 1e847c5..d4d74f4 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -180,6 +180,11 @@
     public static final int FOREGROUND_SERVICE = 22;
 
     /**
+     * A constant indicating an aggregate wifi multicast timer
+     */
+     public static final int WIFI_AGGREGATE_MULTICAST_ENABLED = 23;
+
+    /**
      * Include all of the data in the stats, including previously saved data.
      */
     public static final int STATS_SINCE_CHARGED = 0;
@@ -2334,6 +2339,22 @@
     };
 
     /**
+     * Returns total time for WiFi Multicast Wakelock timer.
+     * Note that this may be different from the sum of per uid timer values.
+     *
+     *  {@hide}
+     */
+    public abstract long getWifiMulticastWakelockTime(long elapsedRealtimeUs, int which);
+
+    /**
+     * Returns total time for WiFi Multicast Wakelock timer
+     * Note that this may be different from the sum of per uid timer values.
+     *
+     * {@hide}
+     */
+    public abstract int getWifiMulticastWakelockCount(int which);
+
+    /**
      * Returns the time in microseconds that wifi has been on while the device was
      * running on battery.
      *
@@ -3442,16 +3463,13 @@
                 screenDozeTime / 1000);
 
 
-        // Calculate both wakelock and wifi multicast wakelock times across all uids.
+        // Calculate wakelock times across all uids.
         long fullWakeLockTimeTotal = 0;
         long partialWakeLockTimeTotal = 0;
-        long multicastWakeLockTimeTotalMicros = 0;
-        int multicastWakeLockCountTotal = 0;
 
         for (int iu = 0; iu < NU; iu++) {
             final Uid u = uidStats.valueAt(iu);
 
-            // First calculating the wakelock stats
             final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelocks
                     = u.getWakelockStats();
             for (int iw=wakelocks.size()-1; iw>=0; iw--) {
@@ -3469,13 +3487,6 @@
                         rawRealtime, which);
                 }
             }
-
-            // Now calculating the wifi multicast wakelock stats
-            final Timer mcTimer = u.getMulticastWakelockStats();
-            if (mcTimer != null) {
-                multicastWakeLockTimeTotalMicros += mcTimer.getTotalTimeLocked(rawRealtime, which);
-                multicastWakeLockCountTotal += mcTimer.getCountLocked(which);
-            }
         }
 
         // Dump network stats
@@ -3592,6 +3603,9 @@
         dumpLine(pw, 0 /* uid */, category, WIFI_SIGNAL_STRENGTH_COUNT_DATA, args);
 
         // Dump Multicast total stats
+        final long multicastWakeLockTimeTotalMicros =
+                getWifiMulticastWakelockTime(rawRealtime, which);
+        final int multicastWakeLockCountTotal = getWifiMulticastWakelockCount(which);
         dumpLine(pw, 0 /* uid */, category, WIFI_MULTICAST_TOTAL_DATA,
                 multicastWakeLockTimeTotalMicros / 1000,
                 multicastWakeLockCountTotal);
@@ -4456,18 +4470,15 @@
             pw.print("  Connectivity changes: "); pw.println(connChanges);
         }
 
-        // Calculate both wakelock and wifi multicast wakelock times across all uids.
+        // Calculate wakelock times across all uids.
         long fullWakeLockTimeTotalMicros = 0;
         long partialWakeLockTimeTotalMicros = 0;
-        long multicastWakeLockTimeTotalMicros = 0;
-        int multicastWakeLockCountTotal = 0;
 
         final ArrayList<TimerEntry> timers = new ArrayList<>();
 
         for (int iu = 0; iu < NU; iu++) {
             final Uid u = uidStats.valueAt(iu);
 
-            // First calculate wakelock statistics
             final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelocks
                     = u.getWakelockStats();
             for (int iw=wakelocks.size()-1; iw>=0; iw--) {
@@ -4495,13 +4506,6 @@
                     }
                 }
             }
-
-            // Next calculate wifi multicast wakelock statistics
-            final Timer mcTimer = u.getMulticastWakelockStats();
-            if (mcTimer != null) {
-                multicastWakeLockTimeTotalMicros += mcTimer.getTotalTimeLocked(rawRealtime, which);
-                multicastWakeLockCountTotal += mcTimer.getCountLocked(which);
-            }
         }
 
         final long mobileRxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
@@ -4531,6 +4535,9 @@
             pw.println(sb.toString());
         }
 
+        final long multicastWakeLockTimeTotalMicros =
+                getWifiMulticastWakelockTime(rawRealtime, which);
+        final int multicastWakeLockCountTotal = getWifiMulticastWakelockCount(which);
         if (multicastWakeLockTimeTotalMicros != 0) {
             sb.setLength(0);
             sb.append(prefix);
@@ -7051,6 +7058,28 @@
                     }
                 }
             }
+
+            for (int procState = 0; procState < Uid.NUM_PROCESS_STATE; ++procState) {
+                final long[] timesMs = u.getCpuFreqTimes(which, procState);
+                if (timesMs != null && timesMs.length == cpuFreqs.length) {
+                    long[] screenOffTimesMs = u.getScreenOffCpuFreqTimes(which, procState);
+                    if (screenOffTimesMs == null) {
+                        screenOffTimesMs = new long[timesMs.length];
+                    }
+                    final long procToken = proto.start(UidProto.Cpu.BY_PROCESS_STATE);
+                    proto.write(UidProto.Cpu.ByProcessState.PROCESS_STATE, procState);
+                    for (int ic = 0; ic < timesMs.length; ++ic) {
+                        long cToken = proto.start(UidProto.Cpu.ByProcessState.BY_FREQUENCY);
+                        proto.write(UidProto.Cpu.ByFrequency.FREQUENCY_INDEX, ic + 1);
+                        proto.write(UidProto.Cpu.ByFrequency.TOTAL_DURATION_MS,
+                                timesMs[ic]);
+                        proto.write(UidProto.Cpu.ByFrequency.SCREEN_OFF_DURATION_MS,
+                                screenOffTimesMs[ic]);
+                        proto.end(cToken);
+                    }
+                    proto.end(procToken);
+                }
+            }
             proto.end(cpuToken);
 
             // Flashlight (FLASHLIGHT_DATA)
@@ -7535,22 +7564,9 @@
         proto.end(mToken);
 
         // Wifi multicast wakelock total stats (WIFI_MULTICAST_WAKELOCK_TOTAL_DATA)
-        // Calculate multicast wakelock stats across all uids.
-        long multicastWakeLockTimeTotalUs = 0;
-        int multicastWakeLockCountTotal = 0;
-
-        for (int iu = 0; iu < uidStats.size(); iu++) {
-            final Uid u = uidStats.valueAt(iu);
-
-            final Timer mcTimer = u.getMulticastWakelockStats();
-
-            if (mcTimer != null) {
-                multicastWakeLockTimeTotalUs +=
-                        mcTimer.getTotalTimeLocked(rawRealtimeUs, which);
-                multicastWakeLockCountTotal += mcTimer.getCountLocked(which);
-            }
-        }
-
+        final long multicastWakeLockTimeTotalUs =
+                getWifiMulticastWakelockTime(rawRealtimeUs, which);
+        final int multicastWakeLockCountTotal = getWifiMulticastWakelockCount(which);
         final long wmctToken = proto.start(SystemProto.WIFI_MULTICAST_WAKELOCK_TOTAL);
         proto.write(SystemProto.WifiMulticastWakelockTotal.DURATION_MS,
                 multicastWakeLockTimeTotalUs / 1000);
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index 3ca1005..5c5e351 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -388,6 +388,8 @@
      * The runnable will be run on the thread to which this handler is attached.
      *
      * @param r The Runnable that will be executed.
+     * @param token An instance which can be used to cancel {@code r} via
+     *         {@link #removeCallbacksAndMessages}.
      * @param uptimeMillis The absolute time at which the callback should run,
      *         using the {@link android.os.SystemClock#uptimeMillis} time-base.
      * 
@@ -430,6 +432,32 @@
     }
     
     /**
+     * Causes the Runnable r to be added to the message queue, to be run
+     * after the specified amount of time elapses.
+     * The runnable will be run on the thread to which this handler
+     * is attached.
+     * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
+     * Time spent in deep sleep will add an additional delay to execution.
+     *
+     * @param r The Runnable that will be executed.
+     * @param token An instance which can be used to cancel {@code r} via
+     *         {@link #removeCallbacksAndMessages}.
+     * @param delayMillis The delay (in milliseconds) until the Runnable
+     *        will be executed.
+     *
+     * @return Returns true if the Runnable was successfully placed in to the
+     *         message queue.  Returns false on failure, usually because the
+     *         looper processing the message queue is exiting.  Note that a
+     *         result of true does not mean the Runnable will be processed --
+     *         if the looper is quit before the delivery time of the message
+     *         occurs then the message will be dropped.
+     */
+    public final boolean postDelayed(Runnable r, Object token, long delayMillis)
+    {
+        return sendMessageDelayed(getPostMessage(r, token), delayMillis);
+    }
+
+    /**
      * Posts a message to an object that implements Runnable.
      * Causes the Runnable r to executed on the next iteration through the
      * message queue. The runnable will be run on the thread to which this
diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl
index 3db12ed..29812e8 100644
--- a/core/java/android/os/IStatsManager.aidl
+++ b/core/java/android/os/IStatsManager.aidl
@@ -71,7 +71,7 @@
      * Fetches data for the specified configuration key. Returns a byte array representing proto
      * wire-encoded of ConfigMetricsReportList.
      */
-    byte[] getData(in String key);
+    byte[] getData(in long key);
 
     /**
      * Fetches metadata across statsd. Returns byte array representing wire-encoded proto.
@@ -86,7 +86,7 @@
      *
      * Returns if this configuration was correctly registered.
      */
-    boolean addConfiguration(in String configKey, in byte[] config, in String pkg, in String cls);
+    boolean addConfiguration(in long configKey, in byte[] config, in String pkg, in String cls);
 
     /**
      * Removes the configuration with the matching config key. No-op if this config key does not
@@ -94,5 +94,5 @@
      *
      * Returns if this configuration key was removed.
      */
-    boolean removeConfiguration(in String configKey);
+    boolean removeConfiguration(in long configKey);
 }
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index bfb5130..d31bc1f 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -38,7 +38,6 @@
     static {
         DEFAULT_FLAGS = new HashMap<>();
         DEFAULT_FLAGS.put("device_info_v2", "true");
-        DEFAULT_FLAGS.put("new_settings_suggestion", "true");
         DEFAULT_FLAGS.put("settings_search_v2", "true");
         DEFAULT_FLAGS.put("settings_app_info_v2", "false");
         DEFAULT_FLAGS.put("settings_connected_device_v2", "true");
diff --git a/core/java/android/util/StatsManager.java b/core/java/android/util/StatsManager.java
index 26a3c36..c25b272 100644
--- a/core/java/android/util/StatsManager.java
+++ b/core/java/android/util/StatsManager.java
@@ -53,7 +53,7 @@
      * @return true if successful
      */
     @RequiresPermission(Manifest.permission.DUMP)
-    public boolean addConfiguration(String configKey, byte[] config, String pkg, String cls) {
+    public boolean addConfiguration(long configKey, byte[] config, String pkg, String cls) {
         synchronized (this) {
             try {
                 IStatsManager service = getIStatsManagerLocked();
@@ -76,7 +76,7 @@
      * @return true if successful
      */
     @RequiresPermission(Manifest.permission.DUMP)
-    public boolean removeConfiguration(String configKey) {
+    public boolean removeConfiguration(long configKey) {
         synchronized (this) {
             try {
                 IStatsManager service = getIStatsManagerLocked();
@@ -100,7 +100,7 @@
      * @return Serialized ConfigMetricsReportList proto. Returns null on failure.
      */
     @RequiresPermission(Manifest.permission.DUMP)
-    public byte[] getData(String configKey) {
+    public byte[] getData(long configKey) {
         synchronized (this) {
             try {
                 IStatsManager service = getIStatsManagerLocked();
diff --git a/core/java/com/android/internal/net/INetworkWatchlistManager.aidl b/core/java/com/android/internal/net/INetworkWatchlistManager.aidl
index 7e88369..ee01a23 100644
--- a/core/java/com/android/internal/net/INetworkWatchlistManager.aidl
+++ b/core/java/com/android/internal/net/INetworkWatchlistManager.aidl
@@ -22,5 +22,6 @@
 interface INetworkWatchlistManager {
     boolean startWatchlistLogging();
     boolean stopWatchlistLogging();
+    void reloadWatchlist();
     void reportWatchlistIfNecessary();
 }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 72f07b7..1739bed 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -506,8 +506,8 @@
     final HistoryEventTracker mActiveEvents = new HistoryEventTracker();
 
     long mHistoryBaseTime;
-    boolean mHaveBatteryLevel = false;
-    boolean mRecordingHistory = false;
+    protected boolean mHaveBatteryLevel = false;
+    protected boolean mRecordingHistory = false;
     int mNumHistoryItems;
 
     final Parcel mHistoryBuffer = Parcel.obtain();
@@ -652,6 +652,14 @@
             new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
 
     /**
+     * The WiFi Overall wakelock timer
+     * This timer tracks the actual aggregate time for which MC wakelocks are enabled
+     * since addition of per UID timers would not result in an accurate value due to overlapp of
+     * per uid wakelock timers
+     */
+    StopwatchTimer mWifiMulticastWakelockTimer;
+
+    /**
      * The WiFi controller activity (time in tx, rx, idle, and power consumed) for the device.
      */
     ControllerActivityCounterImpl mWifiActivity;
@@ -3975,30 +3983,85 @@
         addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_JOB_FINISH, name, uid);
     }
 
-    public void noteAlarmStartLocked(String name, int uid) {
-        if (!mRecordAllHistory) {
-            return;
-        }
-        uid = mapUid(uid);
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
-        if (!mActiveEvents.updateState(HistoryItem.EVENT_ALARM_START, name, uid, 0)) {
-            return;
-        }
-        addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_ALARM_START, name, uid);
+    public void noteAlarmStartLocked(String name, WorkSource workSource, int uid) {
+        noteAlarmStartOrFinishLocked(HistoryItem.EVENT_ALARM_START, name, workSource, uid);
     }
 
-    public void noteAlarmFinishLocked(String name, int uid) {
+    public void noteAlarmFinishLocked(String name, WorkSource workSource, int uid) {
+        noteAlarmStartOrFinishLocked(HistoryItem.EVENT_ALARM_FINISH, name, workSource, uid);
+    }
+
+    private void noteAlarmStartOrFinishLocked(int historyItem, String name, WorkSource workSource,
+            int uid) {
         if (!mRecordAllHistory) {
             return;
         }
-        uid = mapUid(uid);
+
         final long elapsedRealtime = mClocks.elapsedRealtime();
         final long uptime = mClocks.uptimeMillis();
-        if (!mActiveEvents.updateState(HistoryItem.EVENT_ALARM_FINISH, name, uid, 0)) {
+
+        if (workSource != null) {
+            for (int i = 0; i < workSource.size(); ++i) {
+                uid = mapUid(workSource.get(i));
+                if (mActiveEvents.updateState(historyItem, name, uid, 0)) {
+                    addHistoryEventLocked(elapsedRealtime, uptime, historyItem, name, uid);
+                }
+            }
+
+            List<WorkChain> workChains = workSource.getWorkChains();
+            if (workChains != null) {
+                for (int i = 0; i < workChains.size(); ++i) {
+                    uid = mapUid(workChains.get(i).getAttributionUid());
+                    if (mActiveEvents.updateState(historyItem, name, uid, 0)) {
+                        addHistoryEventLocked(elapsedRealtime, uptime, historyItem, name, uid);
+                    }
+                }
+            }
+        } else {
+            uid = mapUid(uid);
+
+            if (mActiveEvents.updateState(historyItem, name, uid, 0)) {
+                addHistoryEventLocked(elapsedRealtime, uptime, historyItem, name, uid);
+            }
+        }
+    }
+
+    public void noteWakupAlarmLocked(String packageName, int uid, WorkSource workSource,
+            String tag) {
+        if (!isOnBattery()) {
             return;
         }
-        addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_ALARM_FINISH, name, uid);
+
+        if (workSource != null) {
+            for (int i = 0; i < workSource.size(); ++i) {
+                uid = workSource.get(i);
+                final String workSourceName = workSource.getName(i);
+
+                BatteryStatsImpl.Uid.Pkg pkg = getPackageStatsLocked(uid,
+                        workSourceName != null ? workSourceName : packageName);
+                pkg.noteWakeupAlarmLocked(tag);
+
+                StatsLog.write(StatsLog.WAKEUP_ALARM_OCCURRED, uid, tag);
+            }
+
+            ArrayList<WorkChain> workChains = workSource.getWorkChains();
+            if (workChains != null) {
+                for (int i = 0; i < workChains.size(); ++i) {
+                    final WorkChain wc = workChains.get(i);
+                    uid = wc.getAttributionUid();
+
+                    BatteryStatsImpl.Uid.Pkg pkg = getPackageStatsLocked(uid, packageName);
+                    pkg.noteWakeupAlarmLocked(tag);
+
+                    // TODO(statsd): Log the full attribution chain here once it's available
+                    StatsLog.write(StatsLog.WAKEUP_ALARM_OCCURRED, uid, tag);
+                }
+            }
+        } else {
+            BatteryStatsImpl.Uid.Pkg pkg = getPackageStatsLocked(uid, packageName);
+            pkg.noteWakeupAlarmLocked(tag);
+            StatsLog.write(StatsLog.WAKEUP_ALARM_OCCURRED, uid, tag);
+        }
     }
 
     private void requestWakelockCpuUpdate() {
@@ -5534,6 +5597,12 @@
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast on to: "
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(elapsedRealtime, uptime);
+
+            // Start Wifi Multicast overall timer
+            if (!mWifiMulticastWakelockTimer.isRunningLocked()) {
+                if (DEBUG_HISTORY) Slog.v(TAG, "WiFi Multicast Overall Timer Started");
+                mWifiMulticastWakelockTimer.startRunningLocked(elapsedRealtime);
+            }
         }
         mWifiMulticastNesting++;
         getUidStatsLocked(uid).noteWifiMulticastEnabledLocked(elapsedRealtime);
@@ -5549,6 +5618,12 @@
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast off to: "
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(elapsedRealtime, uptime);
+
+            // Stop Wifi Multicast overall timer
+            if (mWifiMulticastWakelockTimer.isRunningLocked()) {
+                if (DEBUG_HISTORY) Slog.v(TAG, "Multicast Overall Timer Stopped");
+                mWifiMulticastWakelockTimer.stopRunningLocked(elapsedRealtime);
+            }
         }
         getUidStatsLocked(uid).noteWifiMulticastDisabledLocked(elapsedRealtime);
     }
@@ -5835,6 +5910,16 @@
         return (int)mMobileRadioActiveUnknownCount.getCountLocked(which);
     }
 
+    @Override public long getWifiMulticastWakelockTime(
+            long elapsedRealtimeUs, int which) {
+        return mWifiMulticastWakelockTimer.getTotalTimeLocked(
+                elapsedRealtimeUs, which);
+    }
+
+    @Override public int getWifiMulticastWakelockCount(int which) {
+        return mWifiMulticastWakelockTimer.getCountLocked(which);
+    }
+
     @Override public long getWifiOnTime(long elapsedRealtimeUs, int which) {
         return mWifiOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
     }
@@ -9435,6 +9520,8 @@
         mMobileRadioActiveAdjustedTime = new LongSamplingCounter(mOnBatteryTimeBase);
         mMobileRadioActiveUnknownTime = new LongSamplingCounter(mOnBatteryTimeBase);
         mMobileRadioActiveUnknownCount = new LongSamplingCounter(mOnBatteryTimeBase);
+        mWifiMulticastWakelockTimer = new StopwatchTimer(mClocks, null,
+                WIFI_AGGREGATE_MULTICAST_ENABLED, null, mOnBatteryTimeBase);
         mWifiOnTimer = new StopwatchTimer(mClocks, null, -4, null, mOnBatteryTimeBase);
         mGlobalWifiRunningTimer = new StopwatchTimer(mClocks, null, -5, null, mOnBatteryTimeBase);
         for (int i=0; i<NUM_WIFI_STATES; i++) {
@@ -10136,6 +10223,7 @@
         for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
             mWifiSignalStrengthsTimer[i].reset(false);
         }
+        mWifiMulticastWakelockTimer.reset(false);
         mWifiActivity.reset(false);
         mBluetoothActivity.reset(false);
         mModemActivity.reset(false);
@@ -12582,6 +12670,7 @@
         mMobileRadioActiveAdjustedTime.readSummaryFromParcelLocked(in);
         mMobileRadioActiveUnknownTime.readSummaryFromParcelLocked(in);
         mMobileRadioActiveUnknownCount.readSummaryFromParcelLocked(in);
+        mWifiMulticastWakelockTimer.readSummaryFromParcelLocked(in);
         mWifiRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
         mWifiOn = false;
         mWifiOnTimer.readSummaryFromParcelLocked(in);
@@ -13022,6 +13111,7 @@
         mMobileRadioActiveAdjustedTime.writeSummaryFromParcelLocked(out);
         mMobileRadioActiveUnknownTime.writeSummaryFromParcelLocked(out);
         mMobileRadioActiveUnknownCount.writeSummaryFromParcelLocked(out);
+        mWifiMulticastWakelockTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         mWifiOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         mGlobalWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         for (int i=0; i<NUM_WIFI_STATES; i++) {
@@ -13485,6 +13575,8 @@
         mMobileRadioActiveAdjustedTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
         mMobileRadioActiveUnknownTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
         mMobileRadioActiveUnknownCount = new LongSamplingCounter(mOnBatteryTimeBase, in);
+        mWifiMulticastWakelockTimer = new StopwatchTimer(mClocks, null, -4, null,
+                mOnBatteryTimeBase, in);
         mWifiRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
         mWifiOn = false;
         mWifiOnTimer = new StopwatchTimer(mClocks, null, -4, null, mOnBatteryTimeBase, in);
@@ -13691,6 +13783,7 @@
         mMobileRadioActiveAdjustedTime.writeToParcel(out);
         mMobileRadioActiveUnknownTime.writeToParcel(out);
         mMobileRadioActiveUnknownCount.writeToParcel(out);
+        mWifiMulticastWakelockTimer.writeToParcel(out, uSecRealtime);
         mWifiOnTimer.writeToParcel(out, uSecRealtime);
         mGlobalWifiRunningTimer.writeToParcel(out, uSecRealtime);
         for (int i=0; i<NUM_WIFI_STATES; i++) {
@@ -13877,6 +13970,8 @@
             mMobileRadioActiveTimer.logState(pr, "  ");
             pr.println("*** Mobile network active adjusted timer:");
             mMobileRadioActiveAdjustedTime.logState(pr, "  ");
+            pr.println("*** Wifi Multicast WakeLock Timer:");
+            mWifiMulticastWakelockTimer.logState(pr, "  ");
             pr.println("*** mWifiRadioPowerState=" + mWifiRadioPowerState);
             pr.println("*** Wifi timer:");
             mWifiOnTimer.logState(pr, "  ");
diff --git a/core/proto/android/os/batterystats.proto b/core/proto/android/os/batterystats.proto
index 0fa428e..da21258 100644
--- a/core/proto/android/os/batterystats.proto
+++ b/core/proto/android/os/batterystats.proto
@@ -537,7 +537,24 @@
       // Screen-off CPU time in milliseconds.
       optional int64 screen_off_duration_ms = 3;
     }
+    // CPU times accumulated across all process states.
     repeated ByFrequency by_frequency = 3;
+
+    enum ProcessState {
+      TOP = 0;
+      FOREGROUND_SERVICE = 1;
+      FOREGROUND = 2;
+      BACKGROUND = 3;
+      TOP_SLEEPING = 4;
+      HEAVY_WEIGHT = 5;
+      CACHED = 6;
+    }
+    // CPU times at different process states.
+    message ByProcessState {
+      optional ProcessState process_state = 1;
+      repeated ByFrequency by_frequency = 2;
+    }
+    repeated ByProcessState by_process_state = 4;
   }
   optional Cpu cpu = 7;
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 272e3c7..52bfcde 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3870,6 +3870,14 @@
             </intent-filter>
         </receiver>
 
+        <receiver android:name="com.android.server.updates.NetworkWatchlistInstallReceiver"
+                  android:permission="android.permission.UPDATE_CONFIG">
+            <intent-filter>
+                <action android:name="android.intent.action.UPDATE_NETWORK_WATCHLIST" />
+                <data android:scheme="content" android:host="*" android:mimeType="*/*" />
+            </intent-filter>
+        </receiver>
+
         <receiver android:name="com.android.server.updates.ApnDbInstallReceiver"
                 android:permission="android.permission.UPDATE_CONFIG">
             <intent-filter>
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
index 0afec34..a55563a 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
@@ -15,16 +15,19 @@
  */
 package com.android.internal.os;
 
+import static android.os.BatteryStats.STATS_CURRENT;
 import static android.os.BatteryStats.STATS_SINCE_CHARGED;
 import static android.os.BatteryStats.WAKE_TYPE_PARTIAL;
 
 import android.app.ActivityManager;
 import android.os.BatteryManager;
 import android.os.BatteryStats;
+import android.os.BatteryStats.HistoryItem;
 import android.os.WorkSource;
 import android.support.test.filters.SmallTest;
 import android.view.Display;
 
+import com.android.internal.os.BatteryStatsImpl.Uid;
 import junit.framework.TestCase;
 
 import java.util.ArrayList;
@@ -44,11 +47,14 @@
  * Run: adb shell am instrument -e class com.android.internal.os.BatteryStatsNoteTest -w \
  *      com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
  */
-public class BatteryStatsNoteTest extends TestCase{
+public class BatteryStatsNoteTest extends TestCase {
+
     private static final int UID = 10500;
     private static final WorkSource WS = new WorkSource(UID);
 
-    /** Test BatteryStatsImpl.Uid.noteBluetoothScanResultLocked. */
+    /**
+     * Test BatteryStatsImpl.Uid.noteBluetoothScanResultLocked.
+     */
     @SmallTest
     public void testNoteBluetoothScanResultLocked() throws Exception {
         MockBatteryStatsImpl bi = new MockBatteryStatsImpl(new MockClocks());
@@ -75,7 +81,9 @@
                         .getCountLocked(STATS_SINCE_CHARGED));
     }
 
-    /** Test BatteryStatsImpl.Uid.noteStartWakeLocked. */
+    /**
+     * Test BatteryStatsImpl.Uid.noteStartWakeLocked.
+     */
     @SmallTest
     public void testNoteStartWakeLocked() throws Exception {
         final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
@@ -86,7 +94,8 @@
 
         bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
         bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP);
-        bi.getUidStatsLocked(UID).noteStartWakeLocked(pid, name, WAKE_TYPE_PARTIAL, clocks.realtime);
+        bi.getUidStatsLocked(UID)
+                .noteStartWakeLocked(pid, name, WAKE_TYPE_PARTIAL, clocks.realtime);
 
         clocks.realtime = clocks.uptime = 100;
         bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
@@ -94,7 +103,8 @@
         clocks.realtime = clocks.uptime = 220;
         bi.getUidStatsLocked(UID).noteStopWakeLocked(pid, name, WAKE_TYPE_PARTIAL, clocks.realtime);
 
-        BatteryStats.Timer aggregTimer = bi.getUidStats().get(UID).getAggregatedPartialWakelockTimer();
+        BatteryStats.Timer aggregTimer = bi.getUidStats().get(UID)
+                .getAggregatedPartialWakelockTimer();
         long actualTime = aggregTimer.getTotalTimeLocked(300_000, STATS_SINCE_CHARGED);
         long bgTime = aggregTimer.getSubTimer().getTotalTimeLocked(300_000, STATS_SINCE_CHARGED);
         assertEquals(220_000, actualTime);
@@ -102,7 +112,9 @@
     }
 
 
-    /** Test BatteryStatsImpl.noteUidProcessStateLocked. */
+    /**
+     * Test BatteryStatsImpl.noteUidProcessStateLocked.
+     */
     @SmallTest
     public void testNoteUidProcessStateLocked() throws Exception {
         final MockClocks clocks = new MockClocks();
@@ -145,7 +157,6 @@
         expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_TOP);
         assertEquals(expectedRunTimeMs * 1000, actualRunTimeUs);
 
-
         actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_FOREGROUND_SERVICE,
                 elapsedTimeUs, STATS_SINCE_CHARGED);
         expectedRunTimeMs = stateRuntimeMap.get(
@@ -153,19 +164,16 @@
                 + stateRuntimeMap.get(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
         assertEquals(expectedRunTimeMs * 1000, actualRunTimeUs);
 
-
         actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_TOP_SLEEPING,
                 elapsedTimeUs, STATS_SINCE_CHARGED);
         expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_TOP_SLEEPING);
         assertEquals(expectedRunTimeMs * 1000, actualRunTimeUs);
 
-
         actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_FOREGROUND,
                 elapsedTimeUs, STATS_SINCE_CHARGED);
         expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
         assertEquals(expectedRunTimeMs * 1000, actualRunTimeUs);
 
-
         actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_BACKGROUND,
                 elapsedTimeUs, STATS_SINCE_CHARGED);
         expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND)
@@ -174,7 +182,6 @@
                 + stateRuntimeMap.get(ActivityManager.PROCESS_STATE_RECEIVER);
         assertEquals(expectedRunTimeMs * 1000, actualRunTimeUs);
 
-
         actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_CACHED,
                 elapsedTimeUs, STATS_SINCE_CHARGED);
         expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_HOME)
@@ -191,7 +198,9 @@
         assertEquals(expectedRunTimeMs * 1000, actualRunTimeUs);
     }
 
-    /** Test BatteryStatsImpl.updateTimeBasesLocked. */
+    /**
+     * Test BatteryStatsImpl.updateTimeBasesLocked.
+     */
     @SmallTest
     public void testUpdateTimeBasesLocked() throws Exception {
         final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
@@ -213,7 +222,9 @@
         assertTrue(bi.getOnBatteryScreenOffTimeBase().isRunning());
     }
 
-    /** Test BatteryStatsImpl.noteScreenStateLocked sets timebases and screen states correctly. */
+    /**
+     * Test BatteryStatsImpl.noteScreenStateLocked sets timebases and screen states correctly.
+     */
     @SmallTest
     public void testNoteScreenStateLocked() throws Exception {
         final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
@@ -232,15 +243,13 @@
         assertEquals(bi.getScreenState(), Display.STATE_OFF);
     }
 
-    /** Test BatteryStatsImpl.noteScreenStateLocked updates timers correctly.
+    /**
+     * Test BatteryStatsImpl.noteScreenStateLocked updates timers correctly.
      *
-     *  Unknown and doze should both be subset of off state
+     * Unknown and doze should both be subset of off state
      *
-     *  Timeline 0----100----200----310----400------------1000
-     *  Unknown         -------
-     *  On                     -------
-     *  Off             -------       ----------------------
-     *  Doze                                ----------------
+     * Timeline 0----100----200----310----400------------1000 Unknown         ------- On ------- Off
+     * -------       ---------------------- Doze ----------------
      */
     @SmallTest
     public void testNoteScreenStateTimersLocked() throws Exception {
@@ -280,4 +289,161 @@
         assertEquals(600_000, bi.getScreenDozeTime(1500_000, STATS_SINCE_CHARGED));
     }
 
+    @SmallTest
+    public void testAlarmStartAndFinishLocked() throws Exception {
+        final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+        MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+        bi.setRecordAllHistoryLocked(true);
+        bi.forceRecordAllHistory();
+
+        bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+        bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP);
+
+        clocks.realtime = clocks.uptime = 100;
+        bi.noteAlarmStartLocked("foo", null, UID);
+        clocks.realtime = clocks.uptime = 5000;
+        bi.noteAlarmFinishLocked("foo", null, UID);
+
+        HistoryItem item = new HistoryItem();
+        assertTrue(bi.startIteratingHistoryLocked());
+
+        assertTrue(bi.getNextHistoryLocked(item));
+        assertEquals(HistoryItem.EVENT_ALARM_START, item.eventCode);
+        assertEquals("foo", item.eventTag.string);
+        assertEquals(UID, item.eventTag.uid);
+
+        // TODO(narayan): Figure out why this event is written to the history buffer. See
+        // test below where it is being interspersed between multiple START events too.
+        assertTrue(bi.getNextHistoryLocked(item));
+        assertEquals(HistoryItem.EVENT_NONE, item.eventCode);
+
+        assertTrue(bi.getNextHistoryLocked(item));
+        assertEquals(HistoryItem.EVENT_ALARM_FINISH, item.eventCode);
+        assertTrue(item.isDeltaData());
+        assertEquals("foo", item.eventTag.string);
+        assertEquals(UID, item.eventTag.uid);
+
+        assertFalse(bi.getNextHistoryLocked(item));
+    }
+
+    @SmallTest
+    public void testAlarmStartAndFinishLocked_workSource() throws Exception {
+        final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+        MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+        bi.setRecordAllHistoryLocked(true);
+        bi.forceRecordAllHistory();
+
+        bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+        bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP);
+
+        WorkSource ws = new WorkSource();
+        ws.add(100);
+        ws.createWorkChain().addNode(500, "tag");
+        bi.noteAlarmStartLocked("foo", ws, UID);
+        clocks.realtime = clocks.uptime = 5000;
+        bi.noteAlarmFinishLocked("foo", ws, UID);
+
+        HistoryItem item = new HistoryItem();
+        assertTrue(bi.startIteratingHistoryLocked());
+
+        assertTrue(bi.getNextHistoryLocked(item));
+        assertEquals(HistoryItem.EVENT_ALARM_START, item.eventCode);
+        assertEquals("foo", item.eventTag.string);
+        assertEquals(100, item.eventTag.uid);
+
+        assertTrue(bi.getNextHistoryLocked(item));
+        assertEquals(HistoryItem.EVENT_NONE, item.eventCode);
+
+        assertTrue(bi.getNextHistoryLocked(item));
+        assertEquals(HistoryItem.EVENT_ALARM_START, item.eventCode);
+        assertEquals("foo", item.eventTag.string);
+        assertEquals(500, item.eventTag.uid);
+
+        assertTrue(bi.getNextHistoryLocked(item));
+        assertEquals(HistoryItem.EVENT_ALARM_FINISH, item.eventCode);
+        assertEquals("foo", item.eventTag.string);
+        assertEquals(100, item.eventTag.uid);
+
+        assertTrue(bi.getNextHistoryLocked(item));
+        assertEquals(HistoryItem.EVENT_ALARM_FINISH, item.eventCode);
+        assertEquals("foo", item.eventTag.string);
+        assertEquals(500, item.eventTag.uid);
+    }
+
+    @SmallTest
+    public void testNoteWakupAlarmLocked() {
+        final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+        MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+        bi.setRecordAllHistoryLocked(true);
+        bi.forceRecordAllHistory();
+        bi.mForceOnBattery = true;
+
+        bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+        bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP);
+
+        bi.noteWakupAlarmLocked("com.foo.bar", UID, null, "tag");
+
+        Uid.Pkg pkg = bi.getPackageStatsLocked(UID, "com.foo.bar");
+        assertEquals(1, pkg.getWakeupAlarmStats().get("tag").getCountLocked(STATS_CURRENT));
+        assertEquals(1, pkg.getWakeupAlarmStats().size());
+    }
+
+    @SmallTest
+    public void testNoteWakupAlarmLocked_workSource_uid() {
+        final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+        MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+        bi.setRecordAllHistoryLocked(true);
+        bi.forceRecordAllHistory();
+        bi.mForceOnBattery = true;
+
+        bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+        bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP);
+
+        WorkSource ws = new WorkSource();
+        ws.add(100);
+
+        // When a WorkSource is present, "UID" should not be used - only the uids present in the
+        // WorkSource should be reported.
+        bi.noteWakupAlarmLocked("com.foo.bar", UID, ws, "tag");
+        Uid.Pkg pkg = bi.getPackageStatsLocked(UID, "com.foo.bar");
+        assertEquals(0, pkg.getWakeupAlarmStats().size());
+        pkg = bi.getPackageStatsLocked(100, "com.foo.bar");
+        assertEquals(1, pkg.getWakeupAlarmStats().size());
+
+        // If the WorkSource contains a "name", it should be interpreted as a package name and
+        // the packageName supplied as an argument must be ignored.
+        ws = new WorkSource();
+        ws.add(100, "com.foo.baz_alternate");
+        bi.noteWakupAlarmLocked("com.foo.baz", UID, ws, "tag");
+        pkg = bi.getPackageStatsLocked(100, "com.foo.baz");
+        assertEquals(0, pkg.getWakeupAlarmStats().size());
+        pkg = bi.getPackageStatsLocked(100, "com.foo.baz_alternate");
+        assertEquals(1, pkg.getWakeupAlarmStats().size());
+    }
+
+    @SmallTest
+    public void testNoteWakupAlarmLocked_workSource_workChain() {
+        final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+        MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+        bi.setRecordAllHistoryLocked(true);
+        bi.forceRecordAllHistory();
+        bi.mForceOnBattery = true;
+
+        bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+        bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP);
+
+        WorkSource ws = new WorkSource();
+        ws.createWorkChain().addNode(100, "com.foo.baz_alternate");
+        bi.noteWakupAlarmLocked("com.foo.bar", UID, ws, "tag");
+
+        // For WorkChains, again we must only attribute to the uids present in the WorkSource
+        // (and not to "UID"). However, unlike the older "tags" we do not change the packagename
+        // supplied as an argument, given that we're logging the entire attribution chain.
+        Uid.Pkg pkg = bi.getPackageStatsLocked(UID, "com.foo.bar");
+        assertEquals(0, pkg.getWakeupAlarmStats().size());
+        pkg = bi.getPackageStatsLocked(100, "com.foo.bar");
+        assertEquals(1, pkg.getWakeupAlarmStats().size());
+        pkg = bi.getPackageStatsLocked(100, "com.foo.baz_alternate");
+        assertEquals(0, pkg.getWakeupAlarmStats().size());
+    }
 }
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index de2fd12..f19ff67 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.os;
 
+import android.os.Handler;
+import android.os.Looper;
 import android.util.SparseIntArray;
 
 import java.util.ArrayList;
@@ -37,6 +39,9 @@
                 mOnBatteryTimeBase);
         mBluetoothScanTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase);
         setExternalStatsSyncLocked(new DummyExternalStatsSync());
+
+        // A no-op handler.
+        mHandler = new Handler(Looper.getMainLooper()) {};
     }
 
     MockBatteryStatsImpl() {
@@ -59,6 +64,12 @@
         return mForceOnBattery ? true : super.isOnBattery();
     }
 
+    public void forceRecordAllHistory() {
+        mHaveBatteryLevel = true;
+        mRecordingHistory = true;
+        mRecordAllHistory = true;
+    }
+
     public TimeBase getOnBatteryBackgroundTimeBase(int uid) {
         return getUidStatsLocked(uid).mOnBatteryBackgroundTimeBase;
     }
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index 1e42425..4a0d6ee 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -122,15 +122,19 @@
 void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint& paint, float x,
                                  float y) {
     auto utf16 = asciiToUtf16(text);
-    canvas->drawText(utf16.get(), 0, strlen(text), strlen(text), x, y, minikin::Bidi::LTR, paint,
-                     nullptr);
+    SkPaint glyphPaint(paint);
+    glyphPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+    canvas->drawText(utf16.get(), 0, strlen(text), strlen(text), x, y, minikin::Bidi::LTR,
+            glyphPaint, nullptr);
 }
 
 void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint& paint,
                                  const SkPath& path) {
     auto utf16 = asciiToUtf16(text);
-    canvas->drawTextOnPath(utf16.get(), strlen(text), minikin::Bidi::LTR, path, 0, 0, paint,
-                           nullptr);
+    SkPaint glyphPaint(paint);
+    glyphPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+    canvas->drawTextOnPath(utf16.get(), strlen(text), minikin::Bidi::LTR, path, 0, 0, glyphPaint,
+            nullptr);
 }
 
 void TestUtils::TestTask::run() {
diff --git a/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp b/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp
index bf0aed9..38999cb 100644
--- a/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp
@@ -40,22 +40,18 @@
     }
 
     void doFrame(int frameNr) override {
-        std::unique_ptr<uint16_t[]> text =
-                TestUtils::asciiToUtf16("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
-        ssize_t textLength = 26 * 2;
+        const char* text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
 
         std::unique_ptr<Canvas> canvas(
                 Canvas::create_recording_canvas(container->stagingProperties().getWidth(),
                                                 container->stagingProperties().getHeight()));
 
         Paint paint;
-        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
         paint.setAntiAlias(true);
         paint.setColor(Color::Black);
         for (int i = 0; i < 5; i++) {
             paint.setTextSize(10 + (frameNr % 20) + i * 20);
-            canvas->drawText(text.get(), 0, textLength, textLength, 0, 100 * (i + 2),
-                             minikin::Bidi::FORCE_LTR, paint, nullptr);
+            TestUtils::drawUtf8ToCanvas(canvas.get(), text, paint, 0, 100 * (i + 2));
         }
 
         container->setStagingDisplayList(canvas->finishRecording());
diff --git a/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
index 6bae80c..58c9980 100644
--- a/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
@@ -36,7 +36,6 @@
         SkPaint textPaint;
         textPaint.setTextSize(dp(20));
         textPaint.setAntiAlias(true);
-        textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
         TestUtils::drawUtf8ToCanvas(&canvas, "not that long long text", textPaint, dp(10), dp(30));
 
         SkPoint pts[2];
diff --git a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
index d7ec288..fd8c252 100644
--- a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
@@ -83,7 +83,6 @@
         canvas.drawRoundRect(0, 0, itemWidth, itemHeight, dp(6), dp(6), roundRectPaint);
 
         SkPaint textPaint;
-        textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
         textPaint.setColor(rand() % 2 ? Color::Black : Color::Grey_500);
         textPaint.setTextSize(dp(20));
         textPaint.setAntiAlias(true);
diff --git a/libs/hwui/tests/common/scenes/MagnifierAnimation.cpp b/libs/hwui/tests/common/scenes/MagnifierAnimation.cpp
index 9eddc20..aa537b4 100644
--- a/libs/hwui/tests/common/scenes/MagnifierAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/MagnifierAnimation.cpp
@@ -38,7 +38,6 @@
         card = TestUtils::createNode(
                 0, 0, width, height, [&](RenderProperties& props, Canvas& canvas) {
                     SkPaint paint;
-                    paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
                     paint.setAntiAlias(true);
                     paint.setTextSize(50);
 
diff --git a/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp b/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp
index fee0659..3befce4 100644
--- a/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp
+++ b/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp
@@ -42,10 +42,8 @@
 
         mBluePaint.setColor(SkColorSetARGB(255, 0, 0, 255));
         mBluePaint.setTextSize(padding);
-        mBluePaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
         mGreenPaint.setColor(SkColorSetARGB(255, 0, 255, 0));
         mGreenPaint.setTextSize(padding);
-        mGreenPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
 
         // interleave drawText and drawRect with saveLayer ops
         for (int i = 0; i < regions; i++, top += smallRectHeight) {
@@ -54,18 +52,15 @@
             canvas.drawColor(SkColorSetARGB(255, 255, 255, 0), SkBlendMode::kSrcOver);
             std::string stri = std::to_string(i);
             std::string offscreen = "offscreen line " + stri;
-            std::unique_ptr<uint16_t[]> offtext = TestUtils::asciiToUtf16(offscreen.c_str());
-            canvas.drawText(offtext.get(), 0, offscreen.length(), offscreen.length(), bounds.fLeft,
-                            top + padding, minikin::Bidi::FORCE_LTR, mBluePaint, nullptr);
+            TestUtils::drawUtf8ToCanvas(&canvas, offscreen.c_str(), mBluePaint, bounds.fLeft,
+                    top + padding);
             canvas.restore();
 
             canvas.drawRect(bounds.fLeft, top + padding, bounds.fRight,
                             top + smallRectHeight - padding, mBluePaint);
             std::string onscreen = "onscreen line " + stri;
-            std::unique_ptr<uint16_t[]> ontext = TestUtils::asciiToUtf16(onscreen.c_str());
-            canvas.drawText(ontext.get(), 0, onscreen.length(), onscreen.length(), bounds.fLeft,
-                            top + smallRectHeight - padding, minikin::Bidi::FORCE_LTR, mGreenPaint,
-                            nullptr);
+            TestUtils::drawUtf8ToCanvas(&canvas, onscreen.c_str(), mGreenPaint, bounds.fLeft,
+                    top + smallRectHeight - padding);
         }
     }
     void doFrame(int frameNr) override {}
diff --git a/libs/hwui/tests/common/scenes/TextAnimation.cpp b/libs/hwui/tests/common/scenes/TextAnimation.cpp
index a502116..a16b1784 100644
--- a/libs/hwui/tests/common/scenes/TextAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/TextAnimation.cpp
@@ -29,7 +29,6 @@
         card = TestUtils::createNode(0, 0, width, height, [](RenderProperties& props,
                                                              Canvas& canvas) {
             SkPaint paint;
-            paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
             paint.setAntiAlias(true);
             paint.setTextSize(50);
 
diff --git a/libs/hwui/tests/common/scenes/TvApp.cpp b/libs/hwui/tests/common/scenes/TvApp.cpp
index c845e6c..003d8e9 100644
--- a/libs/hwui/tests/common/scenes/TvApp.cpp
+++ b/libs/hwui/tests/common/scenes/TvApp.cpp
@@ -117,7 +117,6 @@
                                          canvas.drawColor(0xFFFFEEEE, SkBlendMode::kSrcOver);
 
                                          SkPaint paint;
-                                         paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
                                          paint.setAntiAlias(true);
                                          paint.setTextSize(24);
 
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index e56d2f8..4eb7751 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -537,7 +537,6 @@
                 canvas.save(SaveFlags::MatrixClip);
                 canvas.clipPath(&path, SkClipOp::kIntersect);
                 SkPaint paint;
-                paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
                 paint.setAntiAlias(true);
                 paint.setTextSize(50);
                 TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100);
@@ -569,7 +568,6 @@
     auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400, [](RenderProperties& props,
                                                                           RecordingCanvas& canvas) {
         SkPaint paint;
-        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
         paint.setAntiAlias(true);
         paint.setTextSize(50);
         TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 0);  // will be top clipped
@@ -603,7 +601,6 @@
                 textPaint.setAntiAlias(true);
                 textPaint.setTextSize(20);
                 textPaint.setFlags(textPaint.getFlags() | SkPaint::kStrikeThruText_ReserveFlag);
-                textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
                 for (int i = 0; i < LOOPS; i++) {
                     TestUtils::drawUtf8ToCanvas(&canvas, "test text", textPaint, 10, 100 * (i + 1));
                 }
@@ -654,7 +651,6 @@
     auto node = TestUtils::createNode<RecordingCanvas>(
             0, 0, 400, 400, [](RenderProperties& props, RecordingCanvas& canvas) {
                 SkPaint paint;
-                paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
                 paint.setAntiAlias(true);
                 paint.setTextSize(50);
                 paint.setStrokeWidth(10);
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index 5aae15f..8a9e34f 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -175,7 +175,6 @@
         SkPaint paint;
         paint.setAntiAlias(true);
         paint.setTextSize(20);
-        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
         TestUtils::drawUtf8ToCanvas(&canvas, "test text", paint, 25, 25);
     });
 
@@ -196,7 +195,6 @@
         SkPaint paint;
         paint.setAntiAlias(true);
         paint.setTextSize(20);
-        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
         for (int i = 0; i < 2; i++) {
             for (int j = 0; j < 2; j++) {
                 uint32_t flags = paint.getFlags();
@@ -238,7 +236,6 @@
         SkPaint paint;
         paint.setAntiAlias(true);
         paint.setTextSize(20);
-        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
         paint.setTextAlign(SkPaint::kLeft_Align);
         TestUtils::drawUtf8ToCanvas(&canvas, "test text", paint, 25, 25);
         paint.setTextAlign(SkPaint::kCenter_Align);
@@ -805,9 +802,7 @@
         Paint paint;
         paint.setAntiAlias(true);
         paint.setTextSize(20);
-        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
-        std::unique_ptr<uint16_t[]> dst = TestUtils::asciiToUtf16("HELLO");
-        canvas.drawText(dst.get(), 0, 5, 5, 25, 25, minikin::Bidi::FORCE_LTR, paint, NULL);
+        TestUtils::drawUtf8ToCanvas(&canvas, "HELLO", paint, 25, 25);
     });
 
     int count = 0;
@@ -829,9 +824,7 @@
         paint.setColor(SK_ColorWHITE);
         paint.setAntiAlias(true);
         paint.setTextSize(20);
-        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
-        std::unique_ptr<uint16_t[]> dst = TestUtils::asciiToUtf16("HELLO");
-        canvas.drawText(dst.get(), 0, 5, 5, 25, 25, minikin::Bidi::FORCE_LTR, paint, NULL);
+        TestUtils::drawUtf8ToCanvas(&canvas, "HELLO", paint, 25, 25);
     });
     Properties::enableHighContrastText = false;
 
diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
index 4138f59..1d7dc3d 100644
--- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp
+++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
@@ -36,7 +36,6 @@
         SkPaint paint;
         paint.setAntiAlias(true);
         paint.setTextSize(20);
-        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
         static const char* text = "testing text bounds";
 
         // draw text directly into Recording canvas
diff --git a/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp b/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp
index 78d75d6..92d05e4 100644
--- a/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp
+++ b/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp
@@ -29,6 +29,7 @@
 RENDERTHREAD_OPENGL_PIPELINE_TEST(TextDropShadowCache, addRemove) {
     SkPaint paint;
     paint.setTextSize(20);
+    paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
 
     GammaFontRenderer gammaFontRenderer;
     FontRenderer& fontRenderer = gammaFontRenderer.getFontRenderer();
diff --git a/media/java/android/media/AudioFocusInfo.java b/media/java/android/media/AudioFocusInfo.java
index 6d9c5e2..5d0c8e2 100644
--- a/media/java/android/media/AudioFocusInfo.java
+++ b/media/java/android/media/AudioFocusInfo.java
@@ -130,13 +130,11 @@
         dest.writeInt(mSdkTarget);
     }
 
-    @SystemApi
     @Override
     public int hashCode() {
         return Objects.hash(mAttributes, mClientUid, mClientId, mPackageName, mGainRequest, mFlags);
     }
 
-    @SystemApi
     @Override
     public boolean equals(Object obj) {
         if (this == obj)
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java
new file mode 100644
index 0000000..f0e4ccc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.systemui.pip.phone;
+
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.OP_PICTURE_IN_PICTURE;
+
+import android.app.AppOpsManager;
+import android.app.AppOpsManager.OnOpChangedListener;
+import android.app.IActivityManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.util.Pair;
+
+public class PipAppOpsListener {
+    private static final String TAG = PipAppOpsListener.class.getSimpleName();
+
+    private Context mContext;
+    private IActivityManager mActivityManager;
+    private AppOpsManager mAppOpsManager;
+
+    private PipMotionHelper mMotionHelper;
+
+    private AppOpsManager.OnOpChangedListener mAppOpsChangedListener = new OnOpChangedListener() {
+        @Override
+        public void onOpChanged(String op, String packageName) {
+            try {
+                // Dismiss the PiP once the user disables the app ops setting for that package
+                final Pair<ComponentName, Integer> topPipActivityInfo =
+                        PipUtils.getTopPinnedActivity(mContext, mActivityManager);
+                if (topPipActivityInfo.first != null) {
+                    final ApplicationInfo appInfo = mContext.getPackageManager()
+                            .getApplicationInfoAsUser(packageName, 0, topPipActivityInfo.second);
+                    if (appInfo.packageName.equals(topPipActivityInfo.first.getPackageName()) &&
+                            mAppOpsManager.checkOpNoThrow(OP_PICTURE_IN_PICTURE, appInfo.uid,
+                                    packageName) != MODE_ALLOWED) {
+                        mMotionHelper.dismissPip();
+                    }
+                }
+            } catch (NameNotFoundException e) {
+                // Unregister the listener if the package can't be found
+                unregisterAppOpsListener();
+            }
+        }
+    };
+
+    public PipAppOpsListener(Context context, IActivityManager activityManager,
+            PipMotionHelper motionHelper) {
+        mContext = context;
+        mActivityManager = activityManager;
+        mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+        mMotionHelper = motionHelper;
+    }
+
+    public void onActivityPinned(String packageName) {
+        // Register for changes to the app ops setting for this package while it is in PiP
+        registerAppOpsListener(packageName);
+    }
+
+    public void onActivityUnpinned() {
+        // Unregister for changes to the previously PiP'ed package
+        unregisterAppOpsListener();
+    }
+
+    private void registerAppOpsListener(String packageName) {
+        mAppOpsManager.startWatchingMode(OP_PICTURE_IN_PICTURE, packageName,
+                mAppOpsChangedListener);
+    }
+
+    private void unregisterAppOpsListener() {
+        mAppOpsManager.stopWatchingMode(mAppOpsChangedListener);
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index dce3e24..36531bb 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -65,6 +65,7 @@
     private PipMenuActivityController mMenuController;
     private PipMediaController mMediaController;
     private PipTouchHandler mTouchHandler;
+    private PipAppOpsListener mAppOpsListener;
 
     /**
      * Handler for system task stack changes.
@@ -75,6 +76,7 @@
             mTouchHandler.onActivityPinned();
             mMediaController.onActivityPinned();
             mMenuController.onActivityPinned();
+            mAppOpsListener.onActivityPinned(packageName);
 
             SystemServicesProxy.getInstance(mContext).setPipVisibility(true);
         }
@@ -87,6 +89,7 @@
             final int userId = topActivity != null ? topPipActivityInfo.second : 0;
             mMenuController.onActivityUnpinned();
             mTouchHandler.onActivityUnpinned(topActivity);
+            mAppOpsListener.onActivityUnpinned();
 
             SystemServicesProxy.getInstance(mContext).setPipVisibility(topActivity != null);
         }
@@ -177,6 +180,8 @@
                 mInputConsumerController);
         mTouchHandler = new PipTouchHandler(context, mActivityManager, mMenuController,
                 mInputConsumerController);
+        mAppOpsListener = new PipAppOpsListener(context, mActivityManager,
+                mTouchHandler.getMotionHelper());
         EventBus.getDefault().register(this);
     }
 
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 935b787..1aaa538 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5094,6 +5094,36 @@
     // Tag used to report autofill field classification scores
     FIELD_AUTOFILL_MATCH_SCORE = 1274;
 
+    // ACTION: Usb config has been changed to charging
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_USB_CONFIG_CHARGING = 1275;
+
+    // ACTION: Usb config has been changed to mtp (file transfer)
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_USB_CONFIG_MTP = 1276;
+
+    // ACTION: Usb config has been changed to ptp (photo transfer)
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_USB_CONFIG_PTP = 1277;
+
+    // ACTION: Usb config has been changed to rndis (usb tethering)
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_USB_CONFIG_RNDIS = 1278;
+
+    // ACTION: Usb config has been changed to midi
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_USB_CONFIG_MIDI = 1279;
+
+    // ACTION: Usb config has been changed to accessory
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_USB_CONFIG_ACCESSORY = 1280;
+
     // ---- End P Constants, all P constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
index 9b2b4eb..a219edb 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
@@ -229,7 +229,7 @@
     }
 
     void clearAndTransitionToStateDetecting() {
-        mCurrentState = mDelegatingState;
+        mCurrentState = mDetectingState;
         mDetectingState.clear();
         mViewportDraggingState.clear();
         mPanningScalingState.clear();
@@ -649,14 +649,19 @@
                 break;
                 case ACTION_MOVE: {
                     if (isFingerDown()
-                            && distance(mLastDown, /* move */ event) > mSwipeMinDistance
-                            // For convenience, viewport dragging on 3tap&hold takes precedence
-                            // over insta-delegating on 3tap&swipe
-                            // (which is a rare combo to be used aside from magnification)
-                            && !isMultiTapTriggered(2 /* taps */)) {
+                            && distance(mLastDown, /* move */ event) > mSwipeMinDistance) {
 
-                        // Swipe detected - delegate skipping timeout
-                        transitionToDelegatingStateAndClear();
+                        // Swipe detected - transition immediately
+
+                        // For convenience, viewport dragging takes precedence
+                        // over insta-delegating on 3tap&swipe
+                        // (which is a rare combo to be used aside from magnification)
+                        if (isMultiTapTriggered(2 /* taps */)) {
+                            transitionTo(mViewportDraggingState);
+                            clear();
+                        } else {
+                            transitionToDelegatingStateAndClear();
+                        }
                     }
                 }
                 break;
diff --git a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
index 3a37459..51c44e1 100644
--- a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
@@ -1424,6 +1424,8 @@
             final Intent notification = new Intent();
             notification.setAction(BACKUP_FINISHED_ACTION);
             notification.setPackage(receiver);
+            notification.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES |
+                    Intent.FLAG_RECEIVER_FOREGROUND);
             notification.putExtra(BACKUP_FINISHED_PACKAGE_EXTRA, packageName);
             mContext.sendBroadcastAsUser(notification, UserHandle.OWNER);
         }
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 06cf982..472723d 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -3035,15 +3035,8 @@
                     Slog.v(TAG, "sending alarm " + alarm);
                 }
                 if (RECORD_ALARMS_IN_HISTORY) {
-                    if (alarm.workSource != null && alarm.workSource.size() > 0) {
-                        for (int wi=0; wi<alarm.workSource.size(); wi++) {
-                            ActivityManager.noteAlarmStart(
-                                    alarm.operation, alarm.workSource.get(wi), alarm.statsTag);
-                        }
-                    } else {
-                        ActivityManager.noteAlarmStart(
-                                alarm.operation, alarm.uid, alarm.statsTag);
-                    }
+                    ActivityManager.noteAlarmStart(alarm.operation, alarm.workSource, alarm.uid,
+                            alarm.statsTag);
                 }
                 mDeliveryTracker.deliverLocked(alarm, nowELAPSED, allowWhileIdle);
             } catch (RuntimeException e) {
@@ -3553,15 +3546,8 @@
                 fs.aggregateTime += nowELAPSED - fs.startTime;
             }
             if (RECORD_ALARMS_IN_HISTORY) {
-                if (inflight.mWorkSource != null && inflight.mWorkSource.size() > 0) {
-                    for (int wi=0; wi<inflight.mWorkSource.size(); wi++) {
-                        ActivityManager.noteAlarmFinish(
-                                inflight.mPendingIntent, inflight.mWorkSource.get(wi), inflight.mTag);
-                    }
-                } else {
-                    ActivityManager.noteAlarmFinish(
-                            inflight.mPendingIntent, inflight.mUid, inflight.mTag);
-                }
+                ActivityManager.noteAlarmFinish(inflight.mPendingIntent, inflight.mWorkSource,
+                        inflight.mUid, inflight.mTag);
             }
         }
 
@@ -3771,18 +3757,9 @@
                     || alarm.type == RTC_WAKEUP) {
                 bs.numWakeup++;
                 fs.numWakeup++;
-                if (alarm.workSource != null && alarm.workSource.size() > 0) {
-                    for (int wi=0; wi<alarm.workSource.size(); wi++) {
-                        final String wsName = alarm.workSource.getName(wi);
-                        ActivityManager.noteWakeupAlarm(
-                                alarm.operation, alarm.workSource.get(wi),
-                                (wsName != null) ? wsName : alarm.packageName,
-                                alarm.statsTag);
-                    }
-                } else {
-                    ActivityManager.noteWakeupAlarm(
-                            alarm.operation, alarm.uid, alarm.packageName, alarm.statsTag);
-                }
+                ActivityManager.noteWakeupAlarm(
+                        alarm.operation, alarm.workSource, alarm.uid, alarm.packageName,
+                        alarm.statsTag);
             }
         }
     }
diff --git a/services/core/java/com/android/server/EntropyMixer.java b/services/core/java/com/android/server/EntropyMixer.java
index 9877717..5e6e9d34 100644
--- a/services/core/java/com/android/server/EntropyMixer.java
+++ b/services/core/java/com/android/server/EntropyMixer.java
@@ -196,11 +196,14 @@
      * Mixes in the output from HW RNG (if present) into the Linux RNG.
      */
     private void addHwRandomEntropy() {
+        if (!new File(hwRandomDevice).exists()) {
+            // HW RNG not present/exposed -- ignore
+            return;
+        }
+
         try {
             RandomBlock.fromFile(hwRandomDevice).toFile(randomDevice, false);
             Slog.i(TAG, "Added HW RNG output to entropy pool");
-        } catch (FileNotFoundException ignored) {
-            // HW RNG not present/exposed -- ignore
         } catch (IOException e) {
             Slog.w(TAG, "Failed to add HW RNG output to entropy pool", e);
         }
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 31aea63..46eea78 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -5595,25 +5595,26 @@
         long ident = Binder.clearCallingIdentity();
         try {
             packages = mPackageManager.getPackagesForUid(callingUid);
+            if (packages != null) {
+                for (String name : packages) {
+                    try {
+                        PackageInfo packageInfo =
+                                mPackageManager.getPackageInfo(name, 0 /* flags */);
+                        if (packageInfo != null
+                                && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
+                                != 0) {
+                            return true;
+                        }
+                    } catch (NameNotFoundException e) {
+                        Log.w(TAG, String.format("Could not find package [%s]", name), e);
+                    }
+                }
+            } else {
+                Log.w(TAG, "No known packages with uid " + callingUid);
+            }
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
-        if (packages != null) {
-            for (String name : packages) {
-                try {
-                    PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
-                    if (packageInfo != null
-                            && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
-                                    != 0) {
-                        return true;
-                    }
-                } catch (NameNotFoundException e) {
-                    Log.w(TAG, String.format("Could not find package [%s]", name), e);
-                }
-            }
-        } else {
-            Log.w(TAG, "No known packages with uid " + callingUid);
-        }
         return false;
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d92b3b8..5936ce1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -13858,68 +13858,100 @@
                 Context.WINDOW_SERVICE)).addView(v, lp);
     }
 
-    public void noteWakeupAlarm(IIntentSender sender, int sourceUid, String sourcePkg, String tag) {
-        if (sender != null && !(sender instanceof PendingIntentRecord)) {
-            return;
+    @Override
+    public void noteWakeupAlarm(IIntentSender sender, WorkSource workSource, int sourceUid,
+            String sourcePkg, String tag) {
+        if (workSource != null && workSource.isEmpty()) {
+            workSource = null;
         }
-        final PendingIntentRecord rec = (PendingIntentRecord)sender;
-        final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
-        synchronized (stats) {
-            if (mBatteryStatsService.isOnBattery()) {
-                mBatteryStatsService.enforceCallingPermission();
-                int MY_UID = Binder.getCallingUid();
-                final int uid;
-                if (sender == null) {
-                    uid = sourceUid;
-                } else {
-                    uid = rec.uid == MY_UID ? SYSTEM_UID : rec.uid;
+
+        if (sourceUid <= 0 && workSource == null) {
+            // Try and derive a UID to attribute things to based on the caller.
+            if (sender != null) {
+                if (!(sender instanceof PendingIntentRecord)) {
+                    return;
                 }
-                BatteryStatsImpl.Uid.Pkg pkg =
-                    stats.getPackageStatsLocked(sourceUid >= 0 ? sourceUid : uid,
-                            sourcePkg != null ? sourcePkg : rec.key.packageName);
-                pkg.noteWakeupAlarmLocked(tag);
-                StatsLog.write(StatsLog.WAKEUP_ALARM_OCCURRED, sourceUid >= 0 ? sourceUid : uid,
-                        tag);
+
+                final PendingIntentRecord rec = (PendingIntentRecord) sender;
+                final int callerUid = Binder.getCallingUid();
+                sourceUid = rec.uid == callerUid ? SYSTEM_UID : rec.uid;
+            } else {
+                // TODO(narayan): Should we throw an exception in this case ? It means that we
+                // haven't been able to derive a UID to attribute things to.
+                return;
             }
         }
+
+        if (DEBUG_POWER) {
+            Slog.w(TAG, "noteWakupAlarm[ sourcePkg=" + sourcePkg + ", sourceUid=" + sourceUid
+                    + ", workSource=" + workSource + ", tag=" + tag + "]");
+        }
+
+        mBatteryStatsService.noteWakupAlarm(sourcePkg, sourceUid, workSource, tag);
     }
 
-    public void noteAlarmStart(IIntentSender sender, int sourceUid, String tag) {
-        if (sender != null && !(sender instanceof PendingIntentRecord)) {
-            return;
+    @Override
+    public void noteAlarmStart(IIntentSender sender, WorkSource workSource, int sourceUid,
+            String tag) {
+        if (workSource != null && workSource.isEmpty()) {
+            workSource = null;
         }
-        final PendingIntentRecord rec = (PendingIntentRecord)sender;
-        final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
-        synchronized (stats) {
-            mBatteryStatsService.enforceCallingPermission();
-            int MY_UID = Binder.getCallingUid();
-            final int uid;
-            if (sender == null) {
-                uid = sourceUid;
+
+        if (sourceUid <= 0 && workSource == null) {
+            // Try and derive a UID to attribute things to based on the caller.
+            if (sender != null) {
+                if (!(sender instanceof PendingIntentRecord)) {
+                    return;
+                }
+
+                final PendingIntentRecord rec = (PendingIntentRecord) sender;
+                final int callerUid = Binder.getCallingUid();
+                sourceUid = rec.uid == callerUid ? SYSTEM_UID : rec.uid;
             } else {
-                uid = rec.uid == MY_UID ? SYSTEM_UID : rec.uid;
+                // TODO(narayan): Should we throw an exception in this case ? It means that we
+                // haven't been able to derive a UID to attribute things to.
+                return;
             }
-            mBatteryStatsService.noteAlarmStart(tag, sourceUid >= 0 ? sourceUid : uid);
         }
+
+        if (DEBUG_POWER) {
+            Slog.w(TAG, "noteAlarmStart[sourceUid=" + sourceUid + ", workSource=" + workSource +
+                    ", tag=" + tag + "]");
+        }
+
+        mBatteryStatsService.noteAlarmStart(tag, workSource, sourceUid);
     }
 
-    public void noteAlarmFinish(IIntentSender sender, int sourceUid, String tag) {
-        if (sender != null && !(sender instanceof PendingIntentRecord)) {
-            return;
+    @Override
+    public void noteAlarmFinish(IIntentSender sender, WorkSource workSource, int sourceUid,
+            String tag) {
+        if (workSource != null && workSource.isEmpty()) {
+            workSource = null;
         }
-        final PendingIntentRecord rec = (PendingIntentRecord)sender;
-        final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
-        synchronized (stats) {
-            mBatteryStatsService.enforceCallingPermission();
-            int MY_UID = Binder.getCallingUid();
-            final int uid;
-            if (sender == null) {
-                uid = sourceUid;
+
+        if (sourceUid <= 0 && workSource == null) {
+            // Try and derive a UID to attribute things to based on the caller.
+            if (sender != null) {
+                if (!(sender instanceof PendingIntentRecord)) {
+                    return;
+                }
+
+                final PendingIntentRecord rec = (PendingIntentRecord) sender;
+                final int callerUid = Binder.getCallingUid();
+                sourceUid = rec.uid == callerUid ? SYSTEM_UID : rec.uid;
             } else {
-                uid = rec.uid == MY_UID ? SYSTEM_UID : rec.uid;
+                // TODO(narayan): Should we throw an exception in this case ? It means that we
+                // haven't been able to derive a UID to attribute things to.
+                return;
             }
-            mBatteryStatsService.noteAlarmFinish(tag, sourceUid >= 0 ? sourceUid : uid);
         }
+
+        if (DEBUG_POWER) {
+            Slog.w(TAG, "noteAlarmFinish[sourceUid=" + sourceUid + ", workSource=" + workSource +
+                    ", tag=" + tag + "]");
+        }
+
+        mBatteryStatsService.noteAlarmFinish(tag, workSource, sourceUid);
     }
 
     public boolean killPids(int[] pids, String pReason, boolean secure) {
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 35318f6..430320a 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -38,6 +38,7 @@
 import android.os.UserHandle;
 import android.os.UserManagerInternal;
 import android.os.WorkSource;
+import android.os.WorkSource.WorkChain;
 import android.os.connectivity.CellularBatteryStats;
 import android.os.health.HealthStatsParceler;
 import android.os.health.HealthStatsWriter;
@@ -66,6 +67,7 @@
 import java.nio.charset.CharsetDecoder;
 import java.nio.charset.CodingErrorAction;
 import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.ExecutionException;
@@ -446,17 +448,24 @@
         }
     }
 
-    public void noteAlarmStart(String name, int uid) {
+    public void noteWakupAlarm(String name, int uid, WorkSource workSource, String tag) {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.noteAlarmStartLocked(name, uid);
+            mStats.noteWakupAlarmLocked(name, uid, workSource, tag);
         }
     }
 
-    public void noteAlarmFinish(String name, int uid) {
+    public void noteAlarmStart(String name, WorkSource workSource, int uid) {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.noteAlarmFinishLocked(name, uid);
+            mStats.noteAlarmStartLocked(name, workSource, uid);
+        }
+    }
+
+    public void noteAlarmFinish(String name, WorkSource workSource, int uid) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteAlarmFinishLocked(name, workSource, uid);
         }
     }
 
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 7715727..c7a4315 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -305,6 +305,7 @@
         } else {
             for (Network underlying : underlyingNetworks) {
                 final NetworkCapabilities underlyingCaps = cm.getNetworkCapabilities(underlying);
+                if (underlyingCaps == null) continue;
                 for (int underlyingType : underlyingCaps.getTransportTypes()) {
                     transportTypes = ArrayUtils.appendInt(transportTypes, underlyingType);
                 }
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
index b1db6b1..ef4dbf5 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
@@ -116,16 +116,12 @@
     /**
      * Returns the current generation ID of the platform key. This increments whenever a platform
      * key has to be replaced. (e.g., because the user has removed and then re-added their lock
-     * screen).
+     * screen). Returns -1 if no key has been generated yet.
      *
      * @hide
      */
     public int getGenerationId() {
-        int generationId = mDatabase.getPlatformKeyGenerationId(mUserId);
-        if (generationId == -1) {
-            return 1;
-        }
-        return generationId;
+        return mDatabase.getPlatformKeyGenerationId(mUserId);
     }
 
     /**
@@ -208,14 +204,22 @@
                     Locale.US, "Platform key generation %d exists already.", generationId));
             return;
         }
-        if (generationId == 1) {
+        if (generationId == -1) {
             Log.i(TAG, "Generating initial platform ID.");
         } else {
             Log.w(TAG, String.format(Locale.US, "Platform generation ID was %d but no "
                     + "entry was present in AndroidKeyStore. Generating fresh key.", generationId));
         }
 
+        if (generationId == -1) {
+            generationId = 1;
+        } else {
+            // Had to generate a fresh key, bump the generation id
+            generationId++;
+        }
+
         generateAndLoadKey(generationId);
+        mDatabase.setPlatformKeyGenerationId(mUserId, generationId);
     }
 
     /**
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index fe1cad4..eccf241 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -216,7 +216,6 @@
         // Any application should be able to check status for its own keys.
         // If caller is a recovery agent it can check statuses for other packages, but
         // only for recoverable keys it manages.
-        checkRecoverKeyStorePermission();
         return mDatabase.getStatusForAllKeys(Binder.getCallingUid());
     }
 
diff --git a/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java b/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java
index 171703a..f35e6ec 100644
--- a/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java
+++ b/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java
@@ -33,6 +33,7 @@
 import android.util.Slog;
 
 import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.net.INetworkWatchlistManager;
@@ -92,6 +93,7 @@
         }
     }
 
+    @GuardedBy("mLoggingSwitchLock")
     private volatile boolean mIsLoggingEnabled = false;
     private final Object mLoggingSwitchLock = new Object();
 
@@ -220,36 +222,11 @@
         }
     }
 
-    /**
-     * Set a new network watchlist.
-     * This method should be called by ConfigUpdater only.
-     *
-     * @return True if network watchlist is updated.
-     */
-    public boolean setNetworkSecurityWatchlist(List<byte[]> domainsCrc32Digests,
-            List<byte[]> domainsSha256Digests,
-            List<byte[]> ipAddressesCrc32Digests,
-            List<byte[]> ipAddressesSha256Digests) {
-        Slog.i(TAG, "Setting network watchlist");
-        if (domainsCrc32Digests == null || domainsSha256Digests == null
-                || ipAddressesCrc32Digests == null || ipAddressesSha256Digests == null) {
-            Slog.e(TAG, "Parameters cannot be null");
-            return false;
-        }
-        if (domainsCrc32Digests.size() != domainsSha256Digests.size()
-                || ipAddressesCrc32Digests.size() != ipAddressesSha256Digests.size()) {
-            Slog.e(TAG, "Must need to have the same number of CRC32 and SHA256 digests");
-            return false;
-        }
-        if (domainsSha256Digests.size() + ipAddressesSha256Digests.size()
-                > MAX_NUM_OF_WATCHLIST_DIGESTS) {
-            Slog.e(TAG, "Total watchlist size cannot exceed " + MAX_NUM_OF_WATCHLIST_DIGESTS);
-            return false;
-        }
-        mSettings.writeSettingsToDisk(domainsCrc32Digests, domainsSha256Digests,
-                ipAddressesCrc32Digests, ipAddressesSha256Digests);
-        Slog.i(TAG, "Set network watchlist: Success");
-        return true;
+    @Override
+    public void reloadWatchlist() throws RemoteException {
+        enforceWatchlistLoggingPermission();
+        Slog.i(TAG, "Reloading watchlist");
+        mSettings.reloadSettings();
     }
 
     @Override
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java b/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java
index f48463f..838aa53 100644
--- a/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java
@@ -21,10 +21,12 @@
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
+import android.os.Environment;
 import android.util.Pair;
 
 import com.android.internal.util.HexDump;
 
+import java.io.File;
 import java.util.ArrayList;
 import java.util.GregorianCalendar;
 import java.util.HashMap;
@@ -83,9 +85,12 @@
         HashMap<String, String> appDigestCNCList;
     }
 
+    static File getSystemWatchlistDbFile() {
+        return new File(Environment.getDataSystemDirectory(), NAME);
+    }
+
     private WatchlistReportDbHelper(Context context) {
-        super(context, WatchlistSettings.getSystemWatchlistFile(NAME).getAbsolutePath(),
-                null, VERSION);
+        super(context, getSystemWatchlistDbFile().getAbsolutePath(), null, VERSION);
         // Memory optimization - close idle connections after 30s of inactivity
         setIdleConnectionTimeout(IDLE_CONNECTION_TIMEOUT_MS);
     }
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java b/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java
index c50f0d5..70002ea 100644
--- a/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java
@@ -19,8 +19,10 @@
 import android.os.Environment;
 import android.util.AtomicFile;
 import android.util.Log;
+import android.util.Slog;
 import android.util.Xml;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.HexDump;
@@ -51,10 +53,9 @@
 class WatchlistSettings {
     private static final String TAG = "WatchlistSettings";
 
-    // Settings xml will be stored in /data/system/network_watchlist/watchlist_settings.xml
-    static final String SYSTEM_WATCHLIST_DIR = "network_watchlist";
-
-    private static final String WATCHLIST_XML_FILE = "watchlist_settings.xml";
+    // Watchlist config that pushed by ConfigUpdater.
+    private static final String NETWORK_WATCHLIST_DB_PATH =
+            "/data/misc/network_watchlist/network_watchlist.xml";
 
     private static class XmlTags {
         private static final String WATCHLIST_SETTINGS = "watchlist-settings";
@@ -65,86 +66,74 @@
         private static final String HASH = "hash";
     }
 
-    private static WatchlistSettings sInstance = new WatchlistSettings();
-    private final AtomicFile mXmlFile;
-    private final Object mLock = new Object();
-    private HarmfulDigests mCrc32DomainDigests = new HarmfulDigests(new ArrayList<>());
-    private HarmfulDigests mSha256DomainDigests = new HarmfulDigests(new ArrayList<>());
-    private HarmfulDigests mCrc32IpDigests = new HarmfulDigests(new ArrayList<>());
-    private HarmfulDigests mSha256IpDigests = new HarmfulDigests(new ArrayList<>());
+    private static class CrcShaDigests {
+        final HarmfulDigests crc32Digests;
+        final HarmfulDigests sha256Digests;
 
-    public static synchronized WatchlistSettings getInstance() {
+        public CrcShaDigests(HarmfulDigests crc32Digests, HarmfulDigests sha256Digests) {
+            this.crc32Digests = crc32Digests;
+            this.sha256Digests = sha256Digests;
+        }
+    }
+
+    private final static WatchlistSettings sInstance = new WatchlistSettings();
+    private final AtomicFile mXmlFile;
+
+    private volatile CrcShaDigests mDomainDigests;
+    private volatile CrcShaDigests mIpDigests;
+
+    public static WatchlistSettings getInstance() {
         return sInstance;
     }
 
     private WatchlistSettings() {
-        this(getSystemWatchlistFile(WATCHLIST_XML_FILE));
+        this(new File(NETWORK_WATCHLIST_DB_PATH));
     }
 
     @VisibleForTesting
     protected WatchlistSettings(File xmlFile) {
         mXmlFile = new AtomicFile(xmlFile);
-        readSettingsLocked();
+        reloadSettings();
     }
 
-    static File getSystemWatchlistFile(String filename) {
-        final File dataSystemDir = Environment.getDataSystemDirectory();
-        final File systemWatchlistDir = new File(dataSystemDir, SYSTEM_WATCHLIST_DIR);
-        systemWatchlistDir.mkdirs();
-        return new File(systemWatchlistDir, filename);
-    }
-
-    private void readSettingsLocked() {
-        synchronized (mLock) {
-            FileInputStream stream;
-            try {
-                stream = mXmlFile.openRead();
-            } catch (FileNotFoundException e) {
-                Log.i(TAG, "No watchlist settings: " + mXmlFile.getBaseFile().getAbsolutePath());
-                return;
-            }
+    public void reloadSettings() {
+        try (FileInputStream stream = mXmlFile.openRead()){
 
             final List<byte[]> crc32DomainList = new ArrayList<>();
             final List<byte[]> sha256DomainList = new ArrayList<>();
             final List<byte[]> crc32IpList = new ArrayList<>();
             final List<byte[]> sha256IpList = new ArrayList<>();
 
-            try {
-                XmlPullParser parser = Xml.newPullParser();
-                parser.setInput(stream, StandardCharsets.UTF_8.name());
-                parser.nextTag();
-                parser.require(XmlPullParser.START_TAG, null, XmlTags.WATCHLIST_SETTINGS);
-                while (parser.nextTag() == XmlPullParser.START_TAG) {
-                    String tagName = parser.getName();
-                    switch (tagName) {
-                        case XmlTags.CRC32_DOMAIN:
-                            parseHash(parser, tagName, crc32DomainList);
-                            break;
-                        case XmlTags.CRC32_IP:
-                            parseHash(parser, tagName, crc32IpList);
-                            break;
-                        case XmlTags.SHA256_DOMAIN:
-                            parseHash(parser, tagName, sha256DomainList);
-                            break;
-                        case XmlTags.SHA256_IP:
-                            parseHash(parser, tagName, sha256IpList);
-                            break;
-                        default:
-                            Log.w(TAG, "Unknown element: " + parser.getName());
-                            XmlUtils.skipCurrentTag(parser);
-                    }
-                }
-                parser.require(XmlPullParser.END_TAG, null, XmlTags.WATCHLIST_SETTINGS);
-                writeSettingsToMemory(crc32DomainList, sha256DomainList, crc32IpList, sha256IpList);
-            } catch (IllegalStateException | NullPointerException | NumberFormatException |
-                    XmlPullParserException | IOException | IndexOutOfBoundsException e) {
-                Log.w(TAG, "Failed parsing " + e);
-            } finally {
-                try {
-                    stream.close();
-                } catch (IOException e) {
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(stream, StandardCharsets.UTF_8.name());
+            parser.nextTag();
+            parser.require(XmlPullParser.START_TAG, null, XmlTags.WATCHLIST_SETTINGS);
+            while (parser.nextTag() == XmlPullParser.START_TAG) {
+                String tagName = parser.getName();
+                switch (tagName) {
+                    case XmlTags.CRC32_DOMAIN:
+                        parseHash(parser, tagName, crc32DomainList);
+                        break;
+                    case XmlTags.CRC32_IP:
+                        parseHash(parser, tagName, crc32IpList);
+                        break;
+                    case XmlTags.SHA256_DOMAIN:
+                        parseHash(parser, tagName, sha256DomainList);
+                        break;
+                    case XmlTags.SHA256_IP:
+                        parseHash(parser, tagName, sha256IpList);
+                        break;
+                    default:
+                        Log.w(TAG, "Unknown element: " + parser.getName());
+                        XmlUtils.skipCurrentTag(parser);
                 }
             }
+            parser.require(XmlPullParser.END_TAG, null, XmlTags.WATCHLIST_SETTINGS);
+            writeSettingsToMemory(crc32DomainList, sha256DomainList, crc32IpList, sha256IpList);
+            Log.i(TAG, "Reload watchlist done");
+        } catch (IllegalStateException | NullPointerException | NumberFormatException |
+                XmlPullParserException | IOException | IndexOutOfBoundsException e) {
+            Slog.e(TAG, "Failed parsing xml", e);
         }
     }
 
@@ -161,101 +150,61 @@
     }
 
     /**
-     * Write network watchlist settings to disk.
-     * Adb should not use it, should use writeSettingsToMemory directly instead.
-     */
-    public void writeSettingsToDisk(List<byte[]> newCrc32DomainList,
-            List<byte[]> newSha256DomainList,
-            List<byte[]> newCrc32IpList,
-            List<byte[]> newSha256IpList) {
-        synchronized (mLock) {
-            FileOutputStream stream;
-            try {
-                stream = mXmlFile.startWrite();
-            } catch (IOException e) {
-                Log.w(TAG, "Failed to write display settings: " + e);
-                return;
-            }
-
-            try {
-                XmlSerializer out = new FastXmlSerializer();
-                out.setOutput(stream, StandardCharsets.UTF_8.name());
-                out.startDocument(null, true);
-                out.startTag(null, XmlTags.WATCHLIST_SETTINGS);
-
-                writeHashSetToXml(out, XmlTags.SHA256_DOMAIN, newSha256DomainList);
-                writeHashSetToXml(out, XmlTags.SHA256_IP, newSha256IpList);
-                writeHashSetToXml(out, XmlTags.CRC32_DOMAIN, newCrc32DomainList);
-                writeHashSetToXml(out, XmlTags.CRC32_IP, newCrc32IpList);
-
-                out.endTag(null, XmlTags.WATCHLIST_SETTINGS);
-                out.endDocument();
-                mXmlFile.finishWrite(stream);
-                writeSettingsToMemory(newCrc32DomainList, newSha256DomainList, newCrc32IpList,
-                        newSha256IpList);
-            } catch (IOException e) {
-                Log.w(TAG, "Failed to write display settings, restoring backup.", e);
-                mXmlFile.failWrite(stream);
-            }
-        }
-    }
-
-    /**
      * Write network watchlist settings to memory.
      */
     public void writeSettingsToMemory(List<byte[]> newCrc32DomainList,
             List<byte[]> newSha256DomainList,
             List<byte[]> newCrc32IpList,
             List<byte[]> newSha256IpList) {
-        synchronized (mLock) {
-            mCrc32DomainDigests = new HarmfulDigests(newCrc32DomainList);
-            mCrc32IpDigests = new HarmfulDigests(newCrc32IpList);
-            mSha256DomainDigests = new HarmfulDigests(newSha256DomainList);
-            mSha256IpDigests = new HarmfulDigests(newSha256IpList);
-        }
-    }
-
-    private static void writeHashSetToXml(XmlSerializer out, String tagName, List<byte[]> hashSet)
-            throws IOException {
-        out.startTag(null, tagName);
-        for (byte[] hash : hashSet) {
-            out.startTag(null, XmlTags.HASH);
-            out.text(HexDump.toHexString(hash));
-            out.endTag(null, XmlTags.HASH);
-        }
-        out.endTag(null, tagName);
+        mDomainDigests = new CrcShaDigests(new HarmfulDigests(newCrc32DomainList),
+                new HarmfulDigests(newSha256DomainList));
+        mIpDigests = new CrcShaDigests(new HarmfulDigests(newCrc32IpList),
+                new HarmfulDigests(newSha256IpList));
     }
 
     public boolean containsDomain(String domain) {
+        final CrcShaDigests domainDigests = mDomainDigests;
+        if (domainDigests == null) {
+            Slog.wtf(TAG, "domainDigests should not be null");
+            return false;
+        }
         // First it does a quick CRC32 check.
         final byte[] crc32 = getCrc32(domain);
-        if (!mCrc32DomainDigests.contains(crc32)) {
+        if (!domainDigests.crc32Digests.contains(crc32)) {
             return false;
         }
         // Now we do a slow SHA256 check.
         final byte[] sha256 = getSha256(domain);
-        return mSha256DomainDigests.contains(sha256);
+        return domainDigests.sha256Digests.contains(sha256);
     }
 
     public boolean containsIp(String ip) {
+        final CrcShaDigests ipDigests = mIpDigests;
+        if (ipDigests == null) {
+            Slog.wtf(TAG, "ipDigests should not be null");
+            return false;
+        }
         // First it does a quick CRC32 check.
         final byte[] crc32 = getCrc32(ip);
-        if (!mCrc32IpDigests.contains(crc32)) {
+        if (!ipDigests.crc32Digests.contains(crc32)) {
             return false;
         }
         // Now we do a slow SHA256 check.
         final byte[] sha256 = getSha256(ip);
-        return mSha256IpDigests.contains(sha256);
+        return ipDigests.sha256Digests.contains(sha256);
     }
 
 
-    /** Get CRC32 of a string */
+    /** Get CRC32 of a string
+     *
+     * TODO: Review if we should use CRC32 or other algorithms
+     */
     private byte[] getCrc32(String str) {
         final CRC32 crc = new CRC32();
         crc.update(str.getBytes());
         final long tmp = crc.getValue();
-        return new byte[]{(byte)(tmp >> 24 & 255), (byte)(tmp >> 16 & 255),
-                (byte)(tmp >> 8 & 255), (byte)(tmp & 255)};
+        return new byte[]{(byte) (tmp >> 24 & 255), (byte) (tmp >> 16 & 255),
+                (byte) (tmp >> 8 & 255), (byte) (tmp & 255)};
     }
 
     /** Get SHA256 of a string */
@@ -273,12 +222,12 @@
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("Domain CRC32 digest list:");
-        mCrc32DomainDigests.dump(fd, pw, args);
+        mDomainDigests.crc32Digests.dump(fd, pw, args);
         pw.println("Domain SHA256 digest list:");
-        mSha256DomainDigests.dump(fd, pw, args);
+        mDomainDigests.sha256Digests.dump(fd, pw, args);
         pw.println("Ip CRC32 digest list:");
-        mCrc32IpDigests.dump(fd, pw, args);
+        mIpDigests.crc32Digests.dump(fd, pw, args);
         pw.println("Ip SHA256 digest list:");
-        mSha256IpDigests.dump(fd, pw, args);
+        mIpDigests.sha256Digests.dump(fd, pw, args);
     }
 }
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 02c8f68..bc7f2e6 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -57,6 +57,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.WorkSource;
+import android.os.WorkSource.WorkChain;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.service.dreams.DreamManagerInternal;
@@ -1976,6 +1977,16 @@
                     return true;
                 }
             }
+
+            final ArrayList<WorkChain> workChains = wakeLock.mWorkSource.getWorkChains();
+            if (workChains != null) {
+                for (int k = 0; k < workChains.size(); k++) {
+                    final int uid = workChains.get(k).getAttributionUid();
+                    if (userId == UserHandle.getUserId(uid)) {
+                        return true;
+                    }
+                }
+            }
         }
         return userId == UserHandle.getUserId(wakeLock.mOwnerUid);
     }
diff --git a/services/core/java/com/android/server/updates/NetworkWatchlistInstallReceiver.java b/services/core/java/com/android/server/updates/NetworkWatchlistInstallReceiver.java
new file mode 100644
index 0000000..3b7ddc2
--- /dev/null
+++ b/services/core/java/com/android/server/updates/NetworkWatchlistInstallReceiver.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2017 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.
+ */
+
+package com.android.server.updates;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.NetworkWatchlistManager;
+import android.os.RemoteException;
+import android.util.Slog;
+
+public class NetworkWatchlistInstallReceiver extends ConfigUpdateInstallReceiver {
+
+    public NetworkWatchlistInstallReceiver() {
+        super("/data/misc/network_watchlist/", "network_watchlist.xml", "metadata/", "version");
+    }
+
+    @Override
+    protected void postInstall(Context context, Intent intent) {
+        try {
+            context.getSystemService(NetworkWatchlistManager.class).reloadWatchlist();
+        } catch (Exception e) {
+            // Network Watchlist is not available
+            Slog.wtf("NetworkWatchlistInstallReceiver", "Unable to reload watchlist");
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index dfb385b..863922f 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2222,12 +2222,13 @@
                         mWinAnimator + ": " + mPolicyVisibilityAfterAnim);
             }
             mPolicyVisibility = mPolicyVisibilityAfterAnim;
-            setDisplayLayoutNeeded();
             if (!mPolicyVisibility) {
+                mWinAnimator.hide("checkPolicyVisibilityChange");
                 if (mService.mCurrentFocus == this) {
                     if (DEBUG_FOCUS_LIGHT) Slog.i(TAG,
                             "setAnimationLocked: setting mFocusMayChange true");
                     mService.mFocusMayChange = true;
+                    setDisplayLayoutNeeded();
                 }
                 // Window is no longer visible -- make sure if we were waiting
                 // for it to be displayed before enabling the display, that
@@ -4291,8 +4292,22 @@
         float9[Matrix.MSKEW_Y] = mWinAnimator.mDtDx;
         float9[Matrix.MSKEW_X] = mWinAnimator.mDtDy;
         float9[Matrix.MSCALE_Y] = mWinAnimator.mDsDy;
-        float9[Matrix.MTRANS_X] = mSurfacePosition.x + mShownPosition.x;
-        float9[Matrix.MTRANS_Y] = mSurfacePosition.y + mShownPosition.y;
+        int x = mSurfacePosition.x + mShownPosition.x;
+        int y = mSurfacePosition.y + mShownPosition.y;
+
+        // If changed, also adjust transformFrameToSurfacePosition
+        final WindowContainer parent = getParent();
+        if (isChildWindow()) {
+            final WindowState parentWindow = getParentWindow();
+            x += parentWindow.mFrame.left - parentWindow.mAttrs.surfaceInsets.left;
+            y += parentWindow.mFrame.top - parentWindow.mAttrs.surfaceInsets.top;
+        } else if (parent != null) {
+            final Rect parentBounds = parent.getBounds();
+            x += parentBounds.left;
+            y += parentBounds.top;
+        }
+        float9[Matrix.MTRANS_X] = x;
+        float9[Matrix.MTRANS_Y] = y;
         float9[Matrix.MPERSP_0] = 0;
         float9[Matrix.MPERSP_1] = 0;
         float9[Matrix.MPERSP_2] = 1;
@@ -4439,6 +4454,8 @@
 
     private void transformFrameToSurfacePosition(int left, int top, Point outPoint) {
         outPoint.set(left, top);
+
+        // If changed, also adjust getTransformationMatrix
         final WindowContainer parentWindowContainer = getParent();
         if (isChildWindow()) {
             // TODO: This probably falls apart at some point and we should
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java
index 8a54c4e..8d5556e 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java
@@ -32,6 +32,7 @@
 
 import android.annotation.NonNull;
 import android.content.Context;
+import android.os.Message;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
 import android.util.DebugUtils;
@@ -48,6 +49,34 @@
 import java.util.function.IntConsumer;
 
 
+/**
+ * Tests the state transitions of {@link MagnificationGestureHandler}
+ *
+ * Here's a dot graph describing the transitions being tested:
+ * {@code
+ *      digraph {
+ *          IDLE -> SHORTCUT_TRIGGERED [label="a11y\nbtn"]
+ *          SHORTCUT_TRIGGERED -> IDLE [label="a11y\nbtn"]
+ *          IDLE -> DOUBLE_TAP [label="2tap"]
+ *          DOUBLE_TAP -> IDLE [label="timeout"]
+ *          DOUBLE_TAP -> TRIPLE_TAP_AND_HOLD [label="down"]
+ *          SHORTCUT_TRIGGERED -> TRIPLE_TAP_AND_HOLD [label="down"]
+ *          TRIPLE_TAP_AND_HOLD -> ZOOMED [label="up"]
+ *          TRIPLE_TAP_AND_HOLD -> DRAGGING_TMP [label="hold/\nswipe"]
+ *          DRAGGING_TMP -> IDLE [label="release"]
+ *          ZOOMED -> ZOOMED_DOUBLE_TAP [label="2tap"]
+ *          ZOOMED_DOUBLE_TAP -> ZOOMED [label="timeout"]
+ *          ZOOMED_DOUBLE_TAP -> DRAGGING [label="hold"]
+ *          ZOOMED_DOUBLE_TAP -> IDLE [label="tap"]
+ *          DRAGGING -> ZOOMED [label="release"]
+ *          ZOOMED -> IDLE [label="a11y\nbtn"]
+ *          ZOOMED -> PANNING [label="2hold"]
+ *          PANNING -> PANNING_SCALING [label="pinch"]
+ *          PANNING_SCALING -> ZOOMED [label="release"]
+ *          PANNING -> ZOOMED [label="release"]
+ *      }
+ * }
+ */
 @RunWith(AndroidJUnit4.class)
 public class MagnificationGestureHandlerTest {
 
@@ -76,6 +105,8 @@
     private MagnificationGestureHandler mMgh;
     private TestHandler mHandler;
 
+    private long mLastDownTime = Integer.MIN_VALUE;
+
     @Before
     public void setUp() {
         mContext = InstrumentationRegistry.getContext();
@@ -104,7 +135,13 @@
         MagnificationGestureHandler h = new MagnificationGestureHandler(
                 mContext, mMagnificationController,
                 detectTripleTap, detectShortcutTrigger);
-        mHandler = new TestHandler(h.mDetectingState, mClock);
+        mHandler = new TestHandler(h.mDetectingState, mClock) {
+            @Override
+            protected String messageToString(Message m) {
+                return DebugUtils.valueToString(
+                        MagnificationGestureHandler.DetectingState.class, "MESSAGE_", m.what);
+            }
+        };
         h.mDetectingState.mHandler = mHandler;
         h.setNext(strictMock(EventStreamTransformation.class));
         return h;
@@ -184,11 +221,11 @@
             fastForward1sec();
         }, STATE_ZOOMED);
 
-        // tap+tap+swipe gets delegated
-        assertTransition(STATE_2TAPS, () -> {
-            allowEventDelegation();
-            swipe();
-        }, STATE_IDLE);
+        // tap+tap+swipe doesn't get delegated
+        assertTransition(STATE_2TAPS, () -> swipe(), STATE_IDLE);
+
+        // tap+tap+swipe initiates viewport dragging immediately
+        assertTransition(STATE_2TAPS, () -> swipeAndHold(), STATE_DRAGGING_TMP);
     }
 
     @Test
@@ -439,23 +476,24 @@
     }
 
     private void tap() {
-        MotionEvent downEvent = downEvent();
-        send(downEvent);
-        send(upEvent(downEvent.getDownTime()));
+        send(downEvent());
+        send(upEvent());
     }
 
     private void swipe() {
-        MotionEvent downEvent = downEvent();
-        send(downEvent);
+        swipeAndHold();
+        send(upEvent());
+    }
+
+    private void swipeAndHold() {
+        send(downEvent());
         send(moveEvent(DEFAULT_X * 2, DEFAULT_Y * 2));
-        send(upEvent(downEvent.getDownTime()));
     }
 
     private void longTap() {
-        MotionEvent downEvent = downEvent();
-        send(downEvent);
+        send(downEvent());
         fastForward(2000);
-        send(upEvent(downEvent.getDownTime()));
+        send(upEvent());
     }
 
     private void triggerShortcut() {
@@ -473,16 +511,17 @@
     }
 
     private MotionEvent moveEvent(float x, float y) {
-        return MotionEvent.obtain(defaultDownTime(), mClock.now(), ACTION_MOVE, x, y, 0);
+        return MotionEvent.obtain(mLastDownTime, mClock.now(), ACTION_MOVE, x, y, 0);
     }
 
     private MotionEvent downEvent() {
-        return MotionEvent.obtain(mClock.now(), mClock.now(),
+        mLastDownTime = mClock.now();
+        return MotionEvent.obtain(mLastDownTime, mLastDownTime,
                 ACTION_DOWN, DEFAULT_X, DEFAULT_Y, 0);
     }
 
     private MotionEvent upEvent() {
-        return upEvent(defaultDownTime());
+        return upEvent(mLastDownTime);
     }
 
     private MotionEvent upEvent(long downTime) {
@@ -490,11 +529,6 @@
                 MotionEvent.ACTION_UP, DEFAULT_X, DEFAULT_Y, 0);
     }
 
-    private long defaultDownTime() {
-        MotionEvent lastDown = mMgh.mDetectingState.mLastDown;
-        return lastDown == null ? mClock.now() - 1 : lastDown.getDownTime();
-    }
-
     private MotionEvent pointerEvent(int action, float x, float y) {
         MotionEvent.PointerProperties defPointerProperties = new MotionEvent.PointerProperties();
         defPointerProperties.id = 0;
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
index 6f13a98..97fbca2 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
@@ -205,6 +205,14 @@
     }
 
     @Test
+    public void init_savesGenerationIdToDatabase() throws Exception {
+        mPlatformKeyManager.init();
+
+        assertEquals(1,
+                mRecoverableKeyStoreDb.getPlatformKeyGenerationId(USER_ID_FIXTURE));
+    }
+
+    @Test
     public void init_setsGenerationIdTo1() throws Exception {
         mPlatformKeyManager.init();
 
@@ -212,7 +220,38 @@
     }
 
     @Test
+    public void init_incrementsGenerationIdIfKeyIsUnavailable() throws Exception {
+        mPlatformKeyManager.init();
+
+        mPlatformKeyManager.init();
+
+        assertEquals(2, mPlatformKeyManager.getGenerationId());
+    }
+
+    @Test
+    public void init_doesNotIncrementGenerationIdIfKeyAvailable() throws Exception {
+        mPlatformKeyManager.init();
+        when(mKeyStoreProxy
+                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
+                        + "platform/42/1/decrypt")).thenReturn(true);
+        when(mKeyStoreProxy
+                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
+                        + "platform/42/1/encrypt")).thenReturn(true);
+
+        mPlatformKeyManager.init();
+
+        assertEquals(1, mPlatformKeyManager.getGenerationId());
+    }
+
+    @Test
+    public void getGenerationId_returnsMinusOneIfNotInitialized() throws Exception {
+        assertEquals(-1, mPlatformKeyManager.getGenerationId());
+    }
+
+    @Test
     public void getDecryptKey_getsDecryptKeyWithCorrectAlias() throws Exception {
+        mPlatformKeyManager.init();
+
         mPlatformKeyManager.getDecryptKey();
 
         verify(mKeyStoreProxy).getKey(
@@ -222,6 +261,8 @@
 
     @Test
     public void getEncryptKey_getsDecryptKeyWithCorrectAlias() throws Exception {
+        mPlatformKeyManager.init();
+
         mPlatformKeyManager.getEncryptKey();
 
         verify(mKeyStoreProxy).getKey(
diff --git a/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistSettingsTests.java b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistSettingsTests.java
index f3cb980..212d25d 100644
--- a/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistSettingsTests.java
@@ -95,41 +95,6 @@
     }
 
     @Test
-    public void testWatchlistSettings_writeSettingsToDisk() throws Exception {
-        copyWatchlistSettingsXml(mContext, TEST_XML_1, mTestXmlFile);
-        WatchlistSettings settings = new WatchlistSettings(mTestXmlFile);
-        settings.writeSettingsToDisk(Arrays.asList(TEST_NEW_CC_DOMAIN_CRC32),
-                Arrays.asList(TEST_NEW_CC_DOMAIN_SHA256), Arrays.asList(TEST_NEW_CC_IP_CRC32),
-                Arrays.asList(TEST_NEW_CC_IP_SHA256));
-        // Ensure old watchlist is not in memory
-        assertFalse(settings.containsDomain(TEST_CC_DOMAIN));
-        assertFalse(settings.containsIp(TEST_CC_IP));
-        assertFalse(settings.containsDomain(TEST_NOT_EXIST_CC_DOMAIN));
-        assertFalse(settings.containsIp(TEST_NOT_EXIST_CC_IP));
-        assertFalse(settings.containsDomain(TEST_SHA256_ONLY_DOMAIN));
-        assertFalse(settings.containsIp(TEST_SHA256_ONLY_IP));
-        assertFalse(settings.containsDomain(TEST_CRC32_ONLY_DOMAIN));
-        assertFalse(settings.containsIp(TEST_CRC32_ONLY_IP));
-        // Ensure new watchlist is in memory
-        assertTrue(settings.containsDomain(TEST_NEW_CC_DOMAIN));
-        assertTrue(settings.containsIp(TEST_NEW_CC_IP));
-        // Reload settings from disk and test again
-        settings = new WatchlistSettings(mTestXmlFile);
-        // Ensure old watchlist is not in memory
-        assertFalse(settings.containsDomain(TEST_CC_DOMAIN));
-        assertFalse(settings.containsIp(TEST_CC_IP));
-        assertFalse(settings.containsDomain(TEST_NOT_EXIST_CC_DOMAIN));
-        assertFalse(settings.containsIp(TEST_NOT_EXIST_CC_IP));
-        assertFalse(settings.containsDomain(TEST_SHA256_ONLY_DOMAIN));
-        assertFalse(settings.containsIp(TEST_SHA256_ONLY_IP));
-        assertFalse(settings.containsDomain(TEST_CRC32_ONLY_DOMAIN));
-        assertFalse(settings.containsIp(TEST_CRC32_ONLY_IP));
-        // Ensure new watchlist is in memory
-        assertTrue(settings.containsDomain(TEST_NEW_CC_DOMAIN));
-        assertTrue(settings.containsIp(TEST_NEW_CC_IP));
-    }
-
-    @Test
     public void testWatchlistSettings_writeSettingsToMemory() throws Exception {
         copyWatchlistSettingsXml(mContext, TEST_XML_1, mTestXmlFile);
         WatchlistSettings settings = new WatchlistSettings(mTestXmlFile);
diff --git a/services/tests/servicestests/src/com/android/server/testutils/TestHandler.java b/services/tests/servicestests/src/com/android/server/testutils/TestHandler.java
index 2d4bc0f..029d9f1 100644
--- a/services/tests/servicestests/src/com/android/server/testutils/TestHandler.java
+++ b/services/tests/servicestests/src/com/android/server/testutils/TestHandler.java
@@ -104,6 +104,15 @@
         return new PriorityQueue<>(mMessages);
     }
 
+    /**
+     * Optionally-overridable to allow deciphering message types
+     *
+     * @see android.util.DebugUtils#valueToString - a handy utility to use when overriding this
+     */
+    protected String messageToString(Message message) {
+        return message.toString();
+    }
+
     private void dispatch(MsgInfo msg) {
         int msgId = msg.message.what;
 
@@ -148,7 +157,7 @@
         @Override
         public String toString() {
             return "MsgInfo{" +
-                    "message=" + message +
+                    "message=" + messageToString(message) +
                     ", sendTime=" + sendTime +
                     '}';
         }
diff --git a/tests/DexLoggerIntegrationTests/Android.mk b/tests/DexLoggerIntegrationTests/Android.mk
new file mode 100644
index 0000000..7187a37
--- /dev/null
+++ b/tests/DexLoggerIntegrationTests/Android.mk
@@ -0,0 +1,49 @@
+#
+# Copyright 2017 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+# Build a tiny library that the test app can dynamically load
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE := DexLoggerTestLibrary
+LOCAL_SRC_FILES := $(call all-java-files-under, src/com/android/dcl)
+
+include $(BUILD_JAVA_LIBRARY)
+
+dexloggertest_jar := $(LOCAL_BUILT_MODULE)
+
+
+# Build the test app itself
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_PACKAGE_NAME := DexLoggerIntegrationTests
+LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_CERTIFICATE := platform
+LOCAL_SRC_FILES := $(call all-java-files-under, src/com/android/server/pm)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    android-support-test \
+    truth-prebuilt \
+
+# This gets us the javalib.jar built by DexLoggerTestLibrary above.
+LOCAL_JAVA_RESOURCE_FILES := $(dexloggertest_jar)
+
+include $(BUILD_PACKAGE)
diff --git a/tests/DexLoggerIntegrationTests/AndroidManifest.xml b/tests/DexLoggerIntegrationTests/AndroidManifest.xml
new file mode 100644
index 0000000..a847e8f
--- /dev/null
+++ b/tests/DexLoggerIntegrationTests/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2017 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.frameworks.dexloggertest">
+
+    <!-- Tests feature introduced in P (27) -->
+    <uses-sdk
+        android:minSdkVersion="27"
+        android:targetSdkVersion="27" />
+
+    <uses-permission android:name="android.permission.READ_LOGS" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation
+        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.frameworks.dexloggertest"
+        android:label="Integration test for DexLogger" />
+</manifest>
diff --git a/tests/DexLoggerIntegrationTests/AndroidTest.xml b/tests/DexLoggerIntegrationTests/AndroidTest.xml
new file mode 100644
index 0000000..8ed19f8
--- /dev/null
+++ b/tests/DexLoggerIntegrationTests/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2017 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.
+-->
+<configuration description="Runs DexLogger Integration Tests">
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="DexLoggerIntegrationTests.apk"/>
+        <option name="cleanup-apks" value="true"/>
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct"/>
+    <option name="test-tag" value="DexLoggerIntegrationTests"/>
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+        <option name="package" value="com.android.frameworks.dexloggertest"/>
+        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
+    </test>
+</configuration>
diff --git a/tests/DexLoggerIntegrationTests/src/com/android/dcl/Simple.java b/tests/DexLoggerIntegrationTests/src/com/android/dcl/Simple.java
new file mode 100644
index 0000000..e995a26
--- /dev/null
+++ b/tests/DexLoggerIntegrationTests/src/com/android/dcl/Simple.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2017 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.
+ */
+
+package com.android.dcl;
+
+/** Dummy class which is built into a jar purely so we can pass it to DexClassLoader. */
+public final class Simple {
+    public Simple() {}
+}
diff --git a/tests/DexLoggerIntegrationTests/src/com/android/server/pm/DexLoggerIntegrationTests.java b/tests/DexLoggerIntegrationTests/src/com/android/server/pm/DexLoggerIntegrationTests.java
new file mode 100644
index 0000000..d9f34d5
--- /dev/null
+++ b/tests/DexLoggerIntegrationTests/src/com/android/server/pm/DexLoggerIntegrationTests.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2017 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.
+ */
+
+package com.android.server.pm;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.util.EventLog;
+
+import dalvik.system.DexClassLoader;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.MessageDigest;
+import java.util.ArrayList;
+import java.util.Formatter;
+import java.util.List;
+
+/**
+ * Integration tests for {@link com.android.server.pm.dex.DexLogger}.
+ *
+ * The setup for the test dynamically loads code in a jar extracted
+ * from our assets (a secondary dex file).
+ *
+ * We then use adb to trigger secondary dex file reconcilation (and
+ * wait for it to complete). As a side-effect of this DexLogger should
+ * be notified of the file and should log the hash of the file's name
+ * and content.  We verify that this message appears in the event log.
+ *
+ * Run with "atest DexLoggerIntegrationTests".
+ */
+@RunWith(JUnit4.class)
+public final class DexLoggerIntegrationTests {
+
+    private static final String TAG = DexLoggerIntegrationTests.class.getSimpleName();
+
+    private static final String PACKAGE_NAME = "com.android.frameworks.dexloggertest";
+
+    private static final int SNET_TAG = 0x534e4554;
+    private static final String DCL_SUBTAG = "dcl";
+
+    // Obtained via "echo -n copied.jar | sha256sum"
+    private static final String EXPECTED_NAME_HASH =
+            "1B6C71DB26F36582867432CCA12FB6A517470C9F9AABE9198DD4C5C030D6DC0C";
+
+    private static String expectedContentHash;
+
+    @BeforeClass
+    public static void setUpAll() throws Exception {
+        Context context = InstrumentationRegistry.getTargetContext();
+        MessageDigest hasher = MessageDigest.getInstance("SHA-256");
+
+        // Copy the jar from our Java resources to a private data directory
+        File privateCopy = new File(context.getDir("jars", Context.MODE_PRIVATE), "copied.jar");
+        try (InputStream input = DexLoggerIntegrationTests.class.getResourceAsStream("/javalib.jar");
+                OutputStream output = new FileOutputStream(privateCopy)) {
+            byte[] buffer = new byte[1024];
+            while (true) {
+                int numRead = input.read(buffer);
+                if (numRead < 0) {
+                    break;
+                }
+                output.write(buffer, 0, numRead);
+                hasher.update(buffer, 0, numRead);
+            }
+        }
+
+        // Remember the SHA-256 of the file content to check that it is the same as
+        // the value we see logged.
+        Formatter formatter = new Formatter();
+        for (byte b : hasher.digest()) {
+            formatter.format("%02X", b);
+        }
+        expectedContentHash = formatter.toString();
+
+        // Feed the jar to a class loader and make sure it contains what we expect.
+        ClassLoader loader =
+                new DexClassLoader(
+                    privateCopy.toString(), null, null, context.getClass().getClassLoader());
+        loader.loadClass("com.android.dcl.Simple");
+    }
+
+    @Test
+    public void testDexLoggerReconcileGeneratesEvents() throws Exception {
+        int[] tagList = new int[] { SNET_TAG };
+        List<EventLog.Event> events = new ArrayList<>();
+
+        // There may already be events in the event log - figure out the most recent one
+        EventLog.readEvents(tagList, events);
+        long previousEventNanos = events.isEmpty() ? 0 : events.get(events.size() - 1).getTimeNanos();
+        events.clear();
+
+        Process process = Runtime.getRuntime().exec(
+            "cmd package reconcile-secondary-dex-files " + PACKAGE_NAME);
+        int exitCode = process.waitFor();
+        assertThat(exitCode).isEqualTo(0);
+
+        int myUid = android.os.Process.myUid();
+        String expectedMessage = EXPECTED_NAME_HASH + " " + expectedContentHash;
+
+        EventLog.readEvents(tagList, events);
+        boolean found = false;
+        for (EventLog.Event event : events) {
+            if (event.getTimeNanos() <= previousEventNanos) {
+                continue;
+            }
+            Object[] data = (Object[]) event.getData();
+
+            // We only care about DCL events that we generated.
+            String subTag = (String) data[0];
+            if (!DCL_SUBTAG.equals(subTag)) {
+                continue;
+            }
+            int uid = (int) data[1];
+            if (uid != myUid) {
+                continue;
+            }
+
+            String message = (String) data[2];
+            assertThat(message).isEqualTo(expectedMessage);
+            found = true;
+        }
+
+        assertThat(found).isTrue();
+    }
+}