| // |
| // Copyright 2015 Google, Inc. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at: |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| |
| #pragma once |
| |
| #include <functional> |
| #include <mutex> |
| #include <unordered_map> |
| |
| #include <base/logging.h> |
| #include <base/macros.h> |
| #include <binder/IBinder.h> |
| #include <binder/IInterface.h> |
| |
| namespace ipc { |
| namespace binder { |
| |
| // Takes care of the grunt work of maintaining a list of remote interfaces, |
| // typically for the use of performing registered callbacks from a remote |
| // service. This is a native equivalent of the the android.os.RemoteCallbackList |
| // Java class. The type "T" must inherit from android::IInterface. |
| // |
| // TODO(armansito): We need to unit test this class. Right now it's defined as a |
| // simple template interface over the native libbinder types directly and we |
| // can't compile libbinder for host unless the Binder kernel module is enabled |
| // on the system. Figure out whether to: |
| // 1) write the Binder test-code in a new target-only executable; |
| // 2) conditionally compile into the host-native test suite if the Binder |
| // module is built; |
| // 3) provide a test-only static library that re-defines the libbinder |
| // classes as mocks. |
| // (See http://b/23386387) |
| // |
| // TODO(armansito): We should make this class non-final and the template |
| // interface abstract, so that code that depends on this can be unit tested |
| // against a mock version of this class. |
| // |
| // TODO(armansito): Consider submitting this class to frameworks/native/binder. |
| template <typename T> |
| class RemoteCallbackList final { |
| public: |
| RemoteCallbackList() = default; |
| ~RemoteCallbackList(); |
| |
| // Register and unregister a callback interface. Registering will |
| // automatically start tracking for death notifications in case the remote |
| // process hosting the Binder dies. In such a case, the Binder is |
| // automatically removed from the list. |
| bool Register(const android::sp<T>& callback); |
| bool Unregister(const android::sp<T>& callback); |
| |
| // Calls the given function on each of the contained callbacks. The internal |
| // mutex is locked for the duration of the iteration. |
| void ForEach(const std::function<void(T*)>& callback); |
| |
| private: |
| class CallbackDeathRecipient : public android::IBinder::DeathRecipient { |
| public: |
| CallbackDeathRecipient(const android::sp<T>& callback, |
| RemoteCallbackList* owner); |
| |
| android::sp<T> get_callback() const { return callback_; } |
| |
| // android::IBinder::DeathRecipient override: |
| void binderDied(const android::wp<android::IBinder>& who) override; |
| |
| private: |
| android::sp<T> callback_; |
| RemoteCallbackList<T>* owner_; // weak |
| }; |
| |
| // Typedef for internal map container. This keeps track of a given Binder and |
| // a death receiver associated with it. |
| using CallbackMap = std::unordered_map<android::IBinder*, |
| android::sp<CallbackDeathRecipient>>; |
| |
| bool UnregisterInternal(typename CallbackMap::iterator iter); |
| |
| std::mutex map_lock_; |
| CallbackMap callbacks_; |
| |
| DISALLOW_COPY_AND_ASSIGN(RemoteCallbackList); |
| }; |
| |
| // Template Implementation details below |
| // ======================================================== |
| |
| using android::IBinder; |
| using android::IInterface; |
| using android::sp; |
| using android::wp; |
| |
| template <typename T> |
| RemoteCallbackList<T>::~RemoteCallbackList() { |
| std::lock_guard<std::mutex> lock(map_lock_); |
| for (auto iter = callbacks_.begin(); iter != callbacks_.end(); ++iter) |
| UnregisterInternal(iter); |
| } |
| |
| template <typename T> |
| bool RemoteCallbackList<T>::Register(const sp<T>& callback) { |
| std::lock_guard<std::mutex> lock(map_lock_); |
| |
| sp<IBinder> binder = IInterface::asBinder(callback.get()); |
| if (callbacks_.find(binder.get()) != callbacks_.end()) { |
| VLOG(1) << "Callback list already contains given callback"; |
| return false; |
| } |
| |
| sp<CallbackDeathRecipient> dr(new CallbackDeathRecipient(callback, this)); |
| |
| if (binder->linkToDeath(dr) != android::NO_ERROR) { |
| LOG(ERROR) << "Failed to link death recipient to binder"; |
| return false; |
| } |
| |
| callbacks_[binder.get()] = dr; |
| |
| VLOG(2) << "Callback successfully registered with list"; |
| |
| return true; |
| } |
| |
| template <typename T> |
| bool RemoteCallbackList<T>::Unregister(const sp<T>& callback) { |
| std::lock_guard<std::mutex> lock(map_lock_); |
| |
| sp<IBinder> binder = IInterface::asBinder(callback.get()); |
| auto iter = callbacks_.find(binder.get()); |
| if (iter == callbacks_.end()) { |
| VLOG(2) << "Given callback not registered with this list"; |
| return false; |
| } |
| |
| return UnregisterInternal(iter); |
| } |
| |
| template <typename T> |
| void RemoteCallbackList<T>::ForEach(const std::function<void(T*)>& callback) { |
| std::lock_guard<std::mutex> lock(map_lock_); |
| for (const auto& iter : callbacks_) |
| callback(iter.second->get_callback().get()); |
| } |
| |
| template <typename T> |
| bool RemoteCallbackList<T>::UnregisterInternal( |
| typename CallbackMap::iterator iter) { |
| sp<CallbackDeathRecipient> dr = iter->second; |
| callbacks_.erase(iter); |
| |
| if (IInterface::asBinder(dr->get_callback().get())->unlinkToDeath(dr) != |
| android::NO_ERROR) { |
| LOG(ERROR) << "Failed to unlink death recipient from binder"; |
| |
| // We removed the entry from |map_| but unlinkToDeath failed. There isn't |
| // really much we can do here other than deleting the binder and returning |
| // an error. |
| return false; |
| } |
| |
| VLOG(2) << "Callback successfully removed from list"; |
| |
| return true; |
| } |
| |
| template <typename T> |
| RemoteCallbackList<T>::CallbackDeathRecipient::CallbackDeathRecipient( |
| const sp<T>& callback, RemoteCallbackList<T>* owner) |
| : callback_(callback), owner_(owner) { |
| CHECK(callback_.get()); |
| CHECK(owner_); |
| } |
| |
| template <typename T> |
| void RemoteCallbackList<T>::CallbackDeathRecipient::binderDied( |
| const wp<IBinder>& who) { |
| VLOG(1) << "Received binderDied"; |
| |
| sp<IBinder> binder = IInterface::asBinder(callback_.get()); |
| CHECK(who.unsafe_get() == binder.get()); |
| |
| // Remove the callback but no need to call unlinkToDeath. |
| std::lock_guard<std::mutex> lock(owner_->map_lock_); |
| auto iter = owner_->callbacks_.find(binder.get()); |
| CHECK(iter != owner_->callbacks_.end()); |
| owner_->callbacks_.erase(iter); |
| |
| VLOG(1) << "Callback from dead process unregistered"; |
| } |
| |
| } // namespace binder |
| } // namespace ipc |