• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //  Copyright (C) 2015 Google, Inc.
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 
17 #pragma once
18 
19 #include <mutex>
20 #include <unordered_map>
21 
22 #include <base/logging.h>
23 #include <base/macros.h>
24 #include <binder/IBinder.h>
25 #include <binder/IInterface.h>
26 
27 namespace ipc {
28 namespace binder {
29 
30 // A map of remote interfaces where the value type "V" must inherit from
31 // android::IInterface. This is just like RemoteCallbackList except it provides
32 // a key-value mapping.
33 //
34 // TODO(armansito): We should make this class non-final and the template
35 // interface abstract, so that code that depends on this can be unit tested
36 // against a mock version of this class.
37 template<typename K, typename V>
38 class RemoteCallbackMap final {
39  public:
40   RemoteCallbackMap() = default;
41   ~RemoteCallbackMap();
42 
43   // The Delegate interface is used to notify when a registered callback is
44   // removed from the map as a result of the death of the remote process that
45   // owns the registered callback.
46   class Delegate {
47    public:
48     virtual ~Delegate() = default;
49 
50     // Called when a remote callback associated with the key |key| has been
51     // removed. This won't get called if the callback was removed as a result of
52     // a call to RemoteCallbackMap::Unregister.
53     virtual void OnRemoteCallbackRemoved(const K& key) = 0;
54   };
55 
56   // Register a callback interface and associate it with the given key.
57   // Registering will automatically start tracking for death notifications in
58   // case the remote process hosting the Binder dies. In such a case, the Binder
59   // is automatically removed from the map.
60   //
61   // An optional |delegate| can be passed which will be assocated with the given
62   // key/value pair. |delegate| must outlive this map.
63   bool Register(const K& key,
64                 const android::sp<V>& callback,
65                 Delegate* delegate = nullptr);
66 
67   // Unregisters a previously registered callback with the given key. Returns
68   // false if |key| doesn't exist.
69   bool Unregister(const K& key);
70 
71   // Returns the callback associated with the given key. Returns NULL if |key|
72   // doesn't exist.
73   android::sp<V> Get(const K& key);
74 
75   // Removes the callback associated with the given key from the map and returns
76   // the value. Returns NULL if the key doesn't exists.
77   android::sp<V> Remove(const K& key);
78 
79   // Clear the contents of the map.
80   void Clear();
81 
82  private:
83   class CallbackDeathRecipient : public android::IBinder::DeathRecipient {
84    public:
85     CallbackDeathRecipient(
86         const K& key,
87         const android::sp<V>& callback,
88         RemoteCallbackMap<K, V>* owner,
89         Delegate* delegate);
90 
get_callback()91     android::sp<V> get_callback() const { return callback_; }
92 
93     // android::IBinder::DeathRecipient override:
94     void binderDied(const android::wp<android::IBinder>& who) override;
95 
96    private:
97     K key_;
98     android::sp<V> callback_;
99     RemoteCallbackMap<K, V>* owner_;  // weak
100     Delegate* delegate_;  // weak
101   };
102 
103   // Typedef for internal map container.
104   using CallbackMap =
105       std::unordered_map<K, android::sp<CallbackDeathRecipient>>;
106 
107   bool UnregisterInternal(typename CallbackMap::iterator iter);
108 
109   std::mutex map_lock_;
110   CallbackMap map_;
111 
112   DISALLOW_COPY_AND_ASSIGN(RemoteCallbackMap);
113 };
114 
115 // Template Implementation details below
116 // ========================================================
117 
118 using android::IBinder;
119 using android::IInterface;
120 using android::sp;
121 using android::wp;
122 using std::lock_guard;
123 using std::mutex;
124 
125 template<typename K, typename V>
~RemoteCallbackMap()126 RemoteCallbackMap<K, V>::~RemoteCallbackMap() {
127   Clear();
128 }
129 
130 template<typename K, typename V>
Register(const K & key,const sp<V> & callback,Delegate * delegate)131 bool RemoteCallbackMap<K, V>::Register(
132     const K& key,
133     const sp<V>& callback,
134     Delegate* delegate) {
135   lock_guard<mutex> lock(map_lock_);
136 
137   if (map_.find(key) != map_.end()) {
138     VLOG(1) << "Callback map already contains key";
139     return false;
140   }
141 
142   sp<CallbackDeathRecipient> dr(
143       new CallbackDeathRecipient(key, callback, this, delegate));
144   sp<IBinder> binder = IInterface::asBinder(callback.get());
145   if (binder->linkToDeath(dr) != android::NO_ERROR) {
146     LOG(ERROR) << "Failed to link death recipient to binder";
147     return false;
148   }
149 
150   map_[key] = dr;
151 
152   VLOG(2) << "Callback successfully registered with map";
153 
154   return true;
155 }
156 
157 template<typename K, typename V>
Unregister(const K & key)158 bool RemoteCallbackMap<K, V>::Unregister(const K& key) {
159   lock_guard<mutex> lock(map_lock_);
160 
161   auto iter = map_.find(key);
162   if (iter == map_.end()) {
163     VLOG(1) << "Callback with given key not found";
164     return false;
165   }
166 
167   return UnregisterInternal(iter);
168 }
169 
170 template<typename K, typename V>
Get(const K & key)171 sp<V> RemoteCallbackMap<K, V>::Get(const K& key) {
172   lock_guard<mutex> lock(map_lock_);
173 
174   auto iter = map_.find(key);
175   if (iter == map_.end())
176     return nullptr;
177 
178   return iter->second->get_callback();
179 }
180 
181 template<typename K, typename V>
Remove(const K & key)182 sp<V> RemoteCallbackMap<K, V>::Remove(const K& key) {
183   lock_guard<mutex> lock(map_lock_);
184 
185   auto iter = map_.find(key);
186   if (iter == map_.end())
187     return nullptr;
188 
189   sp<V> val = iter->second->get_callback();
190   UnregisterInternal(iter);
191 
192   return val;
193 }
194 template<typename K, typename V>
Clear()195 void RemoteCallbackMap<K, V>::Clear() {
196   lock_guard<mutex> lock(map_lock_);
197 
198   for (auto iter = map_.begin(); iter != map_.end();)
199     UnregisterInternal(iter++);
200 }
201 
202 template<typename K, typename V>
UnregisterInternal(typename CallbackMap::iterator iter)203 bool RemoteCallbackMap<K, V>::UnregisterInternal(
204     typename CallbackMap::iterator iter) {
205   sp<CallbackDeathRecipient> dr = iter->second;
206   map_.erase(iter);
207 
208   if (IInterface::asBinder(dr->get_callback().get())->unlinkToDeath(dr) !=
209       android::NO_ERROR) {
210     LOG(ERROR) << "Failed to unlink death recipient from binder";
211 
212     // We removed the entry from |map_| but unlinkToDeath failed. There isn't
213     // really much we can do here other than deleting the binder and returning
214     // an error.
215     return false;
216   }
217 
218   VLOG(2) << "Callback successfully removed from map";
219 
220   return true;
221 }
222 
223 template<typename K, typename V>
CallbackDeathRecipient(const K & key,const sp<V> & callback,RemoteCallbackMap<K,V> * owner,Delegate * delegate)224 RemoteCallbackMap<K, V>::CallbackDeathRecipient::CallbackDeathRecipient(
225     const K& key,
226     const sp<V>& callback,
227     RemoteCallbackMap<K, V>* owner,
228     Delegate* delegate)
229     : key_(key),
230       callback_(callback),
231       owner_(owner),
232       delegate_(delegate) {
233   CHECK(callback_.get());
234 }
235 
236 template<typename K, typename V>
binderDied(const wp<IBinder> & who)237 void RemoteCallbackMap<K, V>::CallbackDeathRecipient::binderDied(
238     const wp<IBinder>& who) {
239   VLOG(1) << "Received binderDied";
240 
241   sp<IBinder> binder = IInterface::asBinder(callback_.get());
242   CHECK(who.unsafe_get() == binder.get());
243 
244   // Remove the callback but no need to call unlinkToDeath.
245   {
246     lock_guard<mutex> lock(owner_->map_lock_);
247     auto iter = owner_->map_.find(key_);
248     CHECK(iter != owner_->map_.end());
249     owner_->map_.erase(iter);
250   }
251 
252   VLOG(1) << "Callback from dead process unregistered; notifying delegate";
253 
254   // Notify delegate.
255   if (delegate_)
256     delegate_->OnRemoteCallbackRemoved(key_);
257 }
258 
259 }  // namespace binder
260 }  // namespace ipc
261