209 lines
6.4 KiB
C++
209 lines
6.4 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 "carwatchdog_testclient"
|
|
|
|
#include "WatchdogClient.h"
|
|
|
|
#include <android-base/file.h>
|
|
#include <android/binder_manager.h>
|
|
|
|
#include <unordered_map>
|
|
|
|
namespace aidl {
|
|
namespace android {
|
|
namespace automotive {
|
|
namespace watchdog {
|
|
|
|
using ::android::Looper;
|
|
using ::android::Message;
|
|
using ::android::Mutex;
|
|
using ::android::sp;
|
|
|
|
namespace {
|
|
|
|
enum { WHAT_CHECK_ALIVE = 1, WHAT_BECOME_INACTIVE = 2, WHAT_TERMINATE = 3 };
|
|
|
|
const std::unordered_map<std::string, TimeoutLength> kTimeoutMap =
|
|
{{"critical", TimeoutLength::TIMEOUT_CRITICAL},
|
|
{"moderate", TimeoutLength::TIMEOUT_MODERATE},
|
|
{"normal", TimeoutLength::TIMEOUT_NORMAL}};
|
|
|
|
} // namespace
|
|
|
|
WatchdogClient::WatchdogClient(const sp<Looper>& handlerLooper) : mHandlerLooper(handlerLooper) {
|
|
mMessageHandler = new MessageHandlerImpl(this);
|
|
}
|
|
|
|
ndk::ScopedAStatus WatchdogClient::checkIfAlive(int32_t sessionId, TimeoutLength timeout) {
|
|
if (mVerbose) {
|
|
ALOGI("Pinged by car watchdog daemon: session id = %d", sessionId);
|
|
}
|
|
Mutex::Autolock lock(mMutex);
|
|
mHandlerLooper->removeMessages(mMessageHandler, WHAT_CHECK_ALIVE);
|
|
mSession = HealthCheckSession(sessionId, timeout);
|
|
mHandlerLooper->sendMessage(mMessageHandler, Message(WHAT_CHECK_ALIVE));
|
|
return ndk::ScopedAStatus::ok();
|
|
}
|
|
|
|
ndk::ScopedAStatus WatchdogClient::prepareProcessTermination() {
|
|
ALOGI("This process is being terminated by car watchdog");
|
|
return ndk::ScopedAStatus::ok();
|
|
}
|
|
|
|
bool WatchdogClient::initialize(const CommandParam& param) {
|
|
ndk::SpAIBinder binder(
|
|
AServiceManager_getService("android.automotive.watchdog.ICarWatchdog/default"));
|
|
if (binder.get() == nullptr) {
|
|
ALOGE("Getting carwatchdog daemon failed");
|
|
return false;
|
|
}
|
|
std::shared_ptr<ICarWatchdog> server = ICarWatchdog::fromBinder(binder);
|
|
if (server == nullptr) {
|
|
ALOGE("Failed to connect to carwatchdog daemon");
|
|
return false;
|
|
}
|
|
{
|
|
Mutex::Autolock lock(mMutex);
|
|
mWatchdogServer = server;
|
|
mIsClientActive = true;
|
|
}
|
|
mForcedKill = param.forcedKill;
|
|
mVerbose = param.verbose;
|
|
registerClient(param.timeout);
|
|
|
|
if (param.inactiveAfterInSec >= 0) {
|
|
mHandlerLooper->sendMessageDelayed(seconds_to_nanoseconds(param.inactiveAfterInSec),
|
|
mMessageHandler, Message(WHAT_BECOME_INACTIVE));
|
|
}
|
|
if (param.terminateAfterInSec >= 0) {
|
|
mHandlerLooper->sendMessageDelayed(seconds_to_nanoseconds(param.terminateAfterInSec),
|
|
mMessageHandler, Message(WHAT_TERMINATE));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void WatchdogClient::finalize() {
|
|
{
|
|
Mutex::Autolock lock(mMutex);
|
|
if (!mWatchdogServer) {
|
|
return;
|
|
}
|
|
}
|
|
unregisterClient();
|
|
}
|
|
|
|
void WatchdogClient::respondToWatchdog() {
|
|
int sessionId;
|
|
std::shared_ptr<ICarWatchdog> watchdogServer;
|
|
std::shared_ptr<ICarWatchdogClient> testClient;
|
|
{
|
|
Mutex::Autolock lock(mMutex);
|
|
if (!mIsClientActive || mTestClient == nullptr || mWatchdogServer == nullptr) {
|
|
return;
|
|
}
|
|
watchdogServer = mWatchdogServer;
|
|
testClient = mTestClient;
|
|
sessionId = mSession.id;
|
|
}
|
|
ndk::ScopedAStatus status = watchdogServer->tellClientAlive(testClient, sessionId);
|
|
if (!status.isOk()) {
|
|
ALOGE("Failed to call binder interface: %d", status.getStatus());
|
|
return;
|
|
}
|
|
if (mVerbose) {
|
|
ALOGI("Sent response to car watchdog daemon: session id = %d", sessionId);
|
|
}
|
|
}
|
|
|
|
void WatchdogClient::becomeInactive() {
|
|
Mutex::Autolock lock(mMutex);
|
|
mIsClientActive = false;
|
|
if (mVerbose) {
|
|
ALOGI("Became inactive");
|
|
}
|
|
}
|
|
|
|
void WatchdogClient::terminateProcess() {
|
|
if (!mForcedKill) {
|
|
unregisterClient();
|
|
}
|
|
raise(SIGKILL);
|
|
}
|
|
|
|
void WatchdogClient::registerClient(const std::string& timeout) {
|
|
ndk::SpAIBinder binder = this->asBinder();
|
|
if (binder.get() == nullptr) {
|
|
ALOGW("Failed to get car watchdog client binder object");
|
|
return;
|
|
}
|
|
std::shared_ptr<ICarWatchdogClient> client = ICarWatchdogClient::fromBinder(binder);
|
|
if (client == nullptr) {
|
|
ALOGW("Failed to get ICarWatchdogClient from binder");
|
|
return;
|
|
}
|
|
std::shared_ptr<ICarWatchdog> watchdogServer;
|
|
{
|
|
Mutex::Autolock lock(mMutex);
|
|
if (mWatchdogServer == nullptr) {
|
|
return;
|
|
}
|
|
watchdogServer = mWatchdogServer;
|
|
mTestClient = client;
|
|
}
|
|
watchdogServer->registerClient(client, kTimeoutMap.at(timeout));
|
|
ALOGI("Successfully registered the client to car watchdog server");
|
|
}
|
|
|
|
void WatchdogClient::unregisterClient() {
|
|
std::shared_ptr<ICarWatchdog> watchdogServer;
|
|
std::shared_ptr<ICarWatchdogClient> testClient;
|
|
{
|
|
Mutex::Autolock lock(mMutex);
|
|
if (mWatchdogServer == nullptr || mTestClient == nullptr) {
|
|
return;
|
|
}
|
|
watchdogServer = mWatchdogServer;
|
|
testClient = mTestClient;
|
|
mTestClient = nullptr;
|
|
}
|
|
watchdogServer->unregisterClient(testClient);
|
|
ALOGI("Successfully unregistered the client from car watchdog server");
|
|
}
|
|
|
|
WatchdogClient::MessageHandlerImpl::MessageHandlerImpl(WatchdogClient* client) : mClient(client) {}
|
|
|
|
void WatchdogClient::MessageHandlerImpl::handleMessage(const Message& message) {
|
|
switch (message.what) {
|
|
case WHAT_CHECK_ALIVE:
|
|
mClient->respondToWatchdog();
|
|
break;
|
|
case WHAT_BECOME_INACTIVE:
|
|
mClient->becomeInactive();
|
|
break;
|
|
case WHAT_TERMINATE:
|
|
mClient->terminateProcess();
|
|
break;
|
|
default:
|
|
ALOGW("Unknown message: %d", message.what);
|
|
}
|
|
}
|
|
|
|
} // namespace watchdog
|
|
} // namespace automotive
|
|
} // namespace android
|
|
} // namespace aidl
|