Snap for 8820681 from 65cde24694b87599f693be7041e28c7538f2c66d to mainline-go-resolv-release

Change-Id: Ib2416baa3112daceea3a29cd9ae46d9e8b095f60
diff --git a/lib/libstatspull/Android.bp b/lib/libstatspull/Android.bp
index c0bc46d..60f237c 100644
--- a/lib/libstatspull/Android.bp
+++ b/lib/libstatspull/Android.bp
@@ -123,7 +123,7 @@
     test_suites: ["general-tests", "mts-statsd"],
     test_config: "libstatspull_test.xml",
 
-    //TODO(b/153588990): Remove when the build system properly separates 
+    //TODO(b/153588990): Remove when the build system properly separates
     //32bit and 64bit architectures.
     compile_multilib: "both",
     multilib: {
diff --git a/lib/libstatspull/stats_pull_atom_callback.cpp b/lib/libstatspull/stats_pull_atom_callback.cpp
index f85db08..8a1c89b 100644
--- a/lib/libstatspull/stats_pull_atom_callback.cpp
+++ b/lib/libstatspull/stats_pull_atom_callback.cpp
@@ -14,13 +14,6 @@
  * limitations under the License.
  */
 
-#include <map>
-#include <thread>
-#include <vector>
-
-#include <stats_event.h>
-#include <stats_pull_atom_callback.h>
-
 #include <aidl/android/os/BnPullAtomCallback.h>
 #include <aidl/android/os/IPullAtomResultReceiver.h>
 #include <aidl/android/os/IStatsd.h>
@@ -28,6 +21,12 @@
 #include <android/binder_auto_utils.h>
 #include <android/binder_ibinder.h>
 #include <android/binder_manager.h>
+#include <stats_event.h>
+#include <stats_pull_atom_callback.h>
+
+#include <map>
+#include <thread>
+#include <vector>
 
 using Status = ::ndk::ScopedAStatus;
 using aidl::android::os::BnPullAtomCallback;
@@ -159,20 +158,20 @@
 };
 
 /**
- * @brief pullAtomMutex is used to guard simultaneous access to mPullers from below threads
+ * @brief pullersMutex is used to guard simultaneous access to pullers from below threads
  * Main thread
  * - AStatsManager_setPullAtomCallback()
  * - AStatsManager_clearPullAtomCallback()
  * Binder thread:
  * - StatsdProvider::binderDied()
  */
-static std::mutex pullAtomMutex;
+static std::mutex pullersMutex;
 
