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