1 /**
2 * Copyright (c) 2020, 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 #define LOG_TAG "carwatchdogd"
18 #define DEBUG false // STOPSHIP if true.
19
20 #include "WatchdogServiceHelper.h"
21
22 #include "ServiceManager.h"
23
24 #include <android/binder_ibinder.h>
25
26 namespace android {
27 namespace automotive {
28 namespace watchdog {
29
30 using ::aidl::android::automotive::watchdog::TimeoutLength;
31 using ::aidl::android::automotive::watchdog::internal::ICarWatchdogServiceForSystem;
32 using ::aidl::android::automotive::watchdog::internal::PackageInfo;
33 using ::aidl::android::automotive::watchdog::internal::PackageIoOveruseStats;
34 using ::aidl::android::automotive::watchdog::internal::ResourceStats;
35 using ::aidl::android::automotive::watchdog::internal::UserPackageIoUsageStats;
36 using ::android::sp;
37 using ::android::wp;
38 using ::android::base::Error;
39 using ::android::base::Result;
40 using ::ndk::ScopedAIBinder_DeathRecipient;
41 using ::ndk::ScopedAStatus;
42 using ::ndk::SpAIBinder;
43
44 namespace {
45
fromExceptionCodeWithMessage(binder_exception_t exceptionCode,const std::string & message)46 ScopedAStatus fromExceptionCodeWithMessage(binder_exception_t exceptionCode,
47 const std::string& message) {
48 ALOGW("%s.", message.c_str());
49 return ScopedAStatus::fromExceptionCodeWithMessage(exceptionCode, message.c_str());
50 }
51
onBinderDied(void * cookie)52 void onBinderDied(void* cookie) {
53 const auto& thiz = ServiceManager::getInstance()->getWatchdogServiceHelper();
54 if (thiz == nullptr) {
55 return;
56 }
57 thiz->handleBinderDeath(cookie);
58 }
59
60 } // namespace
61
WatchdogServiceHelper()62 WatchdogServiceHelper::WatchdogServiceHelper() :
63 mWatchdogProcessService(nullptr),
64 mWatchdogServiceDeathRecipient(
65 ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(onBinderDied))),
66 mDeathRegistrationWrapper(sp<AIBinderDeathRegistrationWrapper>::make()),
67 mService(nullptr) {}
68
init(const sp<WatchdogProcessServiceInterface> & watchdogProcessService)69 Result<void> WatchdogServiceHelper::init(
70 const sp<WatchdogProcessServiceInterface>& watchdogProcessService) {
71 if (watchdogProcessService == nullptr) {
72 return Error() << "Must provide a non-null watchdog process service instance";
73 }
74 mWatchdogProcessService = watchdogProcessService;
75 return {};
76 }
77
registerService(const std::shared_ptr<ICarWatchdogServiceForSystem> & service)78 ScopedAStatus WatchdogServiceHelper::registerService(
79 const std::shared_ptr<ICarWatchdogServiceForSystem>& service) {
80 if (service == nullptr) {
81 return fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, "Must provide non-null service");
82 }
83 const auto binder = service->asBinder();
84 AIBinder* aiBinder = binder.get();
85 {
86 std::unique_lock writeLock(mRWMutex);
87 if (mWatchdogProcessService == nullptr) {
88 return fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
89 "Must initialize watchdog service helper before "
90 "registering car watchdog service");
91 }
92 if (mService != nullptr && mService->asBinder() == binder) {
93 return ScopedAStatus::ok();
94 }
95 unregisterServiceLocked(/*doUnregisterFromProcessService=*/true);
96 if (auto status = mWatchdogProcessService
97 ->registerCarWatchdogService(binder,
98 sp<WatchdogServiceHelperInterface>::
99 fromExisting(this));
100 !status.isOk()) {
101 return status;
102 }
103 mService = service;
104 }
105 auto ret =
106 mDeathRegistrationWrapper->linkToDeath(aiBinder, mWatchdogServiceDeathRecipient.get(),
107 static_cast<void*>(aiBinder));
108 if (!ret.isOk()) {
109 std::unique_lock writeLock(mRWMutex);
110 if (mService != nullptr && mService->asBinder() == binder) {
111 mWatchdogProcessService->unregisterCarWatchdogService(binder);
112 mService.reset();
113 }
114 return fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
115 "Failed to register car watchdog service as it is "
116 "dead");
117 }
118 if (DEBUG) {
119 ALOGW("CarWatchdogService is registered");
120 }
121 return ScopedAStatus::ok();
122 }
123
unregisterService(const std::shared_ptr<ICarWatchdogServiceForSystem> & service)124 ScopedAStatus WatchdogServiceHelper::unregisterService(
125 const std::shared_ptr<ICarWatchdogServiceForSystem>& service) {
126 if (service == nullptr) {
127 return fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, "Must provide non-null service");
128 }
129 std::unique_lock writeLock(mRWMutex);
130 if (const auto binder = service->asBinder();
131 mService == nullptr || binder != mService->asBinder()) {
132 return fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
133 "Failed to unregister car watchdog service as it is "
134 "not registered");
135 }
136 unregisterServiceLocked(/*doUnregisterFromProcessService=*/true);
137
138 if (DEBUG) {
139 ALOGW("CarWatchdogService is unregistered");
140 }
141 return ScopedAStatus::ok();
142 }
143
handleBinderDeath(void * cookie)144 void WatchdogServiceHelper::handleBinderDeath(void* cookie) {
145 std::unique_lock writeLock(mRWMutex);
146 if (mService == nullptr) {
147 return;
148 }
149 const auto curBinder = mService->asBinder();
150 if (reinterpret_cast<uintptr_t>(curBinder.get()) != reinterpret_cast<uintptr_t>(cookie)) {
151 return;
152 }
153 ALOGW("Car watchdog service had died.");
154 mService.reset();
155 mWatchdogProcessService->unregisterCarWatchdogService(curBinder);
156 }
157
terminate()158 void WatchdogServiceHelper::terminate() {
159 std::unique_lock writeLock(mRWMutex);
160 unregisterServiceLocked(/*doUnregisterFromProcessService=*/true);
161 mWatchdogProcessService.clear();
162 }
163
checkIfAlive(const SpAIBinder & who,int32_t sessionId,TimeoutLength timeout) const164 ScopedAStatus WatchdogServiceHelper::checkIfAlive(const SpAIBinder& who, int32_t sessionId,
165 TimeoutLength timeout) const {
166 std::shared_ptr<ICarWatchdogServiceForSystem> service;
167 if (std::shared_lock readLock(mRWMutex); mService == nullptr || mService->asBinder() != who) {
168 return fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
169 "Dropping checkIfAlive request as the given car "
170 "watchdog service binder isn't registered");
171 } else {
172 service = mService;
173 }
174 return service
175 ->checkIfAlive(sessionId,
176 static_cast<
177 aidl::android::automotive::watchdog::internal::TimeoutLength>(
178 timeout));
179 }
180
prepareProcessTermination(const SpAIBinder & who)181 ScopedAStatus WatchdogServiceHelper::prepareProcessTermination(const SpAIBinder& who) {
182 std::shared_ptr<ICarWatchdogServiceForSystem> service;
183 if (std::shared_lock readLock(mRWMutex); mService == nullptr || mService->asBinder() != who) {
184 return fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
185 "Dropping prepareProcessTermination request as the "
186 "given car watchdog service binder isn't registered");
187 } else {
188 service = mService;
189 }
190 auto status = service->prepareProcessTermination();
191 if (status.isOk()) {
192 std::unique_lock writeLock(mRWMutex);
193 /*
194 * prepareTermination callback is called when CarWatchdogService isn't responding, which
195 * indicates the CarWatchdogService is stuck, terminating, or restarting.
196 *
197 * When CarWatchdogService is terminating, it will issue an unregisterService call.
198 * If the unregisterService is executed after the previous |readLock| is released and the
199 * before current |writeLock| is acquired, the |mService| will be updated to null. Then it
200 * won't match |service|.
201 *
202 * When CarWatchdogService is restarting, it will issue an registerService call. When the
203 * registerService is executed between after the previous |readLock| is released and before
204 * the current |writeLock| is acquired, the |mService| will be overwritten. This will lead
205 * to unregistering the new CarWatchdogService.
206 *
207 * To avoid this race condition, check mService before proceeding with unregistering the
208 * CarWatchdogService.
209 */
210 if (mService == service) {
211 // WatchdogProcessService unregisters the watchdog service before calling
212 // prepareProcessTermination. So skip unregistering from WatchdogProcessService.
213 unregisterServiceLocked(/*doUnregisterFromProcessService=*/false);
214 }
215 }
216 return status;
217 }
218
unregisterServiceLocked(bool doUnregisterFromProcessService)219 void WatchdogServiceHelper::unregisterServiceLocked(bool doUnregisterFromProcessService) {
220 if (mService == nullptr) return;
221 const auto binder = mService->asBinder();
222 AIBinder* aiBinder = binder.get();
223 mDeathRegistrationWrapper->unlinkToDeath(aiBinder, mWatchdogServiceDeathRecipient.get(),
224 static_cast<void*>(aiBinder));
225 if (doUnregisterFromProcessService) {
226 mWatchdogProcessService->unregisterCarWatchdogService(binder);
227 }
228 mService.reset();
229 }
230
getPackageInfosForUids(const std::vector<int32_t> & uids,const std::vector<std::string> & vendorPackagePrefixes,std::vector<PackageInfo> * packageInfos) const231 ScopedAStatus WatchdogServiceHelper::getPackageInfosForUids(
232 const std::vector<int32_t>& uids, const std::vector<std::string>& vendorPackagePrefixes,
233 std::vector<PackageInfo>* packageInfos) const {
234 std::shared_ptr<ICarWatchdogServiceForSystem> service;
235 if (std::shared_lock readLock(mRWMutex); mService == nullptr) {
236 return fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
237 "Watchdog service is not initialized");
238 } else {
239 service = mService;
240 }
241 /*
242 * The expected number of vendor package prefixes is in the order of 10s. Thus the overhead of
243 * forwarding these in each get call is very low.
244 */
245 return service->getPackageInfosForUids(uids, vendorPackagePrefixes, packageInfos);
246 }
247
resetResourceOveruseStats(const std::vector<std::string> & packageNames) const248 ScopedAStatus WatchdogServiceHelper::resetResourceOveruseStats(
249 const std::vector<std::string>& packageNames) const {
250 std::shared_ptr<ICarWatchdogServiceForSystem> service;
251 if (std::shared_lock readLock(mRWMutex); mService == nullptr) {
252 return fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
253 "Watchdog service is not initialized");
254 } else {
255 service = mService;
256 }
257 return service->resetResourceOveruseStats(packageNames);
258 }
259
requestTodayIoUsageStats() const260 ScopedAStatus WatchdogServiceHelper::requestTodayIoUsageStats() const {
261 std::shared_ptr<ICarWatchdogServiceForSystem> service;
262 if (std::shared_lock readLock(mRWMutex); mService == nullptr) {
263 return fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
264 "Watchdog service is not initialized");
265 } else {
266 service = mService;
267 }
268 return service->requestTodayIoUsageStats();
269 }
270
onLatestResourceStats(const std::vector<ResourceStats> & resourceStats) const271 ScopedAStatus WatchdogServiceHelper::onLatestResourceStats(
272 const std::vector<ResourceStats>& resourceStats) const {
273 std::shared_ptr<ICarWatchdogServiceForSystem> service;
274 if (std::shared_lock readLock(mRWMutex); mService == nullptr) {
275 return fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
276 "Watchdog service is not initialized");
277 } else {
278 service = mService;
279 }
280 return service->onLatestResourceStats(resourceStats);
281 }
282
requestAidlVhalPid() const283 ScopedAStatus WatchdogServiceHelper::requestAidlVhalPid() const {
284 std::shared_ptr<ICarWatchdogServiceForSystem> service;
285 if (std::shared_lock readLock(mRWMutex); mService == nullptr) {
286 return fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
287 "Watchdog service is not initialized");
288 } else {
289 service = mService;
290 }
291 return service->requestAidlVhalPid();
292 }
293
294 } // namespace watchdog
295 } // namespace automotive
296 } // namespace android
297