1 /*
2 * Copyright (C) 2019 The Android Open Source Project
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 #include <health2impl/BinderHealth.h>
18
19 #include <android-base/logging.h>
20 #include <hidl/HidlTransportSupport.h>
21 #include <hwbinder/IPCThreadState.h>
22
23 #include <health2impl/Callback.h>
24 #include <health2impl/Health.h>
25
26 using android::hardware::handleTransportPoll;
27 using android::hardware::IPCThreadState;
28 using android::hardware::setupTransportPolling;
29
30 using android::hardware::health::V2_0::Result;
31
32 namespace android {
33 namespace hardware {
34 namespace health {
35 namespace V2_1 {
36 namespace implementation {
37
IsDeadObjectLogged(const Return<void> & ret)38 bool IsDeadObjectLogged(const Return<void>& ret) {
39 if (ret.isOk()) return false;
40 if (ret.isDeadObject()) return true;
41 LOG(ERROR) << "Cannot call healthInfoChanged* on callback: " << ret.description();
42 return false;
43 }
44
BinderHealth(const std::string & name,const sp<IHealth> & impl)45 BinderHealth::BinderHealth(const std::string& name, const sp<IHealth>& impl)
46 : HalHealthLoop(name, impl) {
47 CHECK_NE(this, impl.get());
48 CHECK(!impl->isRemote());
49 }
50
51 //
52 // Methods that handle callbacks.
53 //
54
registerCallback(const sp<V2_0::IHealthInfoCallback> & callback)55 Return<Result> BinderHealth::registerCallback(const sp<V2_0::IHealthInfoCallback>& callback) {
56 if (callback == nullptr) {
57 return Result::SUCCESS;
58 }
59
60 Callback* wrapped = nullptr;
61 {
62 std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
63 wrapped = callbacks_.emplace_back(Wrap(callback)).get();
64 // unlock
65 }
66
67 auto linkRet = callback->linkToDeath(this, 0u /* cookie */);
68 if (!linkRet.withDefault(false)) {
69 LOG(WARNING) << __func__ << "Cannot link to death: "
70 << (linkRet.isOk() ? "linkToDeath returns false" : linkRet.description());
71 // ignore the error
72 }
73
74 getHealthInfo_2_1([&](auto res, const auto& health_info) {
75 if (res != Result::SUCCESS) {
76 LOG(ERROR) << "Cannot call getHealthInfo_2_1: " << toString(res);
77 return;
78 }
79 auto ret = wrapped->Notify(health_info);
80 if (IsDeadObjectLogged(ret)) {
81 // Remove callback reference.
82 std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
83 auto it = std::find_if(callbacks_.begin(), callbacks_.end(),
84 [wrapped](const auto& cb) { return cb.get() == wrapped; });
85 if (it != callbacks_.end()) {
86 callbacks_.erase(it);
87 }
88 // unlock
89 }
90 });
91
92 return Result::SUCCESS;
93 }
94
unregisterCallbackInternal(const sp<IBase> & callback)95 bool BinderHealth::unregisterCallbackInternal(const sp<IBase>& callback) {
96 if (callback == nullptr) {
97 return false;
98 }
99
100 bool removed = false;
101 std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
102 for (auto it = callbacks_.begin(); it != callbacks_.end();) {
103 if (interfacesEqual((*it)->Get(), callback)) {
104 it = callbacks_.erase(it);
105 removed = true;
106 } else {
107 ++it;
108 }
109 }
110 (void)callback->unlinkToDeath(this).isOk(); // ignore errors
111 return removed;
112 }
113
update()114 Return<Result> BinderHealth::update() {
115 Result result = service()->update();
116 if (result != Result::SUCCESS) return result;
117 getHealthInfo_2_1([&](auto res, const auto& health_info) {
118 if (res != Result::SUCCESS) {
119 result = res;
120 return;
121 }
122 OnHealthInfoChanged(health_info);
123 });
124 return result;
125 }
126
unregisterCallback(const sp<V2_0::IHealthInfoCallback> & callback)127 Return<Result> BinderHealth::unregisterCallback(const sp<V2_0::IHealthInfoCallback>& callback) {
128 return unregisterCallbackInternal(callback) ? Result::SUCCESS : Result::NOT_FOUND;
129 }
130
OnHealthInfoChanged(const HealthInfo & health_info)131 void BinderHealth::OnHealthInfoChanged(const HealthInfo& health_info) {
132 // Notify all callbacks
133 std::unique_lock<decltype(callbacks_lock_)> lock(callbacks_lock_);
134 for (auto it = callbacks_.begin(); it != callbacks_.end();) {
135 auto ret = (*it)->Notify(health_info);
136 if (IsDeadObjectLogged(ret)) {
137 it = callbacks_.erase(it);
138 } else {
139 ++it;
140 }
141 }
142 lock.unlock();
143
144 // adjusts uevent / wakealarm periods
145 HalHealthLoop::OnHealthInfoChanged(health_info);
146 }
147
serviceDied(uint64_t,const wp<IBase> & who)148 void BinderHealth::serviceDied(uint64_t /* cookie */, const wp<IBase>& who) {
149 (void)unregisterCallbackInternal(who.promote());
150 }
151
BinderEvent(uint32_t)152 void BinderHealth::BinderEvent(uint32_t /*epevents*/) {
153 if (binder_fd_ >= 0) {
154 handleTransportPoll(binder_fd_);
155 }
156 }
157
Init(struct healthd_config * config)158 void BinderHealth::Init(struct healthd_config* config) {
159 // Set up epoll and get uevent / wake alarm periods
160 HalHealthLoop::Init(config);
161
162 LOG(INFO) << instance_name() << " instance initializing with healthd_config...";
163
164 binder_fd_ = setupTransportPolling();
165
166 if (binder_fd_ >= 0) {
167 auto binder_event = [](auto* health_loop, uint32_t epevents) {
168 static_cast<BinderHealth*>(health_loop)->BinderEvent(epevents);
169 };
170 if (RegisterEvent(binder_fd_, binder_event, EVENT_NO_WAKEUP_FD) != 0) {
171 PLOG(ERROR) << instance_name() << " instance: Register for binder events failed";
172 }
173 }
174
175 CHECK_EQ(registerAsService(instance_name()), android::OK)
176 << instance_name() << ": Failed to register HAL";
177
178 LOG(INFO) << instance_name() << ": Hal init done";
179 }
180
PrepareToWait(void)181 int BinderHealth::PrepareToWait(void) {
182 IPCThreadState::self()->flushCommands();
183 return HalHealthLoop::PrepareToWait();
184 }
185
186 } // namespace implementation
187 } // namespace V2_1
188 } // namespace health
189 } // namespace hardware
190 } // namespace android
191