Add template binder call for registering OEM netd unsolicited listener

Bug: 131045919
Test: built, flashed, booted
        system/netd/tests/runtests.sh pass

Change-Id: Id391b3000842ccb4769f0f99bfffcd36a4cdfa35
diff --git a/server/Android.bp b/server/Android.bp
index 7083f47..d1586a2 100644
--- a/server/Android.bp
+++ b/server/Android.bp
@@ -46,10 +46,15 @@
 }
 
 aidl_interface {
+    // This interface is for OEM calls to netd and vice versa that do not exist in AOSP.
+    // Those calls cannot be part of INetd.aidl and INetdUnsolicitedEventListener.aidl
+    // because those interfaces are versioned.
+    // These interfaces must never be versioned or OEMs will not be able to change them.
     name: "oemnetd_aidl_interface",
     local_include_dir: "binder",
     srcs: [
         "binder/com/android/internal/net/IOemNetd.aidl",
+        "binder/com/android/internal/net/IOemNetdUnsolicitedEventListener.aidl",
     ],
 }
 
diff --git a/server/OemNetdListener.cpp b/server/OemNetdListener.cpp
index dddfef0..fb07a80 100644
--- a/server/OemNetdListener.cpp
+++ b/server/OemNetdListener.cpp
@@ -16,15 +16,8 @@
 
 #define LOG_TAG "OemNetd"
 
-#include <log/log.h>
-#include <utils/Errors.h>
-
-#include <binder/IPCThreadState.h>
-
 #include "OemNetdListener.h"
 
-#include "com/android/internal/net/BnOemNetd.h"
-
 namespace com {
 namespace android {
 namespace internal {
@@ -48,6 +41,46 @@
     return ::android::binder::Status::ok();
 }
 
+::android::binder::Status OemNetdListener::registerOemUnsolicitedEventListener(
+        const ::android::sp<IOemNetdUnsolicitedEventListener>& listener) {
+    registerOemUnsolicitedEventListenerInternal(listener);
+    listener->onRegistered();
+    return ::android::binder::Status::ok();
+}
+
+void OemNetdListener::registerOemUnsolicitedEventListenerInternal(
+        const ::android::sp<IOemNetdUnsolicitedEventListener>& listener) {
+    std::lock_guard lock(mOemUnsolicitedMutex);
+
+    // Create the death listener.
+    class DeathRecipient : public ::android::IBinder::DeathRecipient {
+      public:
+        DeathRecipient(OemNetdListener* oemNetdListener,
+                       ::android::sp<IOemNetdUnsolicitedEventListener> listener)
+            : mOemNetdListener(oemNetdListener), mListener(std::move(listener)) {}
+        ~DeathRecipient() override = default;
+        void binderDied(const ::android::wp<::android::IBinder>& /* who */) override {
+            mOemNetdListener->unregisterOemUnsolicitedEventListenerInternal(mListener);
+        }
+
+      private:
+        OemNetdListener* mOemNetdListener;
+        ::android::sp<IOemNetdUnsolicitedEventListener> mListener;
+    };
+    ::android::sp<::android::IBinder::DeathRecipient> deathRecipient =
+            new DeathRecipient(this, listener);
+
+    ::android::IInterface::asBinder(listener)->linkToDeath(deathRecipient);
+
+    mOemUnsolListenerMap.insert({listener, deathRecipient});
+}
+
+void OemNetdListener::unregisterOemUnsolicitedEventListenerInternal(
+        const ::android::sp<IOemNetdUnsolicitedEventListener>& listener) {
+    std::lock_guard lock(mOemUnsolicitedMutex);
+    mOemUnsolListenerMap.erase(listener);
+}
+
 }  // namespace net
 }  // namespace internal
 }  // namespace android
diff --git a/server/OemNetdListener.h b/server/OemNetdListener.h
index a17039c..4fb4fb7 100644
--- a/server/OemNetdListener.h
+++ b/server/OemNetdListener.h
@@ -17,7 +17,12 @@
 #ifndef NETD_SERVER_OEM_NETD_LISTENER_H
 #define NETD_SERVER_OEM_NETD_LISTENER_H
 
+#include <map>
+#include <mutex>
+
+#include <android-base/thread_annotations.h>
 #include "com/android/internal/net/BnOemNetd.h"
+#include "com/android/internal/net/IOemNetdUnsolicitedEventListener.h"
 
 namespace com {
 namespace android {
@@ -26,17 +31,32 @@
 
 class OemNetdListener : public BnOemNetd {
   public:
+    using OemUnsolListenerMap = std::map<const ::android::sp<IOemNetdUnsolicitedEventListener>,
+                                         const ::android::sp<::android::IBinder::DeathRecipient>>;
+
     OemNetdListener() = default;
     ~OemNetdListener() = default;
     static ::android::sp<::android::IBinder> getListener();
 
     ::android::binder::Status isAlive(bool* alive) override;
+    ::android::binder::Status registerOemUnsolicitedEventListener(
+            const ::android::sp<IOemNetdUnsolicitedEventListener>& listener) override;
 
   private:
     std::mutex mMutex;
+    std::mutex mOemUnsolicitedMutex;
+
     ::android::sp<::android::IBinder> mIBinder GUARDED_BY(mMutex);
+    OemUnsolListenerMap mOemUnsolListenerMap GUARDED_BY(mOemUnsolicitedMutex);
 
     ::android::sp<::android::IBinder> getIBinder() EXCLUDES(mMutex);
+
+    void registerOemUnsolicitedEventListenerInternal(
+            const ::android::sp<IOemNetdUnsolicitedEventListener>& listener)
+            EXCLUDES(mOemUnsolicitedMutex);
+    void unregisterOemUnsolicitedEventListenerInternal(
+            const ::android::sp<IOemNetdUnsolicitedEventListener>& listener)
+            EXCLUDES(mOemUnsolicitedMutex);
 };
 
 }  // namespace net
diff --git a/server/binder/com/android/internal/net/IOemNetd.aidl b/server/binder/com/android/internal/net/IOemNetd.aidl
index 7b22389..bd55106 100644
--- a/server/binder/com/android/internal/net/IOemNetd.aidl
+++ b/server/binder/com/android/internal/net/IOemNetd.aidl
@@ -16,10 +16,19 @@
 
 package com.android.internal.net;
 
+import com.android.internal.net.IOemNetdUnsolicitedEventListener;
+
 /** {@hide} */
 interface IOemNetd {
-    /**
-     * Returns true if the service is responding.
-     */
+   /**
+    * Returns true if the service is responding.
+    */
     boolean isAlive();
+
+   /**
+    * Register oem unsolicited event listener
+    *
+    * @param listener oem unsolicited event listener to register
+    */
+    void registerOemUnsolicitedEventListener(IOemNetdUnsolicitedEventListener listener);
 }
diff --git a/server/binder/com/android/internal/net/IOemNetdUnsolicitedEventListener.aidl b/server/binder/com/android/internal/net/IOemNetdUnsolicitedEventListener.aidl
new file mode 100644
index 0000000..e2c6882
--- /dev/null
+++ b/server/binder/com/android/internal/net/IOemNetdUnsolicitedEventListener.aidl
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2019, 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.internal.net;
+
+/**
+ * {@hide}
+ */
+oneway interface IOemNetdUnsolicitedEventListener {
+
+   /**
+    * Notifies that a listener is registered.
+    *
+    * It is a sample method and used for testing.
+    */
+    void onRegistered();
+}
diff --git a/tests/binder_test.cpp b/tests/binder_test.cpp
index a4ea0fd..1f6e5f7 100644
--- a/tests/binder_test.cpp
+++ b/tests/binder_test.cpp
@@ -43,8 +43,11 @@
 #include <android-base/macros.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <binder/IPCThreadState.h>
 #include <bpf/BpfMap.h>
 #include <bpf/BpfUtils.h>
+#include <com/android/internal/net/BnOemNetdUnsolicitedEventListener.h>
+#include <com/android/internal/net/IOemNetd.h>
 #include <cutils/multiuser.h>
 #include <gtest/gtest.h>
 #include <logwrap/logwrap.h>
@@ -57,7 +60,6 @@
 #include "XfrmController.h"
 #include "android/net/INetd.h"
 #include "binder/IServiceManager.h"
-#include "com/android/internal/net/IOemNetd.h"
 #include "netdutils/Stopwatch.h"
 #include "netdutils/Syscalls.h"
 #include "tun_interface.h"
@@ -3035,7 +3037,7 @@
     EXPECT_TRUE(mNetd->networkDestroy(TEST_NETID1).isOk());
 }
 
-TEST_F(BinderTest, OemNetdIsAlive) {
+TEST_F(BinderTest, OemNetdRelated) {
     sp<IBinder> binder;
     binder::Status status = mNetd->getOemNetd(&binder);
     EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
@@ -3043,9 +3045,47 @@
     if (binder != nullptr) {
         oemNetd = android::interface_cast<com::android::internal::net::IOemNetd>(binder);
     }
+    ASSERT_NE(nullptr, oemNetd.get());
 
     TimedOperation t("OemNetd isAlive RPC");
     bool isAlive = false;
     oemNetd->isAlive(&isAlive);
     ASSERT_TRUE(isAlive);
+
+    class TestOemUnsolListener
+        : public com::android::internal::net::BnOemNetdUnsolicitedEventListener {
+      public:
+        android::binder::Status onRegistered() override {
+            std::lock_guard lock(mCvMutex);
+            mCv.notify_one();
+            return android::binder::Status::ok();
+        }
+        std::condition_variable& getCv() { return mCv; }
+        std::mutex& getCvMutex() { return mCvMutex; }
+
+      private:
+        std::mutex mCvMutex;
+        std::condition_variable mCv;
+    };
+
+    // Start the Binder thread pool.
+    android::ProcessState::self()->startThreadPool();
+
+    android::sp<TestOemUnsolListener> testListener = new TestOemUnsolListener();
+
+    auto& cv = testListener->getCv();
+    auto& cvMutex = testListener->getCvMutex();
+
+    {
+        std::unique_lock lock(cvMutex);
+
+        status = oemNetd->registerOemUnsolicitedEventListener(
+                ::android::interface_cast<
+                        com::android::internal::net::IOemNetdUnsolicitedEventListener>(
+                        testListener));
+        EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+
+        // Wait for receiving expected events.
+        EXPECT_EQ(std::cv_status::no_timeout, cv.wait_for(lock, std::chrono::seconds(2)));
+    }
 }