• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #define LOG_TAG "resolv"
17 
18 #include "ResolverEventReporter.h"
19 
20 #include <android-base/logging.h>
21 #include <android/binder_manager.h>
22 
23 using aidl::android::net::metrics::INetdEventListener;
24 using aidl::android::net::resolv::aidl::IDnsResolverUnsolicitedEventListener;
25 
getInstance()26 ResolverEventReporter& ResolverEventReporter::getInstance() {
27     // It should be initialized only once.
28     static ResolverEventReporter instance;
29 
30     // Add framework metrics listener. Because the binder service "netd_listener" may be launched
31     // later than Netd, try to get binder handler in every instance query if any. The framework
32     // metrics listener should be added only once if it has been already added successfully.
33     instance.addDefaultListener();
34 
35     return instance;
36 }
37 
getListeners() const38 ResolverEventReporter::ListenerSet ResolverEventReporter::getListeners() const {
39     return getListenersImpl();
40 }
41 
getUnsolEventListeners() const42 ResolverEventReporter::UnsolEventListenerSet ResolverEventReporter::getUnsolEventListeners() const {
43     return getUnsolEventListenersImpl();
44 }
45 
addListener(const std::shared_ptr<INetdEventListener> & listener)46 int ResolverEventReporter::addListener(const std::shared_ptr<INetdEventListener>& listener) {
47     return addListenerImpl(listener);
48 }
49 
addUnsolEventListener(const std::shared_ptr<IDnsResolverUnsolicitedEventListener> & listener)50 int ResolverEventReporter::addUnsolEventListener(
51         const std::shared_ptr<IDnsResolverUnsolicitedEventListener>& listener) {
52     return addUnsolEventListenerImpl(listener);
53 }
54 
55 // TODO: Consider registering metrics listener from framework and remove this function.
56 // Currently, the framework listener "netd_listener" is shared by netd and libnetd_resolv.
57 // Consider breaking it into two listeners. Once it has done, may let framework register
58 // the listener proactively.
addDefaultListener()59 void ResolverEventReporter::addDefaultListener() {
60     std::lock_guard lock(mMutex);
61 
62     static bool added = false;
63     if (added) return;
64 
65     // Use the non-blocking call AServiceManager_checkService in order not to delay DNS
66     // lookup threads when the netd_listener service is not ready.
67     ndk::SpAIBinder binder = ndk::SpAIBinder(AServiceManager_checkService("netd_listener"));
68     std::shared_ptr<INetdEventListener> listener = INetdEventListener::fromBinder(binder);
69 
70     if (listener == nullptr) return;
71 
72     if (!addListenerImplLocked(listener)) added = true;
73 }
74 
handleBinderDied(const void * who)75 void ResolverEventReporter::handleBinderDied(const void* who) {
76     std::lock_guard lock(mMutex);
77 
78     // Use the raw binder pointer address to be the identification of dead binder. Treat "who"
79     // which passes the raw address of dead binder as an identification only.
80     auto found = std::find_if(mListeners.begin(), mListeners.end(),
81                               [=](const auto& it) { return static_cast<void*>(it.get()) == who; });
82 
83     if (found != mListeners.end()) mListeners.erase(found);
84 }
85 
handleUnsolEventBinderDied(const void * who)86 void ResolverEventReporter::handleUnsolEventBinderDied(const void* who) {
87     std::lock_guard lock(mMutex);
88 
89     // Use the raw binder pointer address to be the identification of dead binder. Treat "who"
90     // which passes the raw address of dead binder as an identification only.
91     auto found = std::find_if(mUnsolEventListeners.begin(), mUnsolEventListeners.end(),
92                               [=](const auto& it) { return static_cast<void*>(it.get()) == who; });
93 
94     if (found != mUnsolEventListeners.end()) mUnsolEventListeners.erase(found);
95 }
96 
getListenersImpl() const97 ResolverEventReporter::ListenerSet ResolverEventReporter::getListenersImpl() const {
98     std::lock_guard lock(mMutex);
99     return mListeners;
100 }
101 
getUnsolEventListenersImpl() const102 ResolverEventReporter::UnsolEventListenerSet ResolverEventReporter::getUnsolEventListenersImpl()
103         const {
104     std::lock_guard lock(mMutex);
105     return mUnsolEventListeners;
106 }
107 
addListenerImpl(const std::shared_ptr<INetdEventListener> & listener)108 int ResolverEventReporter::addListenerImpl(const std::shared_ptr<INetdEventListener>& listener) {
109     std::lock_guard lock(mMutex);
110     return addListenerImplLocked(listener);
111 }
112 
addListenerImplLocked(const std::shared_ptr<INetdEventListener> & listener)113 int ResolverEventReporter::addListenerImplLocked(
114         const std::shared_ptr<INetdEventListener>& listener) {
115     if (listener == nullptr) {
116         LOG(ERROR) << "The listener should not be null";
117         return -EINVAL;
118     }
119 
120     for (const auto& it : mListeners) {
121         if (it->asBinder().get() == listener->asBinder().get()) {
122             LOG(WARNING) << "The listener was already subscribed";
123             return -EEXIST;
124         }
125     }
126 
127     static AIBinder_DeathRecipient* deathRecipient = nullptr;
128     if (deathRecipient == nullptr) {
129         // The AIBinder_DeathRecipient object is used to manage all death recipients for multiple
130         // binder objects. It doesn't released because there should have at least one binder object
131         // from framework.
132         // TODO: Considering to remove death recipient for the binder object from framework because
133         // it doesn't need death recipient actually.
134         deathRecipient = AIBinder_DeathRecipient_new([](void* cookie) {
135             ResolverEventReporter::getInstance().handleBinderDied(cookie);
136         });
137     }
138 
139     // Pass the raw binder pointer address to be the cookie of the death recipient. While the death
140     // notification is fired, the cookie is used for identifying which binder was died. Because
141     // the NDK binder doesn't pass dead binder pointer to binder death handler, the binder death
142     // handler can't know who was died via wp<IBinder>. The reason for wp<IBinder> is not passed
143     // is that NDK binder can't transform a wp<IBinder> to a wp<AIBinder> in some cases.
144     // See more information in b/128712772.
145     auto binder = listener->asBinder().get();
146     auto cookie = static_cast<void*>(listener.get());  // Used for dead binder identification.
147     binder_status_t status = AIBinder_linkToDeath(binder, deathRecipient, cookie);
148 
149     if (STATUS_OK != status) {
150         LOG(ERROR) << "Failed to register death notification for INetdEventListener";
151         return -EAGAIN;
152     }
153 
154     mListeners.insert(listener);
155     return 0;
156 }
157 
addUnsolEventListenerImpl(const std::shared_ptr<IDnsResolverUnsolicitedEventListener> & listener)158 int ResolverEventReporter::addUnsolEventListenerImpl(
159         const std::shared_ptr<IDnsResolverUnsolicitedEventListener>& listener) {
160     std::lock_guard lock(mMutex);
161     return addUnsolEventListenerImplLocked(listener);
162 }
163 
addUnsolEventListenerImplLocked(const std::shared_ptr<IDnsResolverUnsolicitedEventListener> & listener)164 int ResolverEventReporter::addUnsolEventListenerImplLocked(
165         const std::shared_ptr<IDnsResolverUnsolicitedEventListener>& listener) {
166     if (listener == nullptr) {
167         LOG(ERROR) << "The unsolicited event listener should not be null";
168         return -EINVAL;
169     }
170 
171     for (const auto& it : mUnsolEventListeners) {
172         if (it->asBinder().get() == listener->asBinder().get()) {
173             LOG(WARNING) << "The unsolicited event listener was already subscribed";
174             return -EEXIST;
175         }
176     }
177 
178     static AIBinder_DeathRecipient* deathRecipient = nullptr;
179     if (deathRecipient == nullptr) {
180         // The AIBinder_DeathRecipient object is used to manage all death recipients for multiple
181         // binder objects. It doesn't released because there should have at least one binder object
182         // from framework.
183         // TODO: Considering to remove death recipient for the binder object from framework because
184         // it doesn't need death recipient actually.
185         deathRecipient = AIBinder_DeathRecipient_new([](void* cookie) {
186             ResolverEventReporter::getInstance().handleUnsolEventBinderDied(cookie);
187         });
188     }
189 
190     // Pass the raw binder pointer address to be the cookie of the death recipient. While the death
191     // notification is fired, the cookie is used for identifying which binder was died. Because
192     // the NDK binder doesn't pass dead binder pointer to binder death handler, the binder death
193     // handler can't know who was died via wp<IBinder>. The reason for wp<IBinder> is not passed
194     // is that NDK binder can't transform a wp<IBinder> to a wp<AIBinder> in some cases.
195     // See more information in b/128712772.
196     auto binder = listener->asBinder().get();
197     auto cookie = static_cast<void*>(listener.get());  // Used for dead binder identification.
198     binder_status_t status = AIBinder_linkToDeath(binder, deathRecipient, cookie);
199 
200     if (STATUS_OK != status) {
201         LOG(ERROR)
202                 << "Failed to register death notification for IDnsResolverUnsolicitedEventListener";
203         return -EAGAIN;
204     }
205 
206     mUnsolEventListeners.insert(listener);
207     return 0;
208 }
209