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 <functional>
20#include <mutex>
21#include <unordered_map>
22
23#include <base/logging.h>
24#include <base/macros.h>
25#include <binder/IBinder.h>
26#include <binder/IInterface.h>
27
28namespace ipc {
29namespace binder {
30
31// Takes care of the grunt work of maintaining a list of remote interfaces,
32// typically for the use of performing registered callbacks from a remote
33// service. This is a native equivalent of the the android.os.RemoteCallbackList
34// Java class. The type "T" must inherit from android::IInterface.
35//
36// TODO(armansito): We need to unit test this class. Right now it's defined as a
37// simple template interface over the native libbinder types directly and we
38// can't compile libbinder for host unless the Binder kernel module is enabled
39// on the system. Figure out whether to:
40//    1) write the Binder test-code in a new target-only executable;
41//    2) conditionally compile into the host-native test suite if the Binder
42//       module is built;
43//    3) provide a test-only static library that re-defines the libbinder
44//       classes as mocks.
45// (See http://b/23386387)
46//
47// TODO(armansito): We should make this class non-final and the template
48// interface abstract, so that code that depends on this can be unit tested
49// against a mock version of this class.
50//
51// TODO(armansito): Consider submitting this class to frameworks/native/binder.
52template<typename T>
53class RemoteCallbackList final {
54 public:
55  RemoteCallbackList() = default;
56  ~RemoteCallbackList();
57
58  // Register and unregister a callback interface. Registering will
59  // automatically start tracking for death notifications in case the remote
60  // process hosting the Binder dies. In such a case, the Binder is
61  // automatically removed from the list.
62  bool Register(const android::sp<T>& callback);
63  bool Unregister(const android::sp<T>& callback);
64
65  // Calls the given function on each of the contained callbacks. The internal
66  // mutex is locked for the duration of the iteration.
67  void ForEach(const std::function<void(T*)>& callback);
68
69 private:
70  class CallbackDeathRecipient : public android::IBinder::DeathRecipient {
71   public:
72    CallbackDeathRecipient(const android::sp<T>& callback,
73                           RemoteCallbackList* owner);
74
75    android::sp<T> get_callback() const { return callback_; }
76
77    // android::IBinder::DeathRecipient override:
78    void binderDied(const android::wp<android::IBinder>& who) override;
79
80   private:
81    android::sp<T> callback_;
82    RemoteCallbackList<T>* owner_;  // weak
83  };
84
85  // Typedef for internal map container. This keeps track of a given Binder and
86  // a death receiver associated with it.
87  using CallbackMap = std::unordered_map<android::IBinder*,
88                                         android::sp<CallbackDeathRecipient>>;
89
90  bool UnregisterInternal(typename CallbackMap::iterator iter);
91
92  std::mutex map_lock_;
93  CallbackMap callbacks_;
94
95  DISALLOW_COPY_AND_ASSIGN(RemoteCallbackList);
96};
97
98// Template Implementation details below
99// ========================================================
100
101using android::IBinder;
102using android::IInterface;
103using android::sp;
104using android::wp;
105
106template<typename T>
107RemoteCallbackList<T>::~RemoteCallbackList() {
108  std::lock_guard<std::mutex> lock(map_lock_);
109  for (auto iter = callbacks_.begin(); iter != callbacks_.end(); ++iter)
110    UnregisterInternal(iter);
111}
112
113template<typename T>
114bool RemoteCallbackList<T>::Register(const sp<T>& callback) {
115  std::lock_guard<std::mutex> lock(map_lock_);
116
117  sp<IBinder> binder = IInterface::asBinder(callback.get());
118  if (callbacks_.find(binder.get()) != callbacks_.end()) {
119    VLOG(1) << "Callback list already contains given callback";
120    return false;
121  }
122
123  sp<CallbackDeathRecipient> dr(new CallbackDeathRecipient(callback, this));
124
125  if (binder->linkToDeath(dr) != android::NO_ERROR) {
126    LOG(ERROR) << "Failed to link death recipient to binder";
127    return false;
128  }
129
130  callbacks_[binder.get()] = dr;
131
132  VLOG(2) << "Callback successfully registered with list";
133
134  return true;
135}
136
137template<typename T>
138bool RemoteCallbackList<T>::Unregister(const sp<T>& callback) {
139  std::lock_guard<std::mutex> lock(map_lock_);
140
141  sp<IBinder> binder = IInterface::asBinder(callback.get());
142  auto iter = callbacks_.find(binder.get());
143  if (iter == callbacks_.end()) {
144    VLOG(2) << "Given callback not registered with this list";
145    return false;
146  }
147
148  return UnregisterInternal(iter);
149}
150
151template<typename T>
152void RemoteCallbackList<T>::ForEach(const std::function<void(T*)>& callback) {
153  std::lock_guard<std::mutex> lock(map_lock_);
154  for (const auto& iter : callbacks_)
155    callback(iter.second->get_callback().get());
156}
157
158template<typename T>
159bool RemoteCallbackList<T>::UnregisterInternal(
160    typename CallbackMap::iterator iter) {
161  sp<CallbackDeathRecipient> dr = iter->second;
162  callbacks_.erase(iter);
163
164  if (IInterface::asBinder(dr->get_callback().get())->unlinkToDeath(dr) !=
165      android::NO_ERROR) {
166    LOG(ERROR) << "Failed to unlink death recipient from binder";
167
168    // We removed the entry from |map_| but unlinkToDeath failed. There isn't
169    // really much we can do here other than deleting the binder and returning
170    // an error.
171    return false;
172  }
173
174  VLOG(2) << "Callback successfully removed from list";
175
176  return true;
177}
178
179template<typename T>
180RemoteCallbackList<T>::CallbackDeathRecipient::CallbackDeathRecipient(
181    const sp<T>& callback,
182    RemoteCallbackList<T>* owner)
183    : callback_(callback),
184      owner_(owner) {
185  CHECK(callback_.get());
186  CHECK(owner_);
187}
188
189template<typename T>
190void RemoteCallbackList<T>::CallbackDeathRecipient::binderDied(
191    const wp<IBinder>& who) {
192  VLOG(1) << "Received binderDied";
193
194  sp<IBinder> binder = IInterface::asBinder(callback_.get());
195  CHECK(who.unsafe_get() == binder.get());
196
197  // Remove the callback but no need to call unlinkToDeath.
198  std::lock_guard<std::mutex> lock(owner_->map_lock_);
199  auto iter = owner_->callbacks_.find(binder.get());
200  CHECK(iter != owner_->callbacks_.end());
201  owner_->callbacks_.erase(iter);
202
203  VLOG(1) << "Callback from dead process unregistered";
204}
205
206}  // namespace binder
207}  // namespace ipc
208