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 "WatchdogInternalHandler.h"
20
21 #include "WatchdogBinderMediator.h"
22
23 #include <android/automotive/watchdog/internal/BootPhase.h>
24 #include <android/automotive/watchdog/internal/GarageMode.h>
25 #include <android/automotive/watchdog/internal/PowerCycle.h>
26 #include <android/automotive/watchdog/internal/UserState.h>
27 #include <binder/IPCThreadState.h>
28 #include <private/android_filesystem_config.h>
29
30 namespace android {
31 namespace automotive {
32 namespace watchdog {
33
34 namespace aawi = ::android::automotive::watchdog::internal;
35
36 using aawi::ComponentType;
37 using aawi::GarageMode;
38 using aawi::ICarWatchdogServiceForSystem;
39 using aawi::PowerCycle;
40 using aawi::ResourceOveruseConfiguration;
41 using ::android::sp;
42 using ::android::String16;
43 using ::android::binder::Status;
44
45 namespace {
46
47 constexpr const char* kNullCarWatchdogServiceError =
48 "Must provide a non-null car watchdog service instance";
49 constexpr const char* kNullCarWatchdogMonitorError =
50 "Must provide a non-null car watchdog monitor instance";
51
checkSystemUser()52 Status checkSystemUser() {
53 if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
54 return Status::fromExceptionCode(Status::EX_SECURITY,
55 "Calling process does not have proper privilege");
56 }
57 return Status::ok();
58 }
59
fromExceptionCode(int32_t exceptionCode,std::string message)60 Status fromExceptionCode(int32_t exceptionCode, std::string message) {
61 ALOGW("%s", message.c_str());
62 return Status::fromExceptionCode(exceptionCode, message.c_str());
63 }
64
65 } // namespace
66
dump(int fd,const Vector<String16> & args)67 status_t WatchdogInternalHandler::dump(int fd, const Vector<String16>& args) {
68 return mBinderMediator->dump(fd, args);
69 }
70
checkAndRegisterIoOveruseMonitor()71 void WatchdogInternalHandler::checkAndRegisterIoOveruseMonitor() {
72 if (mIoOveruseMonitor->isInitialized()) {
73 return;
74 }
75 if (const auto result = mWatchdogPerfService->registerDataProcessor(mIoOveruseMonitor);
76 !result.ok()) {
77 ALOGE("Failed to register I/O overuse monitor to watchdog performance service: %s",
78 result.error().message().c_str());
79 }
80 return;
81 }
82
registerCarWatchdogService(const sp<ICarWatchdogServiceForSystem> & service)83 Status WatchdogInternalHandler::registerCarWatchdogService(
84 const sp<ICarWatchdogServiceForSystem>& service) {
85 Status status = checkSystemUser();
86 if (!status.isOk()) {
87 return status;
88 }
89 if (service == nullptr) {
90 return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, kNullCarWatchdogServiceError);
91 }
92 /*
93 * I/O overuse monitor reads from system, vendor, and data partitions during initialization.
94 * When CarService is running these partitions are available to read, thus register the I/O
95 * overuse monitor on processing the request to register CarService.
96 */
97 checkAndRegisterIoOveruseMonitor();
98 return mWatchdogServiceHelper->registerService(service);
99 }
100
unregisterCarWatchdogService(const sp<ICarWatchdogServiceForSystem> & service)101 Status WatchdogInternalHandler::unregisterCarWatchdogService(
102 const sp<ICarWatchdogServiceForSystem>& service) {
103 Status status = checkSystemUser();
104 if (!status.isOk()) {
105 return status;
106 }
107 if (service == nullptr) {
108 return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, kNullCarWatchdogServiceError);
109 }
110 return mWatchdogServiceHelper->unregisterService(service);
111 }
112
registerMonitor(const sp<aawi::ICarWatchdogMonitor> & monitor)113 Status WatchdogInternalHandler::registerMonitor(const sp<aawi::ICarWatchdogMonitor>& monitor) {
114 Status status = checkSystemUser();
115 if (!status.isOk()) {
116 return status;
117 }
118 if (monitor == nullptr) {
119 return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, kNullCarWatchdogMonitorError);
120 }
121 return mWatchdogProcessService->registerMonitor(monitor);
122 }
123
unregisterMonitor(const sp<aawi::ICarWatchdogMonitor> & monitor)124 Status WatchdogInternalHandler::unregisterMonitor(const sp<aawi::ICarWatchdogMonitor>& monitor) {
125 Status status = checkSystemUser();
126 if (!status.isOk()) {
127 return status;
128 }
129 if (monitor == nullptr) {
130 return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, kNullCarWatchdogMonitorError);
131 }
132 return mWatchdogProcessService->unregisterMonitor(monitor);
133 }
134
tellCarWatchdogServiceAlive(const android::sp<ICarWatchdogServiceForSystem> & service,const std::vector<int32_t> & clientsNotResponding,int32_t sessionId)135 Status WatchdogInternalHandler::tellCarWatchdogServiceAlive(
136 const android::sp<ICarWatchdogServiceForSystem>& service,
137 const std::vector<int32_t>& clientsNotResponding, int32_t sessionId) {
138 Status status = checkSystemUser();
139 if (!status.isOk()) {
140 return status;
141 }
142 if (service == nullptr) {
143 return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, kNullCarWatchdogServiceError);
144 }
145 return mWatchdogProcessService->tellCarWatchdogServiceAlive(service, clientsNotResponding,
146 sessionId);
147 }
tellDumpFinished(const android::sp<aawi::ICarWatchdogMonitor> & monitor,int32_t pid)148 Status WatchdogInternalHandler::tellDumpFinished(
149 const android::sp<aawi::ICarWatchdogMonitor>& monitor, int32_t pid) {
150 Status status = checkSystemUser();
151 if (!status.isOk()) {
152 return status;
153 }
154 if (monitor == nullptr) {
155 return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, kNullCarWatchdogMonitorError);
156 }
157 return mWatchdogProcessService->tellDumpFinished(monitor, pid);
158 }
159
notifySystemStateChange(aawi::StateType type,int32_t arg1,int32_t arg2)160 Status WatchdogInternalHandler::notifySystemStateChange(aawi::StateType type, int32_t arg1,
161 int32_t arg2) {
162 Status status = checkSystemUser();
163 if (!status.isOk()) {
164 return status;
165 }
166 switch (type) {
167 case aawi::StateType::POWER_CYCLE: {
168 PowerCycle powerCycle = static_cast<PowerCycle>(static_cast<uint32_t>(arg1));
169 if (powerCycle >= PowerCycle::NUM_POWER_CYLES) {
170 return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
171 StringPrintf("Invalid power cycle %d", powerCycle));
172 }
173 return handlePowerCycleChange(powerCycle);
174 }
175 case aawi::StateType::GARAGE_MODE: {
176 GarageMode garageMode = static_cast<GarageMode>(static_cast<uint32_t>(arg1));
177 mWatchdogPerfService->setSystemState(garageMode == GarageMode::GARAGE_MODE_OFF
178 ? SystemState::NORMAL_MODE
179 : SystemState::GARAGE_MODE);
180 return Status::ok();
181 }
182 case aawi::StateType::USER_STATE: {
183 userid_t userId = static_cast<userid_t>(arg1);
184 aawi::UserState userState = static_cast<aawi::UserState>(static_cast<uint32_t>(arg2));
185 if (userState >= aawi::UserState::NUM_USER_STATES) {
186 return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
187 StringPrintf("Invalid user state %d", userState));
188 }
189 return handleUserStateChange(userId, userState);
190 }
191 case aawi::StateType::BOOT_PHASE: {
192 aawi::BootPhase phase = static_cast<aawi::BootPhase>(static_cast<uint32_t>(arg1));
193 if (phase >= aawi::BootPhase::BOOT_COMPLETED) {
194 if (const auto result = mWatchdogPerfService->onBootFinished(); !result.ok()) {
195 return fromExceptionCode(result.error().code(), result.error().message());
196 }
197 }
198 return Status::ok();
199 }
200 }
201 return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
202 StringPrintf("Invalid state change type %d", type));
203 }
204
handlePowerCycleChange(PowerCycle powerCycle)205 Status WatchdogInternalHandler::handlePowerCycleChange(PowerCycle powerCycle) {
206 switch (powerCycle) {
207 case PowerCycle::POWER_CYCLE_SHUTDOWN_PREPARE:
208 ALOGI("Received SHUTDOWN_PREPARE power cycle");
209 mWatchdogProcessService->setEnabled(/*isEnabled=*/false);
210 // TODO(b/189508862): Upload resource overuse stats on shutdown prepare.
211 break;
212 case PowerCycle::POWER_CYCLE_SHUTDOWN_ENTER:
213 ALOGI("Received SHUTDOWN_ENTER power cycle");
214 mWatchdogProcessService->setEnabled(/*isEnabled=*/false);
215 break;
216 case PowerCycle::POWER_CYCLE_RESUME:
217 ALOGI("Received RESUME power cycle");
218 mWatchdogProcessService->setEnabled(/*isEnabled=*/true);
219 break;
220 default:
221 ALOGW("Unsupported power cycle: %d", powerCycle);
222 return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
223 "Unsupported power cycle");
224 }
225 return Status::ok();
226 }
227
handleUserStateChange(userid_t userId,aawi::UserState userState)228 Status WatchdogInternalHandler::handleUserStateChange(userid_t userId, aawi::UserState userState) {
229 std::string stateDesc;
230 switch (userState) {
231 case aawi::UserState::USER_STATE_STARTED:
232 stateDesc = "started";
233 mWatchdogProcessService->notifyUserStateChange(userId, /*isStarted=*/true);
234 break;
235 case aawi::UserState::USER_STATE_STOPPED:
236 stateDesc = "stopped";
237 mWatchdogProcessService->notifyUserStateChange(userId, /*isStarted=*/false);
238 break;
239 case aawi::UserState::USER_STATE_REMOVED:
240 stateDesc = "removed";
241 mIoOveruseMonitor->removeStatsForUser(userId);
242 break;
243 default:
244 ALOGW("Unsupported user state: %d", userState);
245 return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Unsupported user state");
246 }
247 ALOGI("Received user state change: user(%" PRId32 ") is %s", userId, stateDesc.c_str());
248 return Status::ok();
249 }
250
updateResourceOveruseConfigurations(const std::vector<ResourceOveruseConfiguration> & configs)251 Status WatchdogInternalHandler::updateResourceOveruseConfigurations(
252 const std::vector<ResourceOveruseConfiguration>& configs) {
253 Status status = checkSystemUser();
254 if (!status.isOk()) {
255 return status;
256 }
257 // Maybe retry registring I/O overuse monitor if failed to initialize previously.
258 checkAndRegisterIoOveruseMonitor();
259 if (const auto result = mIoOveruseMonitor->updateResourceOveruseConfigurations(configs);
260 !result.ok()) {
261 return fromExceptionCode(result.error().code(), result.error().message());
262 }
263 return Status::ok();
264 }
265
getResourceOveruseConfigurations(std::vector<ResourceOveruseConfiguration> * configs)266 Status WatchdogInternalHandler::getResourceOveruseConfigurations(
267 std::vector<ResourceOveruseConfiguration>* configs) {
268 Status status = checkSystemUser();
269 if (!status.isOk()) {
270 return status;
271 }
272 // Maybe retry registring I/O overuse monitor if failed to initialize previously.
273 checkAndRegisterIoOveruseMonitor();
274 if (const auto result = mIoOveruseMonitor->getResourceOveruseConfigurations(configs);
275 !result.ok()) {
276 return fromExceptionCode(result.error().code(), result.error().message());
277 }
278 return Status::ok();
279 }
280
controlProcessHealthCheck(bool disable)281 Status WatchdogInternalHandler::controlProcessHealthCheck(bool disable) {
282 Status status = checkSystemUser();
283 if (!status.isOk()) {
284 return status;
285 }
286 mWatchdogProcessService->setEnabled(!disable);
287 return Status::ok();
288 }
289
290 } // namespace watchdog
291 } // namespace automotive
292 } // namespace android
293