[DRUEL04] Implement unsolicited NAT64 prefix event

Implement unsolicited NAT64 prefix event that will report to the
listener when change NAT64 prefix.

Bug: 173485754
Test: atest resolv_integration_test resolv_unit_test\
      resolv_stress_test resolv_stats_test_utils_test
Change-Id: If20353529969ffa956b56d19345519f286046e25
diff --git a/ResolverController.cpp b/ResolverController.cpp
index 7b181e2..b193af1 100644
--- a/ResolverController.cpp
+++ b/ResolverController.cpp
@@ -35,6 +35,8 @@
 #include "stats.h"
 
 using aidl::android::net::ResolverParamsParcel;
+using aidl::android::net::resolv::aidl::IDnsResolverUnsolicitedEventListener;
+using aidl::android::net::resolv::aidl::Nat64PrefixEventParcel;
 
 namespace android {
 
@@ -45,14 +47,30 @@
 namespace {
 
 void sendNat64PrefixEvent(const Dns64Configuration::Nat64PrefixInfo& args) {
+    LOG(DEBUG) << "Sending Nat64Prefix " << (args.added ? "added" : "removed") << " event on netId "
+               << args.netId << " with address {" << args.prefixString << "(" << args.prefixLength
+               << ")}";
+    // Send a nat64 prefix event to NetdEventListenerService.
     const auto& listeners = ResolverEventReporter::getInstance().getListeners();
-    if (listeners.size() == 0) {
-        LOG(ERROR) << __func__ << ": No available listener. dropping NAT64 prefix event";
-        return;
+    if (listeners.empty()) {
+        LOG(ERROR) << __func__ << ": No available listener. Skipping NAT64 prefix event";
     }
     for (const auto& it : listeners) {
         it->onNat64PrefixEvent(args.netId, args.added, args.prefixString, args.prefixLength);
     }
+
+    const auto& unsolEventListeners = ResolverEventReporter::getInstance().getUnsolEventListeners();
+    const Nat64PrefixEventParcel nat64PrefixEvent = {
+            .netId = static_cast<int32_t>(args.netId),
+            .prefixOperation =
+                    args.added ? IDnsResolverUnsolicitedEventListener::PREFIX_OPERATION_ADDED
+                               : IDnsResolverUnsolicitedEventListener::PREFIX_OPERATION_REMOVED,
+            .prefixAddress = args.prefixString,
+            .prefixLength = args.prefixLength,
+    };
+    for (const auto& it : unsolEventListeners) {
+        it->onNat64PrefixEvent(nat64PrefixEvent);
+    }
 }
 
 int getDnsInfo(unsigned netId, std::vector<std::string>* servers, std::vector<std::string>* domains,
diff --git a/tests/resolv_integration_test.cpp b/tests/resolv_integration_test.cpp
index 714b2db..890c599 100644
--- a/tests/resolv_integration_test.cpp
+++ b/tests/resolv_integration_test.cpp
@@ -96,6 +96,7 @@
 using aidl::android::net::ResolverParamsParcel;
 using aidl::android::net::metrics::INetdEventListener;
 using aidl::android::net::resolv::aidl::IDnsResolverUnsolicitedEventListener;
+using aidl::android::net::resolv::aidl::Nat64PrefixEventParcel;
 using aidl::android::net::resolv::aidl::PrivateDnsValidationEventParcel;
 using android::base::Error;
 using android::base::ParseInt;
@@ -258,7 +259,12 @@
 
     bool WaitForNat64Prefix(ExpectNat64PrefixStatus status,
                             std::chrono::milliseconds timeout = std::chrono::milliseconds(1000)) {
-        return sDnsMetricsListener->waitForNat64Prefix(status, timeout);
+        return sDnsMetricsListener->waitForNat64Prefix(status, timeout) &&
+               sUnsolicitedEventListener->waitForNat64Prefix(
+                       status == EXPECT_FOUND
+                               ? IDnsResolverUnsolicitedEventListener::PREFIX_OPERATION_ADDED
+                               : IDnsResolverUnsolicitedEventListener::PREFIX_OPERATION_REMOVED,
+                       timeout);
     }
 
     bool WaitForPrivateDnsValidation(std::string serverAddr, bool validated) {
@@ -4031,6 +4037,7 @@
     EXPECT_TRUE(WaitForNat64Prefix(EXPECT_NOT_FOUND));
 
     EXPECT_EQ(0, sDnsMetricsListener->getUnexpectedNat64PrefixUpdates());
+    EXPECT_EQ(0, sUnsolicitedEventListener->getUnexpectedNat64PrefixUpdates());
 }
 
 namespace {
diff --git a/tests/unsolicited_listener/unsolicited_event_listener.cpp b/tests/unsolicited_listener/unsolicited_event_listener.cpp
index f5ebb0b..8cf7505 100644
--- a/tests/unsolicited_listener/unsolicited_event_listener.cpp
+++ b/tests/unsolicited_listener/unsolicited_event_listener.cpp
@@ -23,11 +23,14 @@
 
 namespace android::net::resolv::aidl {
 
+using ::aidl::android::net::resolv::aidl::IDnsResolverUnsolicitedEventListener;
+using ::aidl::android::net::resolv::aidl::Nat64PrefixEventParcel;
 using ::aidl::android::net::resolv::aidl::PrivateDnsValidationEventParcel;
 using android::base::ScopedLockAssertion;
 using std::chrono::milliseconds;
 
 constexpr milliseconds kEventTimeoutMs{5000};
+constexpr milliseconds kRetryIntervalMs{20};
 
 ::ndk::ScopedAStatus UnsolicitedEventListener::onDnsHealthEvent(
         const ::aidl::android::net::resolv::aidl::DnsHealthEventParcel&) {
@@ -36,8 +39,15 @@
 }
 
 ::ndk::ScopedAStatus UnsolicitedEventListener::onNat64PrefixEvent(
-        const ::aidl::android::net::resolv::aidl::Nat64PrefixEventParcel&) {
-    // default no-op
+        const Nat64PrefixEventParcel& event) {
+    std::lock_guard lock(mMutex);
+    mUnexpectedNat64PrefixUpdates++;
+    if (event.netId == mNetId) {
+        mNat64PrefixAddress = (event.prefixOperation ==
+                               IDnsResolverUnsolicitedEventListener::PREFIX_OPERATION_ADDED)
+                                      ? event.prefixAddress
+                                      : "";
+    }
     return ::ndk::ScopedAStatus::ok();
 }
 
@@ -77,4 +87,22 @@
     return false;
 }
 
+bool UnsolicitedEventListener::waitForNat64Prefix(int operation, const milliseconds& timeout) {
+    android::base::Timer t;
+    while (t.duration() < timeout) {
+        {
+            std::lock_guard lock(mMutex);
+            if ((operation == IDnsResolverUnsolicitedEventListener::PREFIX_OPERATION_ADDED &&
+                 !mNat64PrefixAddress.empty()) ||
+                (operation == IDnsResolverUnsolicitedEventListener::PREFIX_OPERATION_REMOVED &&
+                 mNat64PrefixAddress.empty())) {
+                mUnexpectedNat64PrefixUpdates--;
+                return true;
+            }
+        }
+        std::this_thread::sleep_for(kRetryIntervalMs);
+    }
+    return false;
+}
+
 }  // namespace android::net::resolv::aidl
diff --git a/tests/unsolicited_listener/unsolicited_event_listener.h b/tests/unsolicited_listener/unsolicited_event_listener.h
index 5615f24..e8fce1d 100644
--- a/tests/unsolicited_listener/unsolicited_event_listener.h
+++ b/tests/unsolicited_listener/unsolicited_event_listener.h
@@ -44,15 +44,26 @@
     // Wait for the expected private DNS validation result until timeout.
     bool waitForPrivateDnsValidation(const std::string& serverAddr, int validation);
 
+    // Wait for expected NAT64 prefix operation until timeout.
+    bool waitForNat64Prefix(int operation, const std::chrono::milliseconds& timeout)
+            EXCLUDES(mMutex);
+
     // Return true if a validation result for |serverAddr| is found; otherwise, return false.
     bool findValidationRecord(const std::string& serverAddr) const EXCLUDES(mMutex) {
         std::lock_guard lock(mMutex);
         return mValidationRecords.find({mNetId, serverAddr}) != mValidationRecords.end();
     }
 
+    // Returns the number of updates to the NAT64 prefix that have not yet been waited for.
+    int getUnexpectedNat64PrefixUpdates() const EXCLUDES(mMutex) {
+        std::lock_guard lock(mMutex);
+        return mUnexpectedNat64PrefixUpdates;
+    }
+
     void reset() EXCLUDES(mMutex) {
         std::lock_guard lock(mMutex);
         mValidationRecords.clear();
+        mUnexpectedNat64PrefixUpdates = 0;
     }
 
   private:
@@ -68,6 +79,16 @@
     // Used to store the data from onPrivateDnsValidationEvent.
     std::map<ServerKey, int> mValidationRecords GUARDED_BY(mMutex);
 
+    // The NAT64 prefix address of the network |mNetId|. It is updated by onNat64PrefixEvent().
+    std::string mNat64PrefixAddress GUARDED_BY(mMutex);
+
+    // The number of updates to the NAT64 prefix of network |mNetId| that have not yet been waited
+    // for. Increases by 1 every time onNat64PrefixEvent is called, and decreases by 1 every time
+    // waitForNat64Prefix returns true.
+    // This allows tests to check that no unexpected events have been received without having to
+    // resort to timeouts that make the tests slower and flakier.
+    int mUnexpectedNat64PrefixUpdates GUARDED_BY(mMutex);
+
     mutable std::mutex mMutex;
     std::condition_variable mCv;
 };