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