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 "WatchdogBinderMediator.h"
20
21 #include <android-base/file.h>
22 #include <android-base/parseint.h>
23 #include <android-base/stringprintf.h>
24 #include <android-base/strings.h>
25 #include <binder/IServiceManager.h>
26 #include <log/log.h>
27
28 namespace android {
29 namespace automotive {
30 namespace watchdog {
31
32 using ::android::defaultServiceManager;
33 using ::android::IBinder;
34 using ::android::sp;
35 using ::android::String16;
36 using ::android::base::Error;
37 using ::android::base::Join;
38 using ::android::base::ParseUint;
39 using ::android::base::Result;
40 using ::android::base::Split;
41 using ::android::base::StringAppendF;
42 using ::android::base::StringPrintf;
43 using ::android::base::WriteStringToFd;
44 using ::android::binder::Status;
45
46 using AddServiceFunction =
47 std::function<android::base::Result<void>(const char*,
48 const android::sp<android::IBinder>&)>;
49
50 namespace {
51
52 constexpr const char* kHelpFlag = "--help";
53 constexpr const char* kHelpShortFlag = "-h";
54 constexpr const char* kHelpText =
55 "CarWatchdog daemon dumpsys help page:\n"
56 "Format: dumpsys android.automotive.watchdog.ICarWatchdog/default [options]\n\n"
57 "%s or %s: Displays this help text.\n"
58 "When no options are specified, carwatchdog report is generated.\n";
59 constexpr const char* kCarWatchdogServerInterface =
60 "android.automotive.watchdog.ICarWatchdog/default";
61 constexpr const char* kCarWatchdogInternalServerInterface =
62 "android.automotive.watchdog.internal.ICarWatchdog/default";
63 constexpr const char* kNullCarWatchdogClientError =
64 "Must provide a non-null car watchdog client instance";
65
fromExceptionCode(const int32_t exceptionCode,const std::string & message)66 Status fromExceptionCode(const int32_t exceptionCode, const std::string& message) {
67 ALOGW("%s", message.c_str());
68 return Status::fromExceptionCode(exceptionCode, message.c_str());
69 }
70
addToServiceManager(const char * serviceName,sp<IBinder> service)71 Result<void> addToServiceManager(const char* serviceName, sp<IBinder> service) {
72 status_t status = defaultServiceManager()->addService(String16(serviceName), service);
73 if (status != OK) {
74 return Error(status) << "Failed to add '" << serviceName << "' to ServiceManager";
75 }
76 return {};
77 }
78
79 } // namespace
80
WatchdogBinderMediator(const android::sp<WatchdogProcessServiceInterface> & watchdogProcessService,const android::sp<WatchdogPerfServiceInterface> & watchdogPerfService,const android::sp<WatchdogServiceHelperInterface> & watchdogServiceHelper,const AddServiceFunction & addServiceHandler)81 WatchdogBinderMediator::WatchdogBinderMediator(
82 const android::sp<WatchdogProcessServiceInterface>& watchdogProcessService,
83 const android::sp<WatchdogPerfServiceInterface>& watchdogPerfService,
84 const android::sp<WatchdogServiceHelperInterface>& watchdogServiceHelper,
85 const AddServiceFunction& addServiceHandler) :
86 mWatchdogProcessService(watchdogProcessService),
87 mWatchdogPerfService(watchdogPerfService),
88 mWatchdogServiceHelper(watchdogServiceHelper),
89 mAddServiceHandler(addServiceHandler) {
90 if (mAddServiceHandler == nullptr) {
91 mAddServiceHandler = &addToServiceManager;
92 }
93 if (watchdogServiceHelper != nullptr) {
94 mIoOveruseMonitor = sp<IoOveruseMonitor>::make(watchdogServiceHelper);
95 }
96 }
97
init()98 Result<void> WatchdogBinderMediator::init() {
99 if (mWatchdogProcessService == nullptr || mWatchdogPerfService == nullptr ||
100 mWatchdogServiceHelper == nullptr || mIoOveruseMonitor == nullptr) {
101 std::string serviceList;
102 if (mWatchdogProcessService == nullptr) {
103 StringAppendF(&serviceList, "%s%s", (!serviceList.empty() ? ", " : ""),
104 "Watchdog process service");
105 }
106 if (mWatchdogPerfService == nullptr) {
107 StringAppendF(&serviceList, "%s%s", (!serviceList.empty() ? ", " : ""),
108 "Watchdog performance service");
109 }
110 if (mWatchdogServiceHelper == nullptr) {
111 StringAppendF(&serviceList, "%s%s", (!serviceList.empty() ? ", " : ""),
112 "Watchdog service helper");
113 }
114 if (mIoOveruseMonitor == nullptr) {
115 StringAppendF(&serviceList, "%s%s", (!serviceList.empty() ? ", " : ""),
116 "I/O overuse monitor service");
117 }
118 return Error(INVALID_OPERATION)
119 << serviceList << " must be initialized with non-null instance";
120 }
121 mWatchdogInternalHandler =
122 sp<WatchdogInternalHandler>::make(sp<WatchdogBinderMediator>::fromExisting(this),
123 mWatchdogServiceHelper, mWatchdogProcessService,
124 mWatchdogPerfService, mIoOveruseMonitor);
125 if (const auto result =
126 mAddServiceHandler(kCarWatchdogServerInterface, sp<IBinder>::fromExisting(this));
127 !result.ok()) {
128 return result;
129 }
130 if (const auto result =
131 mAddServiceHandler(kCarWatchdogInternalServerInterface, mWatchdogInternalHandler);
132 !result.ok()) {
133 return result;
134 }
135 return {};
136 }
137
dump(int fd,const Vector<String16> & args)138 status_t WatchdogBinderMediator::dump(int fd, const Vector<String16>& args) {
139 int numArgs = args.size();
140 if (numArgs == 0) {
141 return dumpServices(fd, args);
142 }
143 if (numArgs == 1 && (args[0] == String16(kHelpFlag) || args[0] == String16(kHelpShortFlag))) {
144 return dumpHelpText(fd, "");
145 }
146 if (args[0] == String16(kStartCustomCollectionFlag) ||
147 args[0] == String16(kEndCustomCollectionFlag)) {
148 if (auto result = mWatchdogPerfService->onCustomCollection(fd, args); !result.ok()) {
149 std::string mode = args[0] == String16(kStartCustomCollectionFlag) ? "start" : "end";
150 std::string errorMsg = StringPrintf("Failed to %s custom I/O perf collection: %s",
151 mode.c_str(), result.error().message().c_str());
152 if (result.error().code() == BAD_VALUE) {
153 dumpHelpText(fd, errorMsg);
154 } else {
155 ALOGW("%s", errorMsg.c_str());
156 }
157 return result.error().code();
158 }
159 return OK;
160 }
161 if (numArgs == 2 && args[0] == String16(kResetResourceOveruseStatsFlag)) {
162 std::string value = std::string(String8(args[1]));
163 std::vector<std::string> packageNames = Split(value, ",");
164 if (value.empty() || packageNames.empty()) {
165 dumpHelpText(fd,
166 StringPrintf("Must provide valid package names: [%s]\n", value.c_str()));
167 return BAD_VALUE;
168 }
169 if (auto result = mIoOveruseMonitor->resetIoOveruseStats(packageNames); !result.ok()) {
170 ALOGW("Failed to reset stats for packages: [%s]", value.c_str());
171 return FAILED_TRANSACTION;
172 }
173 return OK;
174 }
175 dumpHelpText(fd,
176 StringPrintf("Invalid carwatchdog dumpsys options: [%s]\n",
177 Join(args, " ").c_str()));
178 return dumpServices(fd, args);
179 }
180
dumpServices(int fd,const Vector<String16> & args)181 status_t WatchdogBinderMediator::dumpServices(int fd, const Vector<String16>& args) {
182 if (auto result = mWatchdogProcessService->dump(fd, args); !result.ok()) {
183 ALOGW("Failed to dump carwatchdog process service: %s", result.error().message().c_str());
184 return result.error().code();
185 }
186 if (auto result = mWatchdogPerfService->onDump(fd); !result.ok()) {
187 ALOGW("Failed to dump carwatchdog perf service: %s", result.error().message().c_str());
188 return result.error().code();
189 }
190 return OK;
191 }
192
dumpHelpText(const int fd,const std::string & errorMsg)193 status_t WatchdogBinderMediator::dumpHelpText(const int fd, const std::string& errorMsg) {
194 if (!errorMsg.empty()) {
195 ALOGW("Error: %s", errorMsg.c_str());
196 if (!WriteStringToFd(StringPrintf("Error: %s\n\n", errorMsg.c_str()), fd)) {
197 ALOGW("Failed to write error message to fd");
198 return FAILED_TRANSACTION;
199 }
200 }
201 if (!WriteStringToFd(StringPrintf(kHelpText, kHelpFlag, kHelpShortFlag), fd) ||
202 !mWatchdogPerfService->dumpHelpText(fd) || !mIoOveruseMonitor->dumpHelpText(fd)) {
203 ALOGW("Failed to write help text to fd");
204 return FAILED_TRANSACTION;
205 }
206 return OK;
207 }
208
registerClient(const sp<ICarWatchdogClient> & client,TimeoutLength timeout)209 Status WatchdogBinderMediator::registerClient(const sp<ICarWatchdogClient>& client,
210 TimeoutLength timeout) {
211 if (client == nullptr) {
212 return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, kNullCarWatchdogClientError);
213 }
214 return mWatchdogProcessService->registerClient(client, timeout);
215 }
216
unregisterClient(const sp<ICarWatchdogClient> & client)217 Status WatchdogBinderMediator::unregisterClient(const sp<ICarWatchdogClient>& client) {
218 if (client == nullptr) {
219 return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, kNullCarWatchdogClientError);
220 }
221 return mWatchdogProcessService->unregisterClient(client);
222 }
223
tellClientAlive(const sp<ICarWatchdogClient> & client,int32_t sessionId)224 Status WatchdogBinderMediator::tellClientAlive(const sp<ICarWatchdogClient>& client,
225 int32_t sessionId) {
226 if (client == nullptr) {
227 return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, kNullCarWatchdogClientError);
228 }
229 return mWatchdogProcessService->tellClientAlive(client, sessionId);
230 }
231
addResourceOveruseListener(const std::vector<ResourceType> & resourceTypes,const sp<IResourceOveruseListener> & listener)232 Status WatchdogBinderMediator::addResourceOveruseListener(
233 const std::vector<ResourceType>& resourceTypes,
234 const sp<IResourceOveruseListener>& listener) {
235 if (listener == nullptr) {
236 return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
237 "Must provide a non-null resource overuse listener");
238 }
239 if (resourceTypes.size() != 1 || resourceTypes[0] != ResourceType::IO) {
240 return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
241 "Must provide exactly one I/O resource type");
242 }
243 /*
244 * When more resource types are added, implement a new module to manage listeners for all
245 * resources.
246 */
247 if (const auto result = mIoOveruseMonitor->addIoOveruseListener(listener); !result.ok()) {
248 return fromExceptionCode(result.error().code(),
249 StringPrintf("Failed to register resource overuse listener: %s ",
250 result.error().message().c_str()));
251 }
252 return Status::ok();
253 }
254
removeResourceOveruseListener(const sp<IResourceOveruseListener> & listener)255 Status WatchdogBinderMediator::removeResourceOveruseListener(
256 const sp<IResourceOveruseListener>& listener) {
257 if (listener == nullptr) {
258 return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
259 "Must provide a non-null resource overuse listener");
260 }
261 if (const auto result = mIoOveruseMonitor->removeIoOveruseListener(listener); !result.ok()) {
262 return fromExceptionCode(result.error().code(),
263 StringPrintf("Failed to unregister resource overuse listener: %s",
264 result.error().message().c_str()));
265 }
266 return Status::ok();
267 }
268
getResourceOveruseStats(const std::vector<ResourceType> & resourceTypes,std::vector<ResourceOveruseStats> * resourceOveruseStats)269 Status WatchdogBinderMediator::getResourceOveruseStats(
270 const std::vector<ResourceType>& resourceTypes,
271 std::vector<ResourceOveruseStats>* resourceOveruseStats) {
272 if (resourceOveruseStats == nullptr) {
273 return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
274 "Must provide a non-null resource overuse stats parcelable");
275 }
276 if (resourceTypes.size() != 1 || resourceTypes[0] != ResourceType::IO) {
277 return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
278 "Must provide exactly one I/O resource type");
279 }
280 IoOveruseStats ioOveruseStats;
281 if (const auto result = mIoOveruseMonitor->getIoOveruseStats(&ioOveruseStats); !result.ok()) {
282 return fromExceptionCode(result.error().code(),
283 StringPrintf("Failed to get resource overuse stats: %s",
284 result.error().message().c_str()));
285 }
286 ResourceOveruseStats stats;
287 stats.set<ResourceOveruseStats::ioOveruseStats>(std::move(ioOveruseStats));
288 resourceOveruseStats->emplace_back(std::move(stats));
289 return Status::ok();
290 }
291
registerMediator(const sp<ICarWatchdogClient> &)292 Status WatchdogBinderMediator::registerMediator(const sp<ICarWatchdogClient>& /*mediator*/) {
293 return fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION,
294 "Deprecated method registerMediator");
295 }
296
unregisterMediator(const sp<ICarWatchdogClient> &)297 Status WatchdogBinderMediator::unregisterMediator(const sp<ICarWatchdogClient>& /*mediator*/) {
298 return fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION,
299 "Deprecated method unregisterMediator");
300 }
301
registerMonitor(const sp<ICarWatchdogMonitor> &)302 Status WatchdogBinderMediator::registerMonitor(const sp<ICarWatchdogMonitor>& /*monitor*/) {
303 return fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION, "Deprecated method registerMonitor");
304 }
305
unregisterMonitor(const sp<ICarWatchdogMonitor> &)306 Status WatchdogBinderMediator::unregisterMonitor(const sp<ICarWatchdogMonitor>& /*monitor*/) {
307 return fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION,
308 "Deprecated method unregisterMonitor");
309 }
310
tellMediatorAlive(const sp<ICarWatchdogClient> &,const std::vector<int32_t> &,int32_t)311 Status WatchdogBinderMediator::tellMediatorAlive(
312 const sp<ICarWatchdogClient>& /*mediator*/,
313 const std::vector<int32_t>& /*clientsNotResponding*/, int32_t /*sessionId*/) {
314 return fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION,
315 "Deprecated method tellMediatorAlive");
316 }
317
tellDumpFinished(const sp<ICarWatchdogMonitor> &,int32_t)318 Status WatchdogBinderMediator::tellDumpFinished(const sp<ICarWatchdogMonitor>& /*monitor*/,
319 int32_t /*pid*/) {
320 return fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION,
321 "Deprecated method tellDumpFinished");
322 }
323
notifySystemStateChange(StateType,int32_t,int32_t)324 Status WatchdogBinderMediator::notifySystemStateChange(StateType /*type*/, int32_t /*arg1*/,
325 int32_t /*arg2*/) {
326 return fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION,
327 "Deprecated method notifySystemStateChange");
328 }
329
330 } // namespace watchdog
331 } // namespace automotive
332 } // namespace android
333