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