-static std::map<int32_t, std::shared_ptr<StatsPullAtomCallbackInternal>> mPullers;
+static std::map<int32_t, std::shared_ptr<StatsPullAtomCallbackInternal>> pullers;
 
 class StatsdProvider {
 public:
-    StatsdProvider() : deathRecipient(AIBinder_DeathRecipient_new(binderDied)) {
+    StatsdProvider() : mDeathRecipient(AIBinder_DeathRecipient_new(binderDied)) {
     }
 
     ~StatsdProvider() {
@@ -180,21 +179,21 @@
     }
 
     std::shared_ptr<IStatsd> getStatsService() {
-        std::lock_guard<std::mutex> lock(statsdMutex);
-        if (!statsd) {
+        std::lock_guard<std::mutex> lock(mStatsdMutex);
+        if (!mStatsd) {
             // Fetch statsd
             ::ndk::SpAIBinder binder(AServiceManager_getService("stats"));
-            statsd = IStatsd::fromBinder(binder);
-            if (statsd) {
-                AIBinder_linkToDeath(binder.get(), deathRecipient.get(), this);
+            mStatsd = IStatsd::fromBinder(binder);
+            if (mStatsd) {
+                AIBinder_linkToDeath(binder.get(), mDeathRecipient.get(), this);
             }
         }
-        return statsd;
+        return mStatsd;
     }
 
     void resetStatsService() {
-        std::lock_guard<std::mutex> lock(statsdMutex);
-        statsd = nullptr;
+        std::lock_guard<std::mutex> lock(mStatsdMutex);
+        mStatsd = nullptr;
     }
 
     static void binderDied(void* cookie) {
@@ -210,8 +209,8 @@
         // copy of the data with the lock held before iterating through the map.
         std::map<int32_t, std::shared_ptr<StatsPullAtomCallbackInternal>> pullersCopy;
         {
-            std::lock_guard<std::mutex> lock(pullAtomMutex);
-            pullersCopy = mPullers;
+            std::lock_guard<std::mutex> lock(pullersMutex);
+            pullersCopy = pullers;
         }
         for (const auto& it : pullersCopy) {
             statsService->registerNativePullAtomCallback(it.first, it.second->getCoolDownMillis(),
@@ -222,16 +221,16 @@
 
 private:
     /**
-     * @brief statsdMutex is used to guard simultaneous access to statsd from below threads:
+     * @brief mStatsdMutex is used to guard simultaneous access to mStatsd from below threads:
      * Work thread
      * - registerStatsPullAtomCallbackBlocking()
      * - unregisterStatsPullAtomCallbackBlocking()
      * Binder thread:
      * - StatsdProvider::binderDied()
      */
-    std::mutex statsdMutex;
-    std::shared_ptr<IStatsd> statsd;
-    ::ndk::ScopedAIBinder_DeathRecipient deathRecipient;
+    std::mutex mStatsdMutex;
+    std::shared_ptr<IStatsd> mStatsd;
+    ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
 };
 
 static std::shared_ptr<StatsdProvider> statsProvider = std::make_shared<StatsdProvider>();
@@ -276,9 +275,9 @@
                                                                timeoutMillis, additiveFields);
 
     {
-        std::lock_guard<std::mutex> lg(pullAtomMutex);
+        std::lock_guard<std::mutex> lock(pullersMutex);
         // Always add to the map. If statsd is dead, we will add them when it comes back.
-        mPullers[atom_tag] = callbackBinder;
+        pullers[atom_tag] = callbackBinder;
     }
 
     std::thread registerThread(registerStatsPullAtomCallbackBlocking, atom_tag, statsProvider,
@@ -288,10 +287,10 @@
 
 void AStatsManager_clearPullAtomCallback(int32_t atom_tag) {
     {
-        std::lock_guard<std::mutex> lg(pullAtomMutex);
+        std::lock_guard<std::mutex> lock(pullersMutex);
         // Always remove the puller from our map.
         // If statsd is down, we will not register it when it comes back.
-        mPullers.erase(atom_tag);
+        pullers.erase(atom_tag);
     }
 
     std::thread unregisterThread(unregisterStatsPullAtomCallbackBlocking, atom_tag, statsProvider);
diff --git a/lib/libstatssocket/statsd_writer.c b/lib/libstatssocket/statsd_writer.c
index c00c978..06695fe 100644
--- a/lib/libstatssocket/statsd_writer.c
+++ b/lib/libstatssocket/statsd_writer.c
@@ -76,7 +76,7 @@
 static int statsdOpen();
 static void statsdClose();
 static int statsdWrite(struct timespec* ts, struct iovec* vec, size_t nr);
-static void statsdNoteDrop();
+static void statsdNoteDrop(int error, int tag);
 static int statsdIsClosed();
 
 struct android_log_transport_write statsdLoggerWrite = {
diff --git a/statsd/src/flags/FlagProvider.h b/statsd/src/flags/FlagProvider.h
index dcdf35f..6684ba4 100644
--- a/statsd/src/flags/FlagProvider.h
+++ b/statsd/src/flags/FlagProvider.h
@@ -126,8 +126,7 @@
     FRIEND_TEST(FlagProviderTest_SPlus, TestGetFlagBoolServerFlagEmptyDefaultTrue);
     FRIEND_TEST(FlagProviderTest_SPlus_RealValues, TestGetBootFlagBoolServerFlagTrue);
     FRIEND_TEST(FlagProviderTest_SPlus_RealValues, TestGetBootFlagBoolServerFlagFalse);
-    FRIEND_TEST(MetricsManagerTest, TestAtomMatcherOptimizationEnabledFlagFalse);
-    FRIEND_TEST(MetricsManagerTest, TestAtomMatcherOptimizationEnabledFlagTrue);
+    FRIEND_TEST(MetricsManagerTest_SPlus, TestAtomMatcherOptimizationEnabledFlag);
 };
 
 }  // namespace statsd
diff --git a/statsd/src/main.cpp b/statsd/src/main.cpp
index 66b4389..cd64fe7 100644
--- a/statsd/src/main.cpp
+++ b/statsd/src/main.cpp
@@ -39,20 +39,12 @@
 
 shared_ptr<StatsService> gStatsService = nullptr;
 sp<StatsSocketListener> gSocketListener = nullptr;
+int gCtrlPipe[2];
 
 void signalHandler(int sig) {
-    if (sig == SIGPIPE) {
-        // ShellSubscriber uses SIGPIPE as a signal to detect the end of the
-        // client process. Don't prematurely exit(1) here. Instead, ignore the
-        // signal and allow the write call to return EPIPE.
-        ALOGI("statsd received SIGPIPE. Ignoring signal.");
-        return;
-    }
-
-    if (gSocketListener != nullptr) gSocketListener->stopListener();
-    if (gStatsService != nullptr) gStatsService->Terminate();
     ALOGW("statsd terminated on receiving signal %d.", sig);
-    exit(1);
+    const char c = 'q';
+    write(gCtrlPipe[1], &c, 1);
 }
 
 void registerSignalHandlers()
@@ -60,11 +52,15 @@
     struct sigaction sa;
     sigemptyset(&sa.sa_mask);
     sa.sa_flags = 0;
-    sa.sa_handler = signalHandler;
+
+    sa.sa_handler = SIG_IGN;
+    // ShellSubscriber uses SIGPIPE as a signal to detect the end of the
+    // client process. Don't prematurely exit(1) here. Instead, ignore the
+    // signal and allow the write call to return EPIPE.
     sigaction(SIGPIPE, &sa, nullptr);
-    sigaction(SIGHUP, &sa, nullptr);
-    sigaction(SIGINT, &sa, nullptr);
-    sigaction(SIGQUIT, &sa, nullptr);
+
+    pipe2(gCtrlPipe, O_CLOEXEC);
+    sa.sa_handler = signalHandler;
     sigaction(SIGTERM, &sa, nullptr);
 }
 
@@ -94,8 +90,6 @@
         return -1;
     }
 
-    registerSignalHandlers();
-
     gStatsService->sayHiToStatsCompanion();
 
     gStatsService->Startup();
@@ -108,6 +102,22 @@
         exit(1);
     }
 
+    // Use self-pipe to notify this thread to gracefully quit
+    // when receiving SIGTERM
+    registerSignalHandlers();
+    std::thread([] {
+        while (true) {
+            char c;
+            int i = read(gCtrlPipe[0], &c, 1);
+            if (i < 0) {
+                if (errno == EINTR) continue;
+            }
+            gSocketListener->stopListener();
+            gStatsService->Terminate();
+            exit(1);
+        }
+    }).detach();
+
     // Loop forever -- the reports run on this thread in a handler, and the
     // binder calls remain responsive in their pool of one thread.
     while (true) {
diff --git a/statsd/src/matchers/matcher_util.cpp b/statsd/src/matchers/matcher_util.cpp
index 27b9fb2..20450dd 100644
--- a/statsd/src/matchers/matcher_util.cpp
+++ b/statsd/src/matchers/matcher_util.cpp
@@ -16,9 +16,12 @@
 #define STATSD_DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
-#include "src/statsd_config.pb.h"
-#include "matchers/AtomMatchingTracker.h"
 #include "matchers/matcher_util.h"
+
+#include <fnmatch.h>
+
+#include "matchers/AtomMatchingTracker.h"
+#include "src/statsd_config.pb.h"
 #include "stats_util.h"
 
 using std::set;
@@ -97,6 +100,33 @@
     return false;
 }
 
+bool tryMatchWildcardString(const sp<UidMap>& uidMap, const FieldValue& fieldValue,
+                            const string& wildcardPattern) {
+    if (isAttributionUidField(fieldValue) || isUidField(fieldValue)) {
+        int uid = fieldValue.mValue.int_value;
+        // TODO(b/236886985): replace aid/uid mapping with efficient bidirectional container
+        // AidToUidMapping will never have uids above 10000
+        if (uid < 10000) {
+            for (auto aidIt = UidMap::sAidToUidMapping.begin();
+                 aidIt != UidMap::sAidToUidMapping.end(); ++aidIt) {
+                if ((int)aidIt->second == uid) {
+                    // Assumes there is only one aid mapping for each uid
+                    return fnmatch(wildcardPattern.c_str(), aidIt->first.c_str(), 0) == 0;
+                }
+            }
+        }
+        std::set<string> packageNames = uidMap->getAppNamesFromUid(uid, true /* normalize*/);
+        for (const auto& packageName : packageNames) {
+            if (fnmatch(wildcardPattern.c_str(), packageName.c_str(), 0) == 0) {
+                return true;
+            }
+        }
+    } else if (fieldValue.mValue.getType() == STRING) {
+        return fnmatch(wildcardPattern.c_str(), fieldValue.mValue.str_value.c_str(), 0) == 0;
+    }
+    return false;
+}
+
 bool matchesSimple(const sp<UidMap>& uidMap, const FieldValueMatcher& matcher,
                    const vector<FieldValue>& values, int start, int end, int depth) {
     if (depth > 2) {
@@ -237,13 +267,18 @@
         case FieldValueMatcher::ValueMatcherCase::kNeqAnyString: {
             const auto& str_list = matcher.neq_any_string();
             for (int i = start; i < end; i++) {
+                bool notEqAll = true;
                 for (const auto& str : str_list.str_value()) {
                     if (tryMatchString(uidMap, values[i], str)) {
-                        return false;
+                        notEqAll = false;
+                        break;
                     }
                 }
+                if (notEqAll) {
+                    return true;
+                }
             }
-            return true;
+            return false;
         }
         case FieldValueMatcher::ValueMatcherCase::kEqAnyString: {
             const auto& str_list = matcher.eq_any_string();
@@ -256,6 +291,41 @@
             }
             return false;
         }
+        case FieldValueMatcher::ValueMatcherCase::kEqWildcardString: {
+            for (int i = start; i < end; i++) {
+                if (tryMatchWildcardString(uidMap, values[i], matcher.eq_wildcard_string())) {
+                    return true;
+                }
+            }
+            return false;
+        }
+        case FieldValueMatcher::ValueMatcherCase::kEqAnyWildcardString: {
+            const auto& str_list = matcher.eq_any_wildcard_string();
+            for (int i = start; i < end; i++) {
+                for (const auto& str : str_list.str_value()) {
+                    if (tryMatchWildcardString(uidMap, values[i], str)) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+        case FieldValueMatcher::ValueMatcherCase::kNeqAnyWildcardString: {
+            const auto& str_list = matcher.neq_any_wildcard_string();
+            for (int i = start; i < end; i++) {
+                bool notEqAll = true;
+                for (const auto& str : str_list.str_value()) {
+                    if (tryMatchWildcardString(uidMap, values[i], str)) {
+                        notEqAll = false;
+                        break;
+                    }
+                }
+                if (notEqAll) {
+                    return true;
+                }
+            }
+            return false;
+        }
         case FieldValueMatcher::ValueMatcherCase::kEqInt: {
             for (int i = start; i < end; i++) {
                 if (values[i].mValue.getType() == INT &&
@@ -270,6 +340,46 @@
             }
             return false;
         }
+        case FieldValueMatcher::ValueMatcherCase::kEqAnyInt: {
+            const auto& int_list = matcher.eq_any_int();
+            for (int i = start; i < end; i++) {
+                for (const int int_value : int_list.int_value()) {
+                    if (values[i].mValue.getType() == INT &&
+                        (int_value == values[i].mValue.int_value)) {
+                        return true;
+                    }
+                    // eq_any_int covers both int and long.
+                    if (values[i].mValue.getType() == LONG &&
+                        (int_value == values[i].mValue.long_value)) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+        case FieldValueMatcher::ValueMatcherCase::kNeqAnyInt: {
+            const auto& int_list = matcher.neq_any_int();
+            for (int i = start; i < end; i++) {
+                bool notEqAll = true;
+                for (const int int_value : int_list.int_value()) {
+                    if (values[i].mValue.getType() == INT &&
+                        (int_value == values[i].mValue.int_value)) {
+                        notEqAll = false;
+                        break;
+                    }
+                    // neq_any_int covers both int and long.
+                    if (values[i].mValue.getType() == LONG &&
+                        (int_value == values[i].mValue.long_value)) {
+                        notEqAll = false;
+                        break;
+                    }
+                }
+                if (notEqAll) {
+                    return true;
+                }
+            }
+            return false;
+        }
         case FieldValueMatcher::ValueMatcherCase::kLtInt: {
             for (int i = start; i < end; i++) {
                 if (values[i].mValue.getType() == INT &&
diff --git a/statsd/src/metrics/MetricsManager.h b/statsd/src/metrics/MetricsManager.h
index 1eccf8d..c855a05 100644
--- a/statsd/src/metrics/MetricsManager.h
+++ b/statsd/src/metrics/MetricsManager.h
@@ -347,10 +347,9 @@
     FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithSameDeactivation);
     FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations);
 
-    FRIEND_TEST(MetricsManagerTest, TestAtomMatcherOptimizationEnabledFlagFalse);
-    FRIEND_TEST(MetricsManagerTest, TestAtomMatcherOptimizationEnabledFlagTrue);
     FRIEND_TEST(MetricsManagerTest, TestLogSources);
     FRIEND_TEST(MetricsManagerTest, TestLogSourcesOnConfigUpdate);
+    FRIEND_TEST(MetricsManagerTest_SPlus, TestAtomMatcherOptimizationEnabledFlag);
 
     FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead);
     FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot);
diff --git a/statsd/src/statsd_config.proto b/statsd/src/statsd_config.proto
index be733b4..b75b670 100644
--- a/statsd/src/statsd_config.proto
+++ b/statsd/src/statsd_config.proto
@@ -78,6 +78,12 @@
 
     StringListMatcher eq_any_string = 13;
     StringListMatcher neq_any_string = 14;
+    IntListMatcher eq_any_int = 15;
+    IntListMatcher neq_any_int = 16;
+
+    string eq_wildcard_string = 17;
+    StringListMatcher eq_any_wildcard_string = 18;
+    StringListMatcher neq_any_wildcard_string = 19;
   }
 }
 
@@ -89,6 +95,10 @@
     repeated string str_value = 1;
 }
 
+message IntListMatcher {
+    repeated int64 int_value = 1;
+}
+
 enum LogicalOperation {
   LOGICAL_OPERATION_UNSPECIFIED = 0;
   AND = 1;
diff --git a/statsd/tests/LogEntryMatcher_test.cpp b/statsd/tests/LogEntryMatcher_test.cpp
index 8a4fb19..d0a063f 100644
--- a/statsd/tests/LogEntryMatcher_test.cpp
+++ b/statsd/tests/LogEntryMatcher_test.cpp
@@ -948,7 +948,7 @@
     fieldValueMatcher->set_position(Position::LAST);
     EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
     fieldValueMatcher->set_position(Position::ANY);
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
 
     neqStringList->add_str_value("str3");
     fieldValueMatcher->set_position(Position::FIRST);
@@ -956,7 +956,7 @@
     fieldValueMatcher->set_position(Position::LAST);
     EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
     fieldValueMatcher->set_position(Position::ANY);
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
 
     neqStringList->add_str_value("str1");
     fieldValueMatcher->set_position(Position::FIRST);
@@ -1204,6 +1204,303 @@
     matcherResults.push_back(MatchingState::kMatched);
     EXPECT_FALSE(combinationMatch(children, operation, matcherResults));
 }
+
+TEST(AtomMatcherTest, TestUidFieldMatcherWithWildcardString) {
+    sp<UidMap> uidMap = new UidMap();
+    uidMap->updateMap(
+            1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
+            {android::String16("v1"), android::String16("v1"), android::String16("v2"),
+             android::String16("v1"), android::String16("v2")},
+            {android::String16("package0"), android::String16("pkg1"), android::String16("pkg1"),
+             android::String16("package2"), android::String16("package3")} /* package name list */,
+            {android::String16(""), android::String16(""), android::String16(""),
+             android::String16(""), android::String16("")},
+            /* certificateHash */ {{}, {}, {}, {}, {}});
+
+    // Set up matcher
+    AtomMatcher matcher;
+    auto simpleMatcher = matcher.mutable_simple_atom_matcher();
+    simpleMatcher->set_atom_id(TAG_ID);
+    simpleMatcher->add_field_value_matcher()->set_field(1);
+    simpleMatcher->mutable_field_value_matcher(0)->set_eq_wildcard_string("pkg*");
+
+    // Event without is_uid annotation.
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    makeIntLogEvent(&event1, TAG_ID, 0, 1111);
+    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event1));
+
+    // Event where mapping from uid to package name occurs.
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    makeIntWithBoolAnnotationLogEvent(&event2, TAG_ID, 1111, ANNOTATION_ID_IS_UID, true);
+    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2));
+
+    // Event where uid maps to package names that don't fit wildcard pattern.
+    LogEvent event3(/*uid=*/0, /*pid=*/0);
+    makeIntWithBoolAnnotationLogEvent(&event3, TAG_ID, 3333, ANNOTATION_ID_IS_UID, true);
+    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event3));
+
+    // Update matcher to match one AID
+    simpleMatcher->mutable_field_value_matcher(0)->set_eq_wildcard_string(
+            "AID_SYSTEM");  // uid 1000
+
+    // Event where mapping from uid to aid doesn't fit wildcard pattern.
+    LogEvent event4(/*uid=*/0, /*pid=*/0);
+    makeIntWithBoolAnnotationLogEvent(&event4, TAG_ID, 1005, ANNOTATION_ID_IS_UID, true);
+    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event4));
+
+    // Event where mapping from uid to aid does fit wildcard pattern.
+    LogEvent event5(/*uid=*/0, /*pid=*/0);
+    makeIntWithBoolAnnotationLogEvent(&event5, TAG_ID, 1000, ANNOTATION_ID_IS_UID, true);
+    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event5));
+
+    // Update matcher to match multiple AIDs
+    simpleMatcher->mutable_field_value_matcher(0)->set_eq_wildcard_string("AID_SDCARD_*");
+
+    // Event where mapping from uid to aid doesn't fit wildcard pattern.
+    LogEvent event6(/*uid=*/0, /*pid=*/0);
+    makeIntWithBoolAnnotationLogEvent(&event6, TAG_ID, 1036, ANNOTATION_ID_IS_UID, true);
+    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event6));
+
+    // Event where mapping from uid to aid does fit wildcard pattern.
+    LogEvent event7(/*uid=*/0, /*pid=*/0);
+    makeIntWithBoolAnnotationLogEvent(&event7, TAG_ID, 1034, ANNOTATION_ID_IS_UID, true);
+    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event7));
+
+    LogEvent event8(/*uid=*/0, /*pid=*/0);
+    makeIntWithBoolAnnotationLogEvent(&event8, TAG_ID, 1035, ANNOTATION_ID_IS_UID, true);
+    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event8));
+}
+
+TEST(AtomMatcherTest, TestWildcardStringMatcher) {
+    sp<UidMap> uidMap = new UidMap();
+    // Set up the matcher
+    AtomMatcher matcher;
+    SimpleAtomMatcher* simpleMatcher = matcher.mutable_simple_atom_matcher();
+    simpleMatcher->set_atom_id(TAG_ID);
+    FieldValueMatcher* fieldValueMatcher = simpleMatcher->add_field_value_matcher();
+    fieldValueMatcher->set_field(FIELD_ID_1);
+    // Matches any string that begins with "test.string:test_" and ends with number between 0 and 9
+    // inclusive
+    fieldValueMatcher->set_eq_wildcard_string("test.string:test_[0-9]");
+
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    makeStringLogEvent(&event1, TAG_ID, 0, "test.string:test_0");
+    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event1));
+
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    makeStringLogEvent(&event2, TAG_ID, 0, "test.string:test_19");
+    EXPECT_FALSE(
+            matchesSimple(uidMap, *simpleMatcher, event2));  // extra character at end of string
+
+    LogEvent event3(/*uid=*/0, /*pid=*/0);
+    makeStringLogEvent(&event3, TAG_ID, 0, "extra.test.string:test_1");
+    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher,
+                               event3));  // extra characters at beginning of string
+
+    LogEvent event4(/*uid=*/0, /*pid=*/0);
+    makeStringLogEvent(&event4, TAG_ID, 0, "test.string:test_");
+    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher,
+                               event4));  // missing character from 0-9 at end of string
+
+    LogEvent event5(/*uid=*/0, /*pid=*/0);
+    makeStringLogEvent(&event5, TAG_ID, 0, "est.string:test_1");
+    EXPECT_FALSE(
+            matchesSimple(uidMap, *simpleMatcher, event5));  // missing 't' at beginning of string
+
+    LogEvent event6(/*uid=*/0, /*pid=*/0);
+    makeStringLogEvent(&event6, TAG_ID, 0, "test.string:test_1extra");
+    EXPECT_FALSE(
+            matchesSimple(uidMap, *simpleMatcher, event6));  // extra characters at end of string
+
+    // Matches any string that contains "test.string:test_" + any extra characters before or after
+    fieldValueMatcher->set_eq_wildcard_string("*test.string:test_*");
+
+    LogEvent event7(/*uid=*/0, /*pid=*/0);
+    makeStringLogEvent(&event7, TAG_ID, 0, "test.string:test_");
+    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event7));
+
+    LogEvent event8(/*uid=*/0, /*pid=*/0);
+    makeStringLogEvent(&event8, TAG_ID, 0, "extra.test.string:test_");
+    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event8));
+
+    LogEvent event9(/*uid=*/0, /*pid=*/0);
+    makeStringLogEvent(&event9, TAG_ID, 0, "test.string:test_extra");
+    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event9));
+
+    LogEvent event10(/*uid=*/0, /*pid=*/0);
+    makeStringLogEvent(&event10, TAG_ID, 0, "est.string:test_");
+    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event10));
+
+    LogEvent event11(/*uid=*/0, /*pid=*/0);
+    makeStringLogEvent(&event11, TAG_ID, 0, "test.string:test");
+    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event11));
+}
+
+TEST(AtomMatcherTest, TestEqAnyWildcardStringMatcher) {
+    sp<UidMap> uidMap = new UidMap();
+
+    // Set up the matcher
+    AtomMatcher matcher;
+    SimpleAtomMatcher* simpleMatcher = matcher.mutable_simple_atom_matcher();
+    simpleMatcher->set_atom_id(TAG_ID);
+
+    FieldValueMatcher* fieldValueMatcher = simpleMatcher->add_field_value_matcher();
+    fieldValueMatcher->set_field(FIELD_ID_1);
+    StringListMatcher* eqWildcardStrList = fieldValueMatcher->mutable_eq_any_wildcard_string();
+    eqWildcardStrList->add_str_value("first_string_*");
+    eqWildcardStrList->add_str_value("second_string_*");
+
+    // First wildcard pattern matched.
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    makeStringLogEvent(&event1, TAG_ID, 0, "first_string_1");
+    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event1));
+
+    // Second wildcard pattern matched.
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    makeStringLogEvent(&event2, TAG_ID, 0, "second_string_1");
+    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2));
+
+    // No wildcard patterns matched.
+    LogEvent event3(/*uid=*/0, /*pid=*/0);
+    makeStringLogEvent(&event3, TAG_ID, 0, "third_string_1");
+    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event3));
+}
+
+TEST(AtomMatcherTest, TestNeqAnyWildcardStringMatcher) {
+    sp<UidMap> uidMap = new UidMap();
+
+    // Set up the log event.
+    std::vector<int> attributionUids = {1111, 2222, 3333};
+    std::vector<string> attributionTags = {"location_1", "location_2", "location"};
+    LogEvent event(/*uid=*/0, /*pid=*/0);
+    makeAttributionLogEvent(&event, TAG_ID, 0, attributionUids, attributionTags, "some value");
+
+    // Set up the matcher. Match first tag.
+    AtomMatcher matcher;
+    SimpleAtomMatcher* simpleMatcher = matcher.mutable_simple_atom_matcher();
+    simpleMatcher->set_atom_id(TAG_ID);
+    FieldValueMatcher* attributionMatcher = simpleMatcher->add_field_value_matcher();
+    attributionMatcher->set_field(FIELD_ID_1);
+    attributionMatcher->set_position(Position::FIRST);
+    FieldValueMatcher* attributionTagMatcher =
+            attributionMatcher->mutable_matches_tuple()->add_field_value_matcher();
+    attributionTagMatcher->set_field(ATTRIBUTION_TAG_FIELD_ID);
+    StringListMatcher* neqWildcardStrList =
+            attributionTagMatcher->mutable_neq_any_wildcard_string();
+
+    // First tag is not matched. neq string list {"tag"}
+    neqWildcardStrList->add_str_value("tag");
+    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+
+    // First tag is matched. neq string list {"tag", "location_*"}
+    neqWildcardStrList->add_str_value("location_*");
+    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+
+    // Match last tag.
+    attributionMatcher->set_position(Position::LAST);
+
+    // Last tag is not matched. neq string list {"tag", "location_*"}
+    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+
+    // Last tag is matched. neq string list {"tag", "location_*", "location*"}
+    neqWildcardStrList->add_str_value("location*");
+    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+
+    // Match any tag.
+    attributionMatcher->set_position(Position::ANY);
+
+    // All tags are matched. neq string list {"tag", "location_*", "location*"}
+    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+
+    // Set up another log event.
+    std::vector<string> attributionTags2 = {"location_1", "location", "string"};
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    makeAttributionLogEvent(&event2, TAG_ID, 0, attributionUids, attributionTags2, "some value");
+
+    // Tag "string" is not matched. neq string list {"tag", "location_*", "location*"}
+    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2));
+}
+
+TEST(AtomMatcherTest, TestEqAnyIntMatcher) {
+    sp<UidMap> uidMap = new UidMap();
+
+    // Set up the matcher
+    AtomMatcher matcher;
+    SimpleAtomMatcher* simpleMatcher = matcher.mutable_simple_atom_matcher();
+    simpleMatcher->set_atom_id(TAG_ID);
+
+    FieldValueMatcher* fieldValueMatcher = simpleMatcher->add_field_value_matcher();
+    fieldValueMatcher->set_field(FIELD_ID_1);
+    IntListMatcher* eqIntList = fieldValueMatcher->mutable_eq_any_int();
+    eqIntList->add_int_value(3);
+    eqIntList->add_int_value(5);
+
+    // First int matched.
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    makeIntLogEvent(&event1, TAG_ID, 0, 3);
+    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event1));
+
+    // Second int matched.
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    makeIntLogEvent(&event2, TAG_ID, 0, 5);
+    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2));
+
+    // No ints matched.
+    LogEvent event3(/*uid=*/0, /*pid=*/0);
+    makeIntLogEvent(&event3, TAG_ID, 0, 4);
+    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event3));
+}
+
+TEST(AtomMatcherTest, TestNeqAnyIntMatcher) {
+    sp<UidMap> uidMap = new UidMap();
+
+    // Set up the log event.
+    std::vector<int> attributionUids = {1111, 2222, 3333};
+    std::vector<string> attributionTags = {"location1", "location2", "location3"};
+    LogEvent event(/*uid=*/0, /*pid=*/0);
+    makeAttributionLogEvent(&event, TAG_ID, 0, attributionUids, attributionTags, "some value");
+
+    // Set up the matcher. Match first uid.
+    AtomMatcher matcher;
+    SimpleAtomMatcher* simpleMatcher = matcher.mutable_simple_atom_matcher();
+    simpleMatcher->set_atom_id(TAG_ID);
+    FieldValueMatcher* attributionMatcher = simpleMatcher->add_field_value_matcher();
+    attributionMatcher->set_field(FIELD_ID_1);
+    attributionMatcher->set_position(Position::FIRST);
+    FieldValueMatcher* attributionUidMatcher =
+            attributionMatcher->mutable_matches_tuple()->add_field_value_matcher();
+    attributionUidMatcher->set_field(ATTRIBUTION_UID_FIELD_ID);
+    IntListMatcher* neqIntList = attributionUidMatcher->mutable_neq_any_int();
+
+    // First uid is not matched. neq int list {4444}
+    neqIntList->add_int_value(4444);
+    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+
+    // First uid is matched. neq int list {4444, 1111}
+    neqIntList->add_int_value(1111);
+    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+
+    // Match last uid.
+    attributionMatcher->set_position(Position::LAST);
+
+    // Last uid is not matched. neq int list {4444, 1111}
+    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+
+    // Last uid is matched. neq int list {4444, 1111, 3333}
+    neqIntList->add_int_value(3333);
+    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+
+    // Match any uid.
+    attributionMatcher->set_position(Position::ANY);
+
+    // Uid 2222 is not matched. neq int list {4444, 1111, 3333}
+    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
+
+    // All uids are matched. neq int list {4444, 1111, 3333, 2222}
+    neqIntList->add_int_value(2222);
+    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
+}
+
 #else
 GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif
diff --git a/statsd/tests/MetricsManager_test.cpp b/statsd/tests/MetricsManager_test.cpp
index 5cab800..9650f2d 100644
--- a/statsd/tests/MetricsManager_test.cpp
+++ b/statsd/tests/MetricsManager_test.cpp
@@ -35,6 +35,7 @@
 
 using namespace testing;
 using android::sp;
+using android::modules::sdklevel::IsAtLeastS;
 using android::os::statsd::Predicate;
 using std::map;
 using std::set;
@@ -264,8 +265,55 @@
                 UnorderedElementsAreArray(unionSet({defaultPullUids, app2Uids, {AID_ADB}})));
 }
 
-TEST(MetricsManagerTest, TestAtomMatcherOptimizationEnabledFlagFalse) {
-    FlagProvider::getInstance().overrideFlag(OPTIMIZATION_ATOM_MATCHER_MAP_FLAG, FLAG_FALSE,
+struct MetricsManagerServerFlagParam {
+    string flagValue;
+    string label;
+};
+
+class MetricsManagerTest_SPlus
+    : public ::testing::Test,
+      public ::testing::WithParamInterface<MetricsManagerServerFlagParam> {
+protected:
+    void SetUp() override {
+        if (shouldSkipTest()) {
+            GTEST_SKIP() << skipReason();
+        }
+
+        originalFlagValue = FlagProvider::getInstance().getFlagString(
+                OPTIMIZATION_ATOM_MATCHER_MAP_FLAG, FLAG_EMPTY);
+    }
+
+    bool shouldSkipTest() const {
+        return !IsAtLeastS();
+    }
+
+    string skipReason() const {
+        return "Skipping MetricsManagerTest_SPlus because device is not S+";
+    }
+
+    void TearDown() override {
+        if (originalFlagValue) {
+            writeFlag(OPTIMIZATION_ATOM_MATCHER_MAP_FLAG, originalFlagValue.value());
+        }
+    }
+
+    std::optional<string> originalFlagValue;
+};
+
+INSTANTIATE_TEST_SUITE_P(
+        MetricsManagerTest_SPlus, MetricsManagerTest_SPlus,
+        testing::ValuesIn<MetricsManagerServerFlagParam>({
+                // Server flag values
+                {FLAG_TRUE, "ServerFlagTrue"},
+                {FLAG_FALSE, "ServerFlagFalse"},
+        }),
+        [](const testing::TestParamInfo<MetricsManagerTest_SPlus::ParamType>& info) {
+            return info.param.label;
+        });
+
+TEST_P(MetricsManagerTest_SPlus, TestAtomMatcherOptimizationEnabledFlag) {
+    FlagProvider::getInstance().overrideFlag(OPTIMIZATION_ATOM_MATCHER_MAP_FLAG,
+                                             GetParam().flagValue,
                                              /*isBootFlag=*/true);
 
     sp<UidMap> uidMap;
@@ -277,23 +325,11 @@
     MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap,
                                   pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor);
 
-    EXPECT_FALSE(metricsManager.mAtomMatcherOptimizationEnabled);
-}
-
-TEST(MetricsManagerTest, TestAtomMatcherOptimizationEnabledFlagTrue) {
-    FlagProvider::getInstance().overrideFlag(OPTIMIZATION_ATOM_MATCHER_MAP_FLAG, FLAG_TRUE,
-                                             /*isBootFlag=*/true);
-
-    sp<UidMap> uidMap;
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> periodicAlarmMonitor;
-
-    StatsdConfig config = buildGoodConfig();
-    MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap,
-                                  pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor);
-
-    EXPECT_TRUE(metricsManager.mAtomMatcherOptimizationEnabled);
+    if (GetParam().flagValue == FLAG_TRUE) {
+        EXPECT_TRUE(metricsManager.mAtomMatcherOptimizationEnabled);
+    } else {
+        EXPECT_FALSE(metricsManager.mAtomMatcherOptimizationEnabled);
+    }
 }
 
 TEST(MetricsManagerTest, TestCheckLogCredentialsWhitelistedAtom) {
diff --git a/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java b/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java
index d02d2c4..06034cb 100644
--- a/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java
+++ b/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java
@@ -76,6 +76,7 @@
             "com.google.android.apps.nexuslauncher",
             "AID_KEYSTORE",
             "AID_VIRTUALIZATIONSERVICE",
+            "com.google.android.permissioncontroller",
     };
     private static final String[] DEFAULT_PULL_SOURCES = {
             "AID_KEYSTORE",