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
IsDeadObject(const Return<void> & ret)38 bool IsDeadObject(const Return<void>& ret) {
39 if (ret.isOk()) return false;
40 if (ret.isDeadObject()) return true;
41 return false;
42 }
43
BinderHealth(const std::string & name,const sp<IHealth> & impl)44 BinderHealth::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
registerCallback(const sp<V2_0::IHealthInfoCallback> & callback)54 Return<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);
79 if (IsDeadObject(ret)) {
80 // 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
unregisterCallbackInternal(const sp<IBase> & callback)94 bool 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
update()113 Return<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
unregisterCallback(const sp<V2_0::IHealthInfoCallback> & callback)126 Return<Result> BinderHealth::unregisterCallback(const sp<V2_0::IHealthInfoCallback>& callback) {
127 return unregisterCallbackInternal(callback) ? Result::SUCCESS : Result::NOT_FOUND;
128 }
129
OnHealthInfoChanged(const HealthInfo & health_info)130 void 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);
135 if (IsDeadObject(ret)) {
136 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
serviceDied(uint64_t,const wp<IBase> & who)147 void BinderHealth::serviceDied(uint64_t /* cookie */, const wp<IBase>& who) {
148 (void)unregisterCallbackInternal(who.promote());
149 }
150
BinderEvent(uint32_t)151 void BinderHealth::BinderEvent(uint32_t /*epevents*/) {
152 if (binder_fd_ >= 0) {
153 handleTransportPoll(binder_fd_);
154 }
155 }
156
Init(struct healthd_config * config)157 void 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
PrepareToWait(void)180 int 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
190