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
27namespace ipc {
28namespace 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.
37template<typename K, typename V>
38class 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
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
118using android::IBinder;
119using android::IInterface;
120using android::sp;
121using android::wp;
122using std::lock_guard;
123using std::mutex;
124
125template<typename K, typename V>
126RemoteCallbackMap<K, V>::~RemoteCallbackMap() {
127  Clear();
128}
129
130template<typename K, typename V>
131bool 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
157template<typename K, typename V>
158bool 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
170template<typename K, typename V>
171sp<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
181template<typename K, typename V>
182sp<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}
194template<typename K, typename V>
195void 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
202template<typename K, typename V>
203bool 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
223template<typename K, typename V>
224RemoteCallbackMap<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
236template<typename K, typename V>
237void 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