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, const android::sp<V>& callback,
64                Delegate* delegate = nullptr);
65
66  // Unregisters a previously registered callback with the given key. Returns
67  // false if |key| doesn't exist.
68  bool Unregister(const K& key);
69
70  // Returns the callback associated with the given key. Returns NULL if |key|
71  // doesn't exist.
72  android::sp<V> Get(const K& key);
73
74  // Removes the callback associated with the given key from the map and returns
75  // the value. Returns NULL if the key doesn't exists.
76  android::sp<V> Remove(const K& key);
77
78  // Clear the contents of the map.
79  void Clear();
80
81 private:
82  class CallbackDeathRecipient : public android::IBinder::DeathRecipient {
83   public:
84    CallbackDeathRecipient(const K& key, const android::sp<V>& callback,
85                           RemoteCallbackMap<K, V>* owner, Delegate* delegate);
86
87    android::sp<V> get_callback() const { return callback_; }
88
89    // android::IBinder::DeathRecipient override:
90    void binderDied(const android::wp<android::IBinder>& who) override;
91
92   private:
93    K key_;
94    android::sp<V> callback_;
95    RemoteCallbackMap<K, V>* owner_;  // weak
96    Delegate* delegate_;              // weak
97  };
98
99  // Typedef for internal map container.
100  using CallbackMap =
101      std::unordered_map<K, android::sp<CallbackDeathRecipient>>;
102
103  bool UnregisterInternal(typename CallbackMap::iterator iter);
104
105  std::mutex map_lock_;
106  CallbackMap map_;
107
108  DISALLOW_COPY_AND_ASSIGN(RemoteCallbackMap);
109};
110
111// Template Implementation details below
112// ========================================================
113
114using android::IBinder;
115using android::IInterface;
116using android::sp;
117using android::wp;
118using std::lock_guard;
119using std::mutex;
120
121template <typename K, typename V>
122RemoteCallbackMap<K, V>::~RemoteCallbackMap() {
123  Clear();
124}
125
126template <typename K, typename V>
127bool RemoteCallbackMap<K, V>::Register(const K& key, const sp<V>& callback,
128                                       Delegate* delegate) {
129  lock_guard<mutex> lock(map_lock_);
130
131  if (map_.find(key) != map_.end()) {
132    VLOG(1) << "Callback map already contains key";
133    return false;
134  }
135
136  sp<CallbackDeathRecipient> dr(
137      new CallbackDeathRecipient(key, callback, this, delegate));
138  sp<IBinder> binder = IInterface::asBinder(callback.get());
139  if (binder->linkToDeath(dr) != android::NO_ERROR) {
140    LOG(ERROR) << "Failed to link death recipient to binder";
141    return false;
142  }
143
144  map_[key] = dr;
145
146  VLOG(2) << "Callback successfully registered with map";
147
148  return true;
149}
150
151template <typename K, typename V>
152bool RemoteCallbackMap<K, V>::Unregister(const K& key) {
153  lock_guard<mutex> lock(map_lock_);
154
155  auto iter = map_.find(key);
156  if (iter == map_.end()) {
157    VLOG(1) << "Callback with given key not found";
158    return false;
159  }
160
161  return UnregisterInternal(iter);
162}
163
164template <typename K, typename V>
165sp<V> RemoteCallbackMap<K, V>::Get(const K& key) {
166  lock_guard<mutex> lock(map_lock_);
167
168  auto iter = map_.find(key);
169  if (iter == map_.end()) return nullptr;
170
171  return iter->second->get_callback();
172}
173
174template <typename K, typename V>
175sp<V> RemoteCallbackMap<K, V>::Remove(const K& key) {
176  lock_guard<mutex> lock(map_lock_);
177
178  auto iter = map_.find(key);
179  if (iter == map_.end()) return nullptr;
180
181  sp<V> val = iter->second->get_callback();
182  UnregisterInternal(iter);
183
184  return val;
185}
186template <typename K, typename V>
187void RemoteCallbackMap<K, V>::Clear() {
188  lock_guard<mutex> lock(map_lock_);
189
190  for (auto iter = map_.begin(); iter != map_.end();)
191    UnregisterInternal(iter++);
192}
193
194template <typename K, typename V>
195bool RemoteCallbackMap<K, V>::UnregisterInternal(
196    typename CallbackMap::iterator iter) {
197  sp<CallbackDeathRecipient> dr = iter->second;
198  map_.erase(iter);
199
200  if (IInterface::asBinder(dr->get_callback().get())->unlinkToDeath(dr) !=
201      android::NO_ERROR) {
202    LOG(ERROR) << "Failed to unlink death recipient from binder";
203
204    // We removed the entry from |map_| but unlinkToDeath failed. There isn't
205    // really much we can do here other than deleting the binder and returning
206    // an error.
207    return false;
208  }
209
210  VLOG(2) << "Callback successfully removed from map";
211
212  return true;
213}
214
215template <typename K, typename V>
216RemoteCallbackMap<K, V>::CallbackDeathRecipient::CallbackDeathRecipient(
217    const K& key, const sp<V>& callback, RemoteCallbackMap<K, V>* owner,
218    Delegate* delegate)
219    : key_(key), callback_(callback), owner_(owner), delegate_(delegate) {
220  CHECK(callback_.get());
221}
222
223template <typename K, typename V>
224void RemoteCallbackMap<K, V>::CallbackDeathRecipient::binderDied(
225    const wp<IBinder>& who) {
226  VLOG(1) << "Received binderDied";
227
228  sp<IBinder> binder = IInterface::asBinder(callback_.get());
229  CHECK(who.unsafe_get() == binder.get());
230
231  // Remove the callback but no need to call unlinkToDeath.
232  {
233    lock_guard<mutex> lock(owner_->map_lock_);
234    auto iter = owner_->map_.find(key_);
235    CHECK(iter != owner_->map_.end());
236    owner_->map_.erase(iter);
237  }
238
239  VLOG(1) << "Callback from dead process unregistered; notifying delegate";
240
241  // Notify delegate.
242  if (delegate_) delegate_->OnRemoteCallbackRemoved(key_);
243}
244
245}  // namespace binder
246}  // namespace ipc
247