Loading DnsResolverService.cpp +4 −2 Original line number Diff line number Diff line Loading @@ -143,10 +143,12 @@ binder_status_t DnsResolverService::dump(int fd, const char** args, uint32_t num ::ndk::ScopedAStatus DnsResolverService::registerUnsolicitedEventListener( const std::shared_ptr< aidl::android::net::resolv::aidl::IDnsResolverUnsolicitedEventListener>&) { aidl::android::net::resolv::aidl::IDnsResolverUnsolicitedEventListener>& listener) { ENFORCE_NETWORK_STACK_PERMISSIONS(); return ::ndk::ScopedAStatus(AStatus_newOk()); int res = ResolverEventReporter::getInstance().addUnsolEventListener(listener); return statusFromErrcode(res); } ::ndk::ScopedAStatus DnsResolverService::checkAnyPermission( Loading ResolverEventReporter.cpp +80 −1 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <android/binder_manager.h> using aidl::android::net::metrics::INetdEventListener; using aidl::android::net::resolv::aidl::IDnsResolverUnsolicitedEventListener; ResolverEventReporter& ResolverEventReporter::getInstance() { // It should be initialized only once. Loading @@ -38,10 +39,19 @@ ResolverEventReporter::ListenerSet ResolverEventReporter::getListeners() const { return getListenersImpl(); } ResolverEventReporter::UnsolEventListenerSet ResolverEventReporter::getUnsolEventListeners() const { return getUnsolEventListenersImpl(); } int ResolverEventReporter::addListener(const std::shared_ptr<INetdEventListener>& listener) { return addListenerImpl(listener); } int ResolverEventReporter::addUnsolEventListener( const std::shared_ptr<IDnsResolverUnsolicitedEventListener>& listener) { return addUnsolEventListenerImpl(listener); } // TODO: Consider registering metrics listener from framework and remove this function. // Currently, the framework listener "netd_listener" is shared by netd and libnetd_resolv. // Consider breaking it into two listeners. Once it has done, may let framework register Loading Loading @@ -73,11 +83,28 @@ void ResolverEventReporter::handleBinderDied(const void* who) { if (found != mListeners.end()) mListeners.erase(found); } void ResolverEventReporter::handleUnsolEventBinderDied(const void* who) { std::lock_guard lock(mMutex); // Use the raw binder pointer address to be the identification of dead binder. Treat "who" // which passes the raw address of dead binder as an identification only. auto found = std::find_if(mUnsolEventListeners.begin(), mUnsolEventListeners.end(), [=](const auto& it) { return static_cast<void*>(it.get()) == who; }); if (found != mUnsolEventListeners.end()) mUnsolEventListeners.erase(found); } ResolverEventReporter::ListenerSet ResolverEventReporter::getListenersImpl() const { std::lock_guard lock(mMutex); return mListeners; } ResolverEventReporter::UnsolEventListenerSet ResolverEventReporter::getUnsolEventListenersImpl() const { std::lock_guard lock(mMutex); return mUnsolEventListeners; } int ResolverEventReporter::addListenerImpl(const std::shared_ptr<INetdEventListener>& listener) { std::lock_guard lock(mMutex); return addListenerImplLocked(listener); Loading Loading @@ -127,3 +154,55 @@ int ResolverEventReporter::addListenerImplLocked( mListeners.insert(listener); return 0; } int ResolverEventReporter::addUnsolEventListenerImpl( const std::shared_ptr<IDnsResolverUnsolicitedEventListener>& listener) { std::lock_guard lock(mMutex); return addUnsolEventListenerImplLocked(listener); } int ResolverEventReporter::addUnsolEventListenerImplLocked( const std::shared_ptr<IDnsResolverUnsolicitedEventListener>& listener) { if (listener == nullptr) { LOG(ERROR) << "The unsolicited event listener should not be null"; return -EINVAL; } for (const auto& it : mUnsolEventListeners) { if (it->asBinder().get() == listener->asBinder().get()) { LOG(WARNING) << "The unsolicited event listener was already subscribed"; return -EEXIST; } } static AIBinder_DeathRecipient* deathRecipient = nullptr; if (deathRecipient == nullptr) { // The AIBinder_DeathRecipient object is used to manage all death recipients for multiple // binder objects. It doesn't released because there should have at least one binder object // from framework. // TODO: Considering to remove death recipient for the binder object from framework because // it doesn't need death recipient actually. deathRecipient = AIBinder_DeathRecipient_new([](void* cookie) { ResolverEventReporter::getInstance().handleUnsolEventBinderDied(cookie); }); } // Pass the raw binder pointer address to be the cookie of the death recipient. While the death // notification is fired, the cookie is used for identifying which binder was died. Because // the NDK binder doesn't pass dead binder pointer to binder death handler, the binder death // handler can't know who was died via wp<IBinder>. The reason for wp<IBinder> is not passed // is that NDK binder can't transform a wp<IBinder> to a wp<AIBinder> in some cases. // See more information in b/128712772. auto binder = listener->asBinder().get(); auto cookie = static_cast<void*>(listener.get()); // Used for dead binder identification. binder_status_t status = AIBinder_linkToDeath(binder, deathRecipient, cookie); if (STATUS_OK != status) { LOG(ERROR) << "Failed to register death notification for IDnsResolverUnsolicitedEventListener"; return -EAGAIN; } mUnsolEventListeners.insert(listener); return 0; } ResolverEventReporter.h +24 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include <android-base/thread_annotations.h> #include "aidl/android/net/metrics/INetdEventListener.h" #include "aidl/android/net/resolv/aidl/IDnsResolverUnsolicitedEventListener.h" /* * This class can be used to get the binder reference to the netd events listener service Loading @@ -36,6 +37,8 @@ class ResolverEventReporter { ResolverEventReporter& operator=(ResolverEventReporter&&) = delete; using ListenerSet = std::set<std::shared_ptr<aidl::android::net::metrics::INetdEventListener>>; using UnsolEventListenerSet = std::set<std::shared_ptr< aidl::android::net::resolv::aidl::IDnsResolverUnsolicitedEventListener>>; // Get the instance of the singleton ResolverEventReporter. static ResolverEventReporter& getInstance(); Loading @@ -43,10 +46,20 @@ class ResolverEventReporter { // Return the binder from the singleton ResolverEventReporter. This method is threadsafe. ListenerSet getListeners() const; // Return registered binder services from the singleton ResolverEventReporter. This method is // threadsafe. UnsolEventListenerSet getUnsolEventListeners() const; // Add the binder to the singleton ResolverEventReporter. This method is threadsafe. int addListener( const std::shared_ptr<aidl::android::net::metrics::INetdEventListener>& listener); // Add the binder to the singleton ResolverEventReporter. This method is threadsafe. int addUnsolEventListener( const std::shared_ptr< aidl::android::net::resolv::aidl::IDnsResolverUnsolicitedEventListener>& listener); private: ResolverEventReporter() = default; ~ResolverEventReporter() = default; Loading @@ -58,11 +71,22 @@ class ResolverEventReporter { int addListenerImplLocked( const std::shared_ptr<aidl::android::net::metrics::INetdEventListener>& listener) REQUIRES(mMutex); int addUnsolEventListenerImpl( const std::shared_ptr< aidl::android::net::resolv::aidl::IDnsResolverUnsolicitedEventListener>& listener) EXCLUDES(mMutex); int addUnsolEventListenerImplLocked( const std::shared_ptr< aidl::android::net::resolv::aidl::IDnsResolverUnsolicitedEventListener>& listener) REQUIRES(mMutex); ListenerSet getListenersImpl() const EXCLUDES(mMutex); UnsolEventListenerSet getUnsolEventListenersImpl() const EXCLUDES(mMutex); void handleBinderDied(const void* who) EXCLUDES(mMutex); void handleUnsolEventBinderDied(const void* who) EXCLUDES(mMutex); mutable std::mutex mMutex; ListenerSet mListeners GUARDED_BY(mMutex); UnsolEventListenerSet mUnsolEventListeners GUARDED_BY(mMutex); }; #endif // NETD_RESOLV_EVENT_REPORTER_H tests/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -176,6 +176,7 @@ cc_test { "netd_aidl_interface-ndk_platform", "netd_event_listener_interface-unstable-ndk_platform", "libipchecksum", "resolv_unsolicited_listener", ], // This test talks to the DnsResolver module over a binary protocol on a socket, so keep it as // multilib setting is worth because we might be able to get some coverage for the case where Loading tests/dnsresolver_binder_test.cpp +34 −4 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ #include "dns_metrics_listener/base_metrics_listener.h" #include "dns_metrics_listener/test_metrics.h" #include "unsolicited_listener/unsolicited_event_listener.h" #include "ResolverStats.h" #include "dns_responder.h" Loading Loading @@ -273,16 +274,16 @@ TEST_F(DnsResolverBinderTest, RegisterEventListener_NullListener) { } TEST_F(DnsResolverBinderTest, RegisterEventListener_DuplicateSubscription) { class DummyListener : public android::net::metrics::BaseMetricsListener {}; class FakeListener : public android::net::metrics::BaseMetricsListener {}; // Expect to subscribe successfully. std::shared_ptr<DummyListener> dummyListener = ndk::SharedRefBase::make<DummyListener>(); ::ndk::ScopedAStatus status = mDnsResolver->registerEventListener(dummyListener); std::shared_ptr<FakeListener> fakeListener = ndk::SharedRefBase::make<FakeListener>(); ::ndk::ScopedAStatus status = mDnsResolver->registerEventListener(fakeListener); ASSERT_TRUE(status.isOk()) << status.getMessage(); mExpectedLogData.push_back({"registerEventListener()", "registerEventListener.*"}); // Expect to subscribe failed with registered listener instance. status = mDnsResolver->registerEventListener(dummyListener); status = mDnsResolver->registerEventListener(fakeListener); ASSERT_FALSE(status.isOk()); ASSERT_EQ(EEXIST, status.getServiceSpecificError()); mExpectedLogData.push_back( Loading @@ -290,6 +291,35 @@ TEST_F(DnsResolverBinderTest, RegisterEventListener_DuplicateSubscription) { "registerEventListener.*17"}); } TEST_F(DnsResolverBinderTest, RegisterUnsolicitedEventListener_NullListener) { ::ndk::ScopedAStatus status = mDnsResolver->registerUnsolicitedEventListener(nullptr); ASSERT_FALSE(status.isOk()); ASSERT_EQ(EINVAL, status.getServiceSpecificError()); mExpectedLogData.push_back( {"registerUnsolicitedEventListener() -> ServiceSpecificException(22, \"Invalid " "argument\")", "registerUnsolicitedEventListener.*22"}); } TEST_F(DnsResolverBinderTest, RegisterUnsolicitedEventListener_DuplicateSubscription) { class FakeListener : public android::net::resolv::aidl::UnsolicitedEventListener {}; // Expect to subscribe successfully. std::shared_ptr<FakeListener> fakeListener = ndk::SharedRefBase::make<FakeListener>(); ::ndk::ScopedAStatus status = mDnsResolver->registerUnsolicitedEventListener(fakeListener); ASSERT_TRUE(status.isOk()) << status.getMessage(); mExpectedLogData.push_back( {"registerUnsolicitedEventListener()", "registerUnsolicitedEventListener.*"}); // Expect to subscribe failed with registered listener instance. status = mDnsResolver->registerUnsolicitedEventListener(fakeListener); ASSERT_FALSE(status.isOk()); ASSERT_EQ(EEXIST, status.getServiceSpecificError()); mExpectedLogData.push_back( {"registerUnsolicitedEventListener() -> ServiceSpecificException(17, \"File exists\")", "registerUnsolicitedEventListener.*17"}); } // TODO: Move this test to resolv_integration_test.cpp TEST_F(DnsResolverBinderTest, RegisterEventListener_onDnsEvent) { // The test configs are used to trigger expected events. The expected results are defined in Loading Loading
DnsResolverService.cpp +4 −2 Original line number Diff line number Diff line Loading @@ -143,10 +143,12 @@ binder_status_t DnsResolverService::dump(int fd, const char** args, uint32_t num ::ndk::ScopedAStatus DnsResolverService::registerUnsolicitedEventListener( const std::shared_ptr< aidl::android::net::resolv::aidl::IDnsResolverUnsolicitedEventListener>&) { aidl::android::net::resolv::aidl::IDnsResolverUnsolicitedEventListener>& listener) { ENFORCE_NETWORK_STACK_PERMISSIONS(); return ::ndk::ScopedAStatus(AStatus_newOk()); int res = ResolverEventReporter::getInstance().addUnsolEventListener(listener); return statusFromErrcode(res); } ::ndk::ScopedAStatus DnsResolverService::checkAnyPermission( Loading
ResolverEventReporter.cpp +80 −1 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <android/binder_manager.h> using aidl::android::net::metrics::INetdEventListener; using aidl::android::net::resolv::aidl::IDnsResolverUnsolicitedEventListener; ResolverEventReporter& ResolverEventReporter::getInstance() { // It should be initialized only once. Loading @@ -38,10 +39,19 @@ ResolverEventReporter::ListenerSet ResolverEventReporter::getListeners() const { return getListenersImpl(); } ResolverEventReporter::UnsolEventListenerSet ResolverEventReporter::getUnsolEventListeners() const { return getUnsolEventListenersImpl(); } int ResolverEventReporter::addListener(const std::shared_ptr<INetdEventListener>& listener) { return addListenerImpl(listener); } int ResolverEventReporter::addUnsolEventListener( const std::shared_ptr<IDnsResolverUnsolicitedEventListener>& listener) { return addUnsolEventListenerImpl(listener); } // TODO: Consider registering metrics listener from framework and remove this function. // Currently, the framework listener "netd_listener" is shared by netd and libnetd_resolv. // Consider breaking it into two listeners. Once it has done, may let framework register Loading Loading @@ -73,11 +83,28 @@ void ResolverEventReporter::handleBinderDied(const void* who) { if (found != mListeners.end()) mListeners.erase(found); } void ResolverEventReporter::handleUnsolEventBinderDied(const void* who) { std::lock_guard lock(mMutex); // Use the raw binder pointer address to be the identification of dead binder. Treat "who" // which passes the raw address of dead binder as an identification only. auto found = std::find_if(mUnsolEventListeners.begin(), mUnsolEventListeners.end(), [=](const auto& it) { return static_cast<void*>(it.get()) == who; }); if (found != mUnsolEventListeners.end()) mUnsolEventListeners.erase(found); } ResolverEventReporter::ListenerSet ResolverEventReporter::getListenersImpl() const { std::lock_guard lock(mMutex); return mListeners; } ResolverEventReporter::UnsolEventListenerSet ResolverEventReporter::getUnsolEventListenersImpl() const { std::lock_guard lock(mMutex); return mUnsolEventListeners; } int ResolverEventReporter::addListenerImpl(const std::shared_ptr<INetdEventListener>& listener) { std::lock_guard lock(mMutex); return addListenerImplLocked(listener); Loading Loading @@ -127,3 +154,55 @@ int ResolverEventReporter::addListenerImplLocked( mListeners.insert(listener); return 0; } int ResolverEventReporter::addUnsolEventListenerImpl( const std::shared_ptr<IDnsResolverUnsolicitedEventListener>& listener) { std::lock_guard lock(mMutex); return addUnsolEventListenerImplLocked(listener); } int ResolverEventReporter::addUnsolEventListenerImplLocked( const std::shared_ptr<IDnsResolverUnsolicitedEventListener>& listener) { if (listener == nullptr) { LOG(ERROR) << "The unsolicited event listener should not be null"; return -EINVAL; } for (const auto& it : mUnsolEventListeners) { if (it->asBinder().get() == listener->asBinder().get()) { LOG(WARNING) << "The unsolicited event listener was already subscribed"; return -EEXIST; } } static AIBinder_DeathRecipient* deathRecipient = nullptr; if (deathRecipient == nullptr) { // The AIBinder_DeathRecipient object is used to manage all death recipients for multiple // binder objects. It doesn't released because there should have at least one binder object // from framework. // TODO: Considering to remove death recipient for the binder object from framework because // it doesn't need death recipient actually. deathRecipient = AIBinder_DeathRecipient_new([](void* cookie) { ResolverEventReporter::getInstance().handleUnsolEventBinderDied(cookie); }); } // Pass the raw binder pointer address to be the cookie of the death recipient. While the death // notification is fired, the cookie is used for identifying which binder was died. Because // the NDK binder doesn't pass dead binder pointer to binder death handler, the binder death // handler can't know who was died via wp<IBinder>. The reason for wp<IBinder> is not passed // is that NDK binder can't transform a wp<IBinder> to a wp<AIBinder> in some cases. // See more information in b/128712772. auto binder = listener->asBinder().get(); auto cookie = static_cast<void*>(listener.get()); // Used for dead binder identification. binder_status_t status = AIBinder_linkToDeath(binder, deathRecipient, cookie); if (STATUS_OK != status) { LOG(ERROR) << "Failed to register death notification for IDnsResolverUnsolicitedEventListener"; return -EAGAIN; } mUnsolEventListeners.insert(listener); return 0; }
ResolverEventReporter.h +24 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include <android-base/thread_annotations.h> #include "aidl/android/net/metrics/INetdEventListener.h" #include "aidl/android/net/resolv/aidl/IDnsResolverUnsolicitedEventListener.h" /* * This class can be used to get the binder reference to the netd events listener service Loading @@ -36,6 +37,8 @@ class ResolverEventReporter { ResolverEventReporter& operator=(ResolverEventReporter&&) = delete; using ListenerSet = std::set<std::shared_ptr<aidl::android::net::metrics::INetdEventListener>>; using UnsolEventListenerSet = std::set<std::shared_ptr< aidl::android::net::resolv::aidl::IDnsResolverUnsolicitedEventListener>>; // Get the instance of the singleton ResolverEventReporter. static ResolverEventReporter& getInstance(); Loading @@ -43,10 +46,20 @@ class ResolverEventReporter { // Return the binder from the singleton ResolverEventReporter. This method is threadsafe. ListenerSet getListeners() const; // Return registered binder services from the singleton ResolverEventReporter. This method is // threadsafe. UnsolEventListenerSet getUnsolEventListeners() const; // Add the binder to the singleton ResolverEventReporter. This method is threadsafe. int addListener( const std::shared_ptr<aidl::android::net::metrics::INetdEventListener>& listener); // Add the binder to the singleton ResolverEventReporter. This method is threadsafe. int addUnsolEventListener( const std::shared_ptr< aidl::android::net::resolv::aidl::IDnsResolverUnsolicitedEventListener>& listener); private: ResolverEventReporter() = default; ~ResolverEventReporter() = default; Loading @@ -58,11 +71,22 @@ class ResolverEventReporter { int addListenerImplLocked( const std::shared_ptr<aidl::android::net::metrics::INetdEventListener>& listener) REQUIRES(mMutex); int addUnsolEventListenerImpl( const std::shared_ptr< aidl::android::net::resolv::aidl::IDnsResolverUnsolicitedEventListener>& listener) EXCLUDES(mMutex); int addUnsolEventListenerImplLocked( const std::shared_ptr< aidl::android::net::resolv::aidl::IDnsResolverUnsolicitedEventListener>& listener) REQUIRES(mMutex); ListenerSet getListenersImpl() const EXCLUDES(mMutex); UnsolEventListenerSet getUnsolEventListenersImpl() const EXCLUDES(mMutex); void handleBinderDied(const void* who) EXCLUDES(mMutex); void handleUnsolEventBinderDied(const void* who) EXCLUDES(mMutex); mutable std::mutex mMutex; ListenerSet mListeners GUARDED_BY(mMutex); UnsolEventListenerSet mUnsolEventListeners GUARDED_BY(mMutex); }; #endif // NETD_RESOLV_EVENT_REPORTER_H
tests/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -176,6 +176,7 @@ cc_test { "netd_aidl_interface-ndk_platform", "netd_event_listener_interface-unstable-ndk_platform", "libipchecksum", "resolv_unsolicited_listener", ], // This test talks to the DnsResolver module over a binary protocol on a socket, so keep it as // multilib setting is worth because we might be able to get some coverage for the case where Loading
tests/dnsresolver_binder_test.cpp +34 −4 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ #include "dns_metrics_listener/base_metrics_listener.h" #include "dns_metrics_listener/test_metrics.h" #include "unsolicited_listener/unsolicited_event_listener.h" #include "ResolverStats.h" #include "dns_responder.h" Loading Loading @@ -273,16 +274,16 @@ TEST_F(DnsResolverBinderTest, RegisterEventListener_NullListener) { } TEST_F(DnsResolverBinderTest, RegisterEventListener_DuplicateSubscription) { class DummyListener : public android::net::metrics::BaseMetricsListener {}; class FakeListener : public android::net::metrics::BaseMetricsListener {}; // Expect to subscribe successfully. std::shared_ptr<DummyListener> dummyListener = ndk::SharedRefBase::make<DummyListener>(); ::ndk::ScopedAStatus status = mDnsResolver->registerEventListener(dummyListener); std::shared_ptr<FakeListener> fakeListener = ndk::SharedRefBase::make<FakeListener>(); ::ndk::ScopedAStatus status = mDnsResolver->registerEventListener(fakeListener); ASSERT_TRUE(status.isOk()) << status.getMessage(); mExpectedLogData.push_back({"registerEventListener()", "registerEventListener.*"}); // Expect to subscribe failed with registered listener instance. status = mDnsResolver->registerEventListener(dummyListener); status = mDnsResolver->registerEventListener(fakeListener); ASSERT_FALSE(status.isOk()); ASSERT_EQ(EEXIST, status.getServiceSpecificError()); mExpectedLogData.push_back( Loading @@ -290,6 +291,35 @@ TEST_F(DnsResolverBinderTest, RegisterEventListener_DuplicateSubscription) { "registerEventListener.*17"}); } TEST_F(DnsResolverBinderTest, RegisterUnsolicitedEventListener_NullListener) { ::ndk::ScopedAStatus status = mDnsResolver->registerUnsolicitedEventListener(nullptr); ASSERT_FALSE(status.isOk()); ASSERT_EQ(EINVAL, status.getServiceSpecificError()); mExpectedLogData.push_back( {"registerUnsolicitedEventListener() -> ServiceSpecificException(22, \"Invalid " "argument\")", "registerUnsolicitedEventListener.*22"}); } TEST_F(DnsResolverBinderTest, RegisterUnsolicitedEventListener_DuplicateSubscription) { class FakeListener : public android::net::resolv::aidl::UnsolicitedEventListener {}; // Expect to subscribe successfully. std::shared_ptr<FakeListener> fakeListener = ndk::SharedRefBase::make<FakeListener>(); ::ndk::ScopedAStatus status = mDnsResolver->registerUnsolicitedEventListener(fakeListener); ASSERT_TRUE(status.isOk()) << status.getMessage(); mExpectedLogData.push_back( {"registerUnsolicitedEventListener()", "registerUnsolicitedEventListener.*"}); // Expect to subscribe failed with registered listener instance. status = mDnsResolver->registerUnsolicitedEventListener(fakeListener); ASSERT_FALSE(status.isOk()); ASSERT_EQ(EEXIST, status.getServiceSpecificError()); mExpectedLogData.push_back( {"registerUnsolicitedEventListener() -> ServiceSpecificException(17, \"File exists\")", "registerUnsolicitedEventListener.*17"}); } // TODO: Move this test to resolv_integration_test.cpp TEST_F(DnsResolverBinderTest, RegisterEventListener_onDnsEvent) { // The test configs are used to trigger expected events. The expected results are defined in Loading