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