332 lines
13 KiB
C++
332 lines
13 KiB
C++
/**
|
|
* Copyright (c) 2020, The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#define LOG_TAG "carwatchdogd"
|
|
|
|
#include "WatchdogInternalHandler.h"
|
|
|
|
#include "UidProcStatsCollector.h"
|
|
#include "WatchdogBinderMediator.h"
|
|
|
|
#include <android/automotive/watchdog/internal/BootPhase.h>
|
|
#include <android/automotive/watchdog/internal/GarageMode.h>
|
|
#include <android/automotive/watchdog/internal/PowerCycle.h>
|
|
#include <android/automotive/watchdog/internal/UserState.h>
|
|
#include <binder/IPCThreadState.h>
|
|
#include <private/android_filesystem_config.h>
|
|
|
|
namespace android {
|
|
namespace automotive {
|
|
namespace watchdog {
|
|
|
|
namespace aawi = ::android::automotive::watchdog::internal;
|
|
|
|
using aawi::ComponentType;
|
|
using aawi::GarageMode;
|
|
using aawi::ICarWatchdogServiceForSystem;
|
|
using aawi::PowerCycle;
|
|
using aawi::ProcessIdentifier;
|
|
using aawi::ResourceOveruseConfiguration;
|
|
using aawi::ThreadPolicyWithPriority;
|
|
using ::android::sp;
|
|
using ::android::String16;
|
|
using ::android::binder::Status;
|
|
|
|
namespace {
|
|
|
|
constexpr const char* kNullCarWatchdogServiceError =
|
|
"Must provide a non-null car watchdog service instance";
|
|
constexpr const char* kNullCarWatchdogMonitorError =
|
|
"Must provide a non-null car watchdog monitor instance";
|
|
|
|
Status checkSystemUser() {
|
|
if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
|
|
return Status::fromExceptionCode(Status::EX_SECURITY,
|
|
"Calling process does not have proper privilege");
|
|
}
|
|
return Status::ok();
|
|
}
|
|
|
|
Status fromExceptionCode(int32_t exceptionCode, std::string message) {
|
|
ALOGW("%s", message.c_str());
|
|
return Status::fromExceptionCode(exceptionCode, message.c_str());
|
|
}
|
|
|
|
} // namespace
|
|
|
|
status_t WatchdogInternalHandler::dump(int fd, const Vector<String16>& args) {
|
|
return mWatchdogBinderMediator->dump(fd, args);
|
|
}
|
|
|
|
void WatchdogInternalHandler::checkAndRegisterIoOveruseMonitor() {
|
|
if (mIoOveruseMonitor->isInitialized()) {
|
|
return;
|
|
}
|
|
if (const auto result = mWatchdogPerfService->registerDataProcessor(mIoOveruseMonitor);
|
|
!result.ok()) {
|
|
ALOGE("Failed to register I/O overuse monitor to watchdog performance service: %s",
|
|
result.error().message().c_str());
|
|
}
|
|
return;
|
|
}
|
|
|
|
Status WatchdogInternalHandler::registerCarWatchdogService(
|
|
const sp<ICarWatchdogServiceForSystem>& service) {
|
|
Status status = checkSystemUser();
|
|
if (!status.isOk()) {
|
|
return status;
|
|
}
|
|
if (service == nullptr) {
|
|
return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, kNullCarWatchdogServiceError);
|
|
}
|
|
/*
|
|
* I/O overuse monitor reads from system, vendor, and data partitions during initialization.
|
|
* When CarService is running these partitions are available to read, thus register the I/O
|
|
* overuse monitor on processing the request to register CarService.
|
|
*/
|
|
checkAndRegisterIoOveruseMonitor();
|
|
return mWatchdogServiceHelper->registerService(service);
|
|
}
|
|
|
|
Status WatchdogInternalHandler::unregisterCarWatchdogService(
|
|
const sp<ICarWatchdogServiceForSystem>& service) {
|
|
Status status = checkSystemUser();
|
|
if (!status.isOk()) {
|
|
return status;
|
|
}
|
|
if (service == nullptr) {
|
|
return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, kNullCarWatchdogServiceError);
|
|
}
|
|
return mWatchdogServiceHelper->unregisterService(service);
|
|
}
|
|
|
|
Status WatchdogInternalHandler::registerMonitor(const sp<aawi::ICarWatchdogMonitor>& monitor) {
|
|
Status status = checkSystemUser();
|
|
if (!status.isOk()) {
|
|
return status;
|
|
}
|
|
if (monitor == nullptr) {
|
|
return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, kNullCarWatchdogMonitorError);
|
|
}
|
|
return mWatchdogProcessService->registerMonitor(monitor);
|
|
}
|
|
|
|
Status WatchdogInternalHandler::unregisterMonitor(const sp<aawi::ICarWatchdogMonitor>& monitor) {
|
|
Status status = checkSystemUser();
|
|
if (!status.isOk()) {
|
|
return status;
|
|
}
|
|
if (monitor == nullptr) {
|
|
return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, kNullCarWatchdogMonitorError);
|
|
}
|
|
return mWatchdogProcessService->unregisterMonitor(monitor);
|
|
}
|
|
|
|
Status WatchdogInternalHandler::tellCarWatchdogServiceAlive(
|
|
const android::sp<ICarWatchdogServiceForSystem>& service,
|
|
const std::vector<ProcessIdentifier>& clientsNotResponding, int32_t sessionId) {
|
|
Status status = checkSystemUser();
|
|
if (!status.isOk()) {
|
|
return status;
|
|
}
|
|
if (service == nullptr) {
|
|
return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, kNullCarWatchdogServiceError);
|
|
}
|
|
return mWatchdogProcessService->tellCarWatchdogServiceAlive(service, clientsNotResponding,
|
|
sessionId);
|
|
}
|
|
Status WatchdogInternalHandler::tellDumpFinished(
|
|
const android::sp<aawi::ICarWatchdogMonitor>& monitor,
|
|
const ProcessIdentifier& processIdentifier) {
|
|
Status status = checkSystemUser();
|
|
if (!status.isOk()) {
|
|
return status;
|
|
}
|
|
if (monitor == nullptr) {
|
|
return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, kNullCarWatchdogMonitorError);
|
|
}
|
|
return mWatchdogProcessService->tellDumpFinished(monitor, processIdentifier);
|
|
}
|
|
|
|
Status WatchdogInternalHandler::notifySystemStateChange(aawi::StateType type, int32_t arg1,
|
|
int32_t arg2) {
|
|
Status status = checkSystemUser();
|
|
if (!status.isOk()) {
|
|
return status;
|
|
}
|
|
switch (type) {
|
|
case aawi::StateType::POWER_CYCLE: {
|
|
PowerCycle powerCycle = static_cast<PowerCycle>(static_cast<uint32_t>(arg1));
|
|
return handlePowerCycleChange(powerCycle);
|
|
}
|
|
case aawi::StateType::GARAGE_MODE: {
|
|
GarageMode garageMode = static_cast<GarageMode>(static_cast<uint32_t>(arg1));
|
|
mWatchdogPerfService->setSystemState(garageMode == GarageMode::GARAGE_MODE_OFF
|
|
? SystemState::NORMAL_MODE
|
|
: SystemState::GARAGE_MODE);
|
|
return Status::ok();
|
|
}
|
|
case aawi::StateType::USER_STATE: {
|
|
userid_t userId = static_cast<userid_t>(arg1);
|
|
aawi::UserState userState = static_cast<aawi::UserState>(static_cast<uint32_t>(arg2));
|
|
return handleUserStateChange(userId, userState);
|
|
}
|
|
case aawi::StateType::BOOT_PHASE: {
|
|
aawi::BootPhase phase = static_cast<aawi::BootPhase>(static_cast<uint32_t>(arg1));
|
|
if (phase >= aawi::BootPhase::BOOT_COMPLETED) {
|
|
if (const auto result = mWatchdogPerfService->onBootFinished(); !result.ok()) {
|
|
return fromExceptionCode(result.error().code(), result.error().message());
|
|
}
|
|
}
|
|
return Status::ok();
|
|
}
|
|
}
|
|
return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
|
|
StringPrintf("Invalid state change type %d", type));
|
|
}
|
|
|
|
Status WatchdogInternalHandler::handlePowerCycleChange(PowerCycle powerCycle) {
|
|
switch (powerCycle) {
|
|
case PowerCycle::POWER_CYCLE_SHUTDOWN_PREPARE:
|
|
ALOGI("Received SHUTDOWN_PREPARE power cycle");
|
|
mWatchdogProcessService->setEnabled(/*isEnabled=*/false);
|
|
// TODO(b/189508862): Upload resource overuse stats on shutdown prepare.
|
|
break;
|
|
case PowerCycle::POWER_CYCLE_SHUTDOWN_ENTER:
|
|
ALOGI("Received SHUTDOWN_ENTER power cycle");
|
|
mWatchdogProcessService->setEnabled(/*isEnabled=*/false);
|
|
mWatchdogPerfService->onShutdownEnter();
|
|
break;
|
|
case PowerCycle::POWER_CYCLE_SUSPEND_EXIT:
|
|
ALOGI("Received SUSPEND_EXIT power cycle");
|
|
mWatchdogPerfService->onSuspendExit();
|
|
break;
|
|
case PowerCycle::POWER_CYCLE_RESUME:
|
|
ALOGI("Received RESUME power cycle");
|
|
mWatchdogProcessService->setEnabled(/*isEnabled=*/true);
|
|
break;
|
|
default:
|
|
ALOGW("Unsupported power cycle: %d", powerCycle);
|
|
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
|
|
"Unsupported power cycle");
|
|
}
|
|
return Status::ok();
|
|
}
|
|
|
|
Status WatchdogInternalHandler::handleUserStateChange(userid_t userId,
|
|
const aawi::UserState& userState) {
|
|
std::string stateDesc;
|
|
switch (userState) {
|
|
case aawi::UserState::USER_STATE_STARTED:
|
|
stateDesc = "started";
|
|
mWatchdogProcessService->onUserStateChange(userId, /*isStarted=*/true);
|
|
break;
|
|
case aawi::UserState::USER_STATE_SWITCHING:
|
|
stateDesc = "switching";
|
|
mWatchdogPerfService->onUserStateChange(userId, userState);
|
|
break;
|
|
case aawi::UserState::USER_STATE_UNLOCKING:
|
|
stateDesc = "unlocking";
|
|
mWatchdogPerfService->onUserStateChange(userId, userState);
|
|
break;
|
|
case aawi::UserState::USER_STATE_POST_UNLOCKED:
|
|
stateDesc = "post_unlocked";
|
|
mWatchdogPerfService->onUserStateChange(userId, userState);
|
|
break;
|
|
case aawi::UserState::USER_STATE_STOPPED:
|
|
stateDesc = "stopped";
|
|
mWatchdogProcessService->onUserStateChange(userId, /*isStarted=*/false);
|
|
break;
|
|
case aawi::UserState::USER_STATE_REMOVED:
|
|
stateDesc = "removed";
|
|
mIoOveruseMonitor->removeStatsForUser(userId);
|
|
break;
|
|
default:
|
|
// UserState::USER_STATE_UNLOCKED is not sent by CarService to the daemon. If signal is
|
|
// received, an exception will be thrown.
|
|
ALOGW("Unsupported user state: %d", userState);
|
|
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Unsupported user state");
|
|
}
|
|
ALOGI("Received user state change: user(%" PRId32 ") is %s", userId, stateDesc.c_str());
|
|
return Status::ok();
|
|
}
|
|
|
|
Status WatchdogInternalHandler::updateResourceOveruseConfigurations(
|
|
const std::vector<ResourceOveruseConfiguration>& configs) {
|
|
Status status = checkSystemUser();
|
|
if (!status.isOk()) {
|
|
return status;
|
|
}
|
|
// Maybe retry registring I/O overuse monitor if failed to initialize previously.
|
|
checkAndRegisterIoOveruseMonitor();
|
|
if (const auto result = mIoOveruseMonitor->updateResourceOveruseConfigurations(configs);
|
|
!result.ok()) {
|
|
return fromExceptionCode(result.error().code(), result.error().message());
|
|
}
|
|
return Status::ok();
|
|
}
|
|
|
|
Status WatchdogInternalHandler::getResourceOveruseConfigurations(
|
|
std::vector<ResourceOveruseConfiguration>* configs) {
|
|
Status status = checkSystemUser();
|
|
if (!status.isOk()) {
|
|
return status;
|
|
}
|
|
// Maybe retry registring I/O overuse monitor if failed to initialize previously.
|
|
checkAndRegisterIoOveruseMonitor();
|
|
if (const auto result = mIoOveruseMonitor->getResourceOveruseConfigurations(configs);
|
|
!result.ok()) {
|
|
return fromExceptionCode(result.error().code(), result.error().message());
|
|
}
|
|
return Status::ok();
|
|
}
|
|
|
|
Status WatchdogInternalHandler::controlProcessHealthCheck(bool enable) {
|
|
Status status = checkSystemUser();
|
|
if (!status.isOk()) {
|
|
return status;
|
|
}
|
|
mWatchdogProcessService->setEnabled(enable);
|
|
return Status::ok();
|
|
}
|
|
|
|
Status WatchdogInternalHandler::setThreadPriority(int pid, int tid, int uid, int policy,
|
|
int priority) {
|
|
Status status = checkSystemUser();
|
|
if (!status.isOk()) {
|
|
return status;
|
|
}
|
|
return mThreadPriorityController->setThreadPriority(pid, tid, uid, policy, priority);
|
|
}
|
|
|
|
Status WatchdogInternalHandler::getThreadPriority(int pid, int tid, int uid,
|
|
ThreadPolicyWithPriority* result) {
|
|
Status status = checkSystemUser();
|
|
if (!status.isOk()) {
|
|
return status;
|
|
}
|
|
return mThreadPriorityController->getThreadPriority(pid, tid, uid, result);
|
|
}
|
|
|
|
void WatchdogInternalHandler::setThreadPriorityController(
|
|
std::unique_ptr<ThreadPriorityController> threadPriorityController) {
|
|
mThreadPriorityController = std::move(threadPriorityController);
|
|
}
|
|
|
|
} // namespace watchdog
|
|
} // namespace automotive
|
|
} // namespace android
|