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 
19 #include "WatchdogServiceHelper.h"
20 
21 #include "ServiceManager.h"
22 
23 #include <android/automotive/watchdog/internal/BnCarWatchdogServiceForSystem.h>
24 
25 namespace android {
26 namespace automotive {
27 namespace watchdog {
28 
29 namespace aawi = ::android::automotive::watchdog::internal;
30 
31 using aawi::BnCarWatchdogServiceForSystem;
32 using aawi::ICarWatchdogServiceForSystem;
33 using aawi::PackageInfo;
34 using aawi::PackageIoOveruseStats;
35 using aawi::UserPackageIoUsageStats;
36 using ::android::IBinder;
37 using ::android::sp;
38 using ::android::wp;
39 using ::android::base::Error;
40 using ::android::base::Result;
41 using ::android::binder::Status;
42 
43 namespace {
44 
fromExceptionCode(int32_t exceptionCode,std::string message)45 Status fromExceptionCode(int32_t exceptionCode, std::string message) {
46     ALOGW("%s.", message.c_str());
47     return Status::fromExceptionCode(exceptionCode, message.c_str());
48 }
49 
50 }  // namespace
51 
init(const sp<WatchdogProcessService> & watchdogProcessService)52 Result<void> WatchdogServiceHelper::init(const sp<WatchdogProcessService>& watchdogProcessService) {
53     if (watchdogProcessService == nullptr) {
54         return Error() << "Must provide a non-null watchdog process service instance";
55     }
56     mWatchdogProcessService = watchdogProcessService;
57     return mWatchdogProcessService->registerWatchdogServiceHelper(this);
58 }
59 
~WatchdogServiceHelper()60 WatchdogServiceHelper::~WatchdogServiceHelper() {
61     terminate();
62 }
63 
registerService(const android::sp<ICarWatchdogServiceForSystem> & service)64 Status WatchdogServiceHelper::registerService(
65         const android::sp<ICarWatchdogServiceForSystem>& service) {
66     std::unique_lock writeLock(mRWMutex);
67     if (mWatchdogProcessService == nullptr) {
68         return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE,
69                                          "Must initialize watchdog service helper before "
70                                          "registering car watchdog service");
71     }
72     sp<IBinder> curBinder = BnCarWatchdogServiceForSystem::asBinder(mService);
73     sp<IBinder> newBinder = BnCarWatchdogServiceForSystem::asBinder(service);
74     if (mService != nullptr && curBinder == newBinder) {
75         return Status::ok();
76     }
77     if (status_t ret = newBinder->linkToDeath(this); ret != OK) {
78         return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE,
79                                          "Failed to register car watchdog service as it is dead");
80     }
81     unregisterServiceLocked();
82     if (Status status = mWatchdogProcessService->registerCarWatchdogService(newBinder);
83         !status.isOk()) {
84         newBinder->unlinkToDeath(this);
85         return status;
86     }
87     mService = service;
88     return Status::ok();
89 }
90 
unregisterService(const sp<ICarWatchdogServiceForSystem> & service)91 Status WatchdogServiceHelper::unregisterService(const sp<ICarWatchdogServiceForSystem>& service) {
92     std::unique_lock writeLock(mRWMutex);
93     if (sp<IBinder> binder = BnCarWatchdogServiceForSystem::asBinder(service);
94         binder != BnCarWatchdogServiceForSystem::asBinder(mService)) {
95         return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
96                                  "Failed to unregister car watchdog service as it is not "
97                                  "registered");
98     }
99     unregisterServiceLocked();
100     return Status::ok();
101 }
102 
binderDied(const wp<android::IBinder> & who)103 void WatchdogServiceHelper::binderDied(const wp<android::IBinder>& who) {
104     std::unique_lock writeLock(mRWMutex);
105     sp<IBinder> curBinder = BnCarWatchdogServiceForSystem::asBinder(mService);
106     if (IBinder* diedBinder = who.unsafe_get(); curBinder == nullptr || diedBinder != curBinder) {
107         return;
108     }
109     ALOGW("Car watchdog service had died.");
110     mService.clear();
111     mWatchdogProcessService->unregisterCarWatchdogService(curBinder);
112 }
113 
terminate()114 void WatchdogServiceHelper::terminate() {
115     std::unique_lock writeLock(mRWMutex);
116     unregisterServiceLocked();
117     mWatchdogProcessService.clear();
118 }
119 
checkIfAlive(const wp<IBinder> & who,int32_t sessionId,TimeoutLength timeout) const120 Status WatchdogServiceHelper::checkIfAlive(const wp<IBinder>& who, int32_t sessionId,
121                                            TimeoutLength timeout) const {
122     sp<ICarWatchdogServiceForSystem> service;
123     if (std::shared_lock readLock(mRWMutex); mService == nullptr ||
124         who.unsafe_get() != BnCarWatchdogServiceForSystem::asBinder(mService)) {
125         return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
126                                  "Dropping checkIfAlive request as the given car watchdog "
127                                  "service "
128                                  "binder isn't registered");
129     } else {
130         service = mService;
131     }
132     return service->checkIfAlive(sessionId, static_cast<aawi::TimeoutLength>(timeout));
133 }
134 
prepareProcessTermination(const wp<IBinder> & who)135 Status WatchdogServiceHelper::prepareProcessTermination(const wp<IBinder>& who) {
136     sp<ICarWatchdogServiceForSystem> service;
137     if (std::shared_lock readLock(mRWMutex); mService == nullptr ||
138         who.unsafe_get() != BnCarWatchdogServiceForSystem::asBinder(mService)) {
139         return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
140                                  "Dropping prepareProcessTermination request as the given "
141                                  "car watchdog service binder isn't registered");
142     } else {
143         service = mService;
144     }
145     Status status = service->prepareProcessTermination();
146     if (status.isOk()) {
147         std::unique_lock writeLock(mRWMutex);
148         /*
149          * prepareTermination callback is called when CarWatchdogService isn't responding, which
150          * indicates the CarWatchdogService is stuck, terminating, or restarting.
151          *
152          * When CarWatchdogService is terminating, it will issue an unregisterService call.
153          * If the unregisterService is executed after the previous |readLock| is released and the
154          * before current |writeLock| is acquired, the |mService| will be updated to null. Then it
155          * won't match |service|.
156          *
157          * When CarWatchdogService is restarting, it will issue an registerService call. When the
158          * registerService is executed between after the previous |readLock| is released and before
159          * the current |writeLock| is acquired, the |mService| will be overwritten. This will lead
160          * to unregistering the new CarWatchdogService.
161          *
162          * To avoid this race condition, check mService before proceeding with unregistering the
163          * CarWatchdogService.
164          */
165         if (mService == service) {
166             unregisterServiceLocked();
167         }
168     }
169     return status;
170 }
171 
unregisterServiceLocked()172 void WatchdogServiceHelper::unregisterServiceLocked() {
173     if (mService == nullptr) return;
174     sp<IBinder> binder = BnCarWatchdogServiceForSystem::asBinder(mService);
175     binder->unlinkToDeath(this);
176     mService.clear();
177     mWatchdogProcessService->unregisterCarWatchdogService(binder);
178 }
179 
getPackageInfosForUids(const std::vector<int32_t> & uids,const std::vector<std::string> & vendorPackagePrefixes,std::vector<PackageInfo> * packageInfos)180 Status WatchdogServiceHelper::getPackageInfosForUids(
181         const std::vector<int32_t>& uids, const std::vector<std::string>& vendorPackagePrefixes,
182         std::vector<PackageInfo>* packageInfos) {
183     sp<ICarWatchdogServiceForSystem> service;
184     if (std::shared_lock readLock(mRWMutex); mService == nullptr) {
185         return fromExceptionCode(Status::EX_ILLEGAL_STATE, "Watchdog service is not initialized");
186     } else {
187         service = mService;
188     }
189     /*
190      * The expected number of vendor package prefixes is in the order of 10s. Thus the overhead of
191      * forwarding these in each get call is very low.
192      */
193     return service->getPackageInfosForUids(uids, vendorPackagePrefixes, packageInfos);
194 }
195 
latestIoOveruseStats(const std::vector<PackageIoOveruseStats> & packageIoOveruseStats)196 Status WatchdogServiceHelper::latestIoOveruseStats(
197         const std::vector<PackageIoOveruseStats>& packageIoOveruseStats) {
198     sp<ICarWatchdogServiceForSystem> service;
199     if (std::shared_lock readLock(mRWMutex); mService == nullptr) {
200         return fromExceptionCode(Status::EX_ILLEGAL_STATE, "Watchdog service is not initialized");
201     } else {
202         service = mService;
203     }
204     return service->latestIoOveruseStats(packageIoOveruseStats);
205 }
206 
resetResourceOveruseStats(const std::vector<std::string> & packageNames)207 Status WatchdogServiceHelper::resetResourceOveruseStats(
208         const std::vector<std::string>& packageNames) {
209     sp<ICarWatchdogServiceForSystem> service;
210     if (std::shared_lock readLock(mRWMutex); mService == nullptr) {
211         return fromExceptionCode(Status::EX_ILLEGAL_STATE, "Watchdog service is not initialized");
212     } else {
213         service = mService;
214     }
215     return service->resetResourceOveruseStats(packageNames);
216 }
217 
getTodayIoUsageStats(std::vector<UserPackageIoUsageStats> * userPackageIoUsageStats)218 Status WatchdogServiceHelper::getTodayIoUsageStats(
219         std::vector<UserPackageIoUsageStats>* userPackageIoUsageStats) {
220     sp<ICarWatchdogServiceForSystem> service;
221     if (std::shared_lock readLock(mRWMutex); mService == nullptr) {
222         return fromExceptionCode(Status::EX_ILLEGAL_STATE, "Watchdog service is not initialized");
223     } else {
224         service = mService;
225     }
226     return service->getTodayIoUsageStats(userPackageIoUsageStats);
227 }
228 
229 }  // namespace watchdog
230 }  // namespace automotive
231 }  // namespace android
232