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