// // Copyright (C) 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 #include #include #include #include #include #include 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 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& callback); bool Unregister(const android::sp& 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& callback); private: class CallbackDeathRecipient : public android::IBinder::DeathRecipient { public: CallbackDeathRecipient(const android::sp& callback, RemoteCallbackList* owner); android::sp get_callback() const { return callback_; } // android::IBinder::DeathRecipient override: void binderDied(const android::wp& who) override; private: android::sp callback_; RemoteCallbackList* 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>; 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 RemoteCallbackList::~RemoteCallbackList() { std::lock_guard lock(map_lock_); for (auto iter = callbacks_.begin(); iter != callbacks_.end(); ++iter) UnregisterInternal(iter); } template bool RemoteCallbackList::Register(const sp& callback) { std::lock_guard lock(map_lock_); sp binder = IInterface::asBinder(callback.get()); if (callbacks_.find(binder.get()) != callbacks_.end()) { VLOG(1) << "Callback list already contains given callback"; return false; } sp 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 bool RemoteCallbackList::Unregister(const sp& callback) { std::lock_guard lock(map_lock_); sp 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 void RemoteCallbackList::ForEach(const std::function& callback) { std::lock_guard lock(map_lock_); for (const auto& iter : callbacks_) callback(iter.second->get_callback().get()); } template bool RemoteCallbackList::UnregisterInternal( typename CallbackMap::iterator iter) { sp 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 RemoteCallbackList::CallbackDeathRecipient::CallbackDeathRecipient( const sp& callback, RemoteCallbackList* owner) : callback_(callback), owner_(owner) { CHECK(callback_.get()); CHECK(owner_); } template void RemoteCallbackList::CallbackDeathRecipient::binderDied( const wp& who) { VLOG(1) << "Received binderDied"; sp binder = IInterface::asBinder(callback_.get()); CHECK(who.unsafe_get() == binder.get()); // Remove the callback but no need to call unlinkToDeath. std::lock_guard 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