Handle power cycle change in car watchdog daemon
- When the system goes into suspend/shutdown power cycle, car watchdog
daemon stops checking clients' health status.
- Accordingly, when the system resumes, car watchdog daemon resumes the
health check.
- Pinged client check is refactored.
- ICarWatchdog::notifyStateChange's signature is modified not to use
vector or List.
- Add verbose mode to carwatchog_testclient
Bug: 148884065
Test: run carwatchdog_testcliet with verbose, run "dumpsys car_service
resume", and make sure that car watchdog daemon pauses pinging.
Change-Id: I1d357dd5c101fac8728303ac60fb5cc001c9fd70
diff --git a/service/src/com/android/car/watchdog/CarWatchdogService.java b/service/src/com/android/car/watchdog/CarWatchdogService.java
index 21ed269..b511e04 100644
--- a/service/src/com/android/car/watchdog/CarWatchdogService.java
+++ b/service/src/com/android/car/watchdog/CarWatchdogService.java
@@ -26,6 +26,10 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.automotive.watchdog.ICarWatchdogClient;
+import android.automotive.watchdog.PowerCycle;
+import android.automotive.watchdog.StateType;
+import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
+import android.car.hardware.power.ICarPowerStateListener;
import android.car.watchdog.ICarWatchdogService;
import android.car.watchdoglib.CarWatchdogDaemonHelper;
import android.content.Context;
@@ -39,6 +43,8 @@
import androidx.annotation.VisibleForTesting;
+import com.android.car.CarLocalServices;
+import com.android.car.CarPowerManagementService;
import com.android.car.CarServiceBase;
import com.android.internal.annotations.GuardedBy;
@@ -116,6 +122,7 @@
}
mCarWatchdogDaemonHelper.addOnConnectionChangeListener(mConnectionListener);
mCarWatchdogDaemonHelper.connect();
+ subscribePowerCycleChange();
if (DEBUG) {
Log.d(TAG, "CarWatchdogService is initialized");
}
@@ -357,6 +364,54 @@
}
}
+ private void subscribePowerCycleChange() {
+ CarPowerManagementService powerService =
+ CarLocalServices.getService(CarPowerManagementService.class);
+ if (powerService == null) {
+ Log.w(TAG, "Cannot get CarPowerManagementService");
+ return;
+ }
+ powerService.registerListener(new ICarPowerStateListener.Stub() {
+ @Override
+ public void onStateChanged(int state) {
+ int powerCycle;
+ switch (state) {
+ // SHUTDOWN_PREPARE covers suspend and shutdown.
+ case CarPowerStateListener.SHUTDOWN_PREPARE:
+ powerCycle = PowerCycle.POWER_CYCLE_SUSPEND;
+ break;
+ // ON covers resume.
+ case CarPowerStateListener.ON:
+ powerCycle = PowerCycle.POWER_CYCLE_RESUME;
+ // There might be outdated & incorrect info. We should reset them before
+ // starting to do health check.
+ prepareHealthCheck();
+ break;
+ default:
+ return;
+ }
+ try {
+ mCarWatchdogDaemonHelper.notifySystemStateChange(StateType.POWER_CYCLE,
+ powerCycle, /* arg2= */ -1);
+ } catch (IllegalArgumentException | RemoteException e) {
+ Log.w(TAG, "Notifying system state change failed: " + e);
+ }
+ if (DEBUG) {
+ Log.d(TAG, "Notified car watchdog daemon a power cycle(" + powerCycle + ")");
+ }
+ }
+ });
+ }
+
+ private void prepareHealthCheck() {
+ synchronized (mLock) {
+ for (int timeout : ALL_TIMEOUTS) {
+ SparseArray<ClientInfo> pingedClients = mPingedClientMap.get(timeout);
+ pingedClients.clear();
+ }
+ }
+ }
+
@NonNull
private int[] toIntArray(@NonNull ArrayList<Integer> list) {
int size = list.size();
diff --git a/watchdog/aidl/android/automotive/watchdog/ICarWatchdog.aidl b/watchdog/aidl/android/automotive/watchdog/ICarWatchdog.aidl
index ae11b4a..8368a81 100644
--- a/watchdog/aidl/android/automotive/watchdog/ICarWatchdog.aidl
+++ b/watchdog/aidl/android/automotive/watchdog/ICarWatchdog.aidl
@@ -119,11 +119,12 @@
* The caller should have system UID.
*
* @param type One of the change types defined in the StateType enum.
- * @param args State change information for the specified type.
+ * @param arg1 First state change information for the specified type.
+ * @param arg2 Second state change information for the specified type.
*
- * When type is POWER_CYCLE, args should contain the current power cycle of the device.
- * When type is USER_STATE, args should contain the user ID and current user state.
- * When type is BOOT_PHASE, args should contain the current boot phase.
+ * When type is POWER_CYCLE, arg1 should contain the current power cycle of the device.
+ * When type is USER_STATE, arg1 and arg2 should contain the user ID and the current user state.
+ * When type is BOOT_PHASE, arg1 should contain the current boot phase.
*/
- void notifySystemStateChange(in StateType type, in @utf8InCpp List<String> args);
+ void notifySystemStateChange(in StateType type, in int arg1, in int arg2);
}
diff --git a/watchdog/car-watchdog-lib/src/android/car/watchdoglib/CarWatchdogDaemonHelper.java b/watchdog/car-watchdog-lib/src/android/car/watchdoglib/CarWatchdogDaemonHelper.java
index 73cb766..45bd8ff 100644
--- a/watchdog/car-watchdog-lib/src/android/car/watchdoglib/CarWatchdogDaemonHelper.java
+++ b/watchdog/car-watchdog-lib/src/android/car/watchdoglib/CarWatchdogDaemonHelper.java
@@ -33,7 +33,6 @@
import com.android.internal.annotations.GuardedBy;
-import java.util.List;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -260,14 +259,16 @@
/**
* Tells car watchdog daemon that system state has been changed for the specified StateType.
*
- * @param StateType Either PowerCycle, UserState, or BootPhase
- * @param args Args explaining the state change for the specified state type.
+ * @param type Either PowerCycle, UserState, or BootPhase
+ * @param arg1 First state change information for the specified state type.
+ * @param arg2 Second state change information for the specified state type.
* @throws IllegalArgumentException If the args don't match the state type. Refer to the aidl
- * interface for more information on the args.
+ * interface for more information on the args.
* @throws RemoteException
*/
- public void notifySystemStateChange(int type, List<String> args) throws RemoteException {
- invokeDaemonMethod((daemon) -> daemon.notifySystemStateChange(type, args));
+ public void notifySystemStateChange(int type, int arg1, int arg2)
+ throws IllegalArgumentException, RemoteException {
+ invokeDaemonMethod((daemon) -> daemon.notifySystemStateChange(type, arg1, arg2));
}
private void invokeDaemonMethod(Invokable r) throws IllegalArgumentException, RemoteException {
diff --git a/watchdog/server/src/WatchdogBinderMediator.cpp b/watchdog/server/src/WatchdogBinderMediator.cpp
index aedd27c..68c944a 100644
--- a/watchdog/server/src/WatchdogBinderMediator.cpp
+++ b/watchdog/server/src/WatchdogBinderMediator.cpp
@@ -140,28 +140,14 @@
return mWatchdogProcessService->unregisterMonitor(monitor);
}
-Status WatchdogBinderMediator::notifySystemStateChange(StateType type,
- const std::vector<std::string>& args) {
+Status WatchdogBinderMediator::notifySystemStateChange(StateType type, int32_t arg1, int32_t arg2) {
Status status = checkSystemPermission();
if (!status.isOk()) {
return status;
}
switch (type) {
case StateType::POWER_CYCLE: {
- if (args.size() != 1) {
- return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
- StringPrintf("Expected exactly one argument for %s "
- "change, got %zu",
- toString(StateType::POWER_CYCLE).c_str(),
- args.size()));
- }
- uint32_t powerCycleArg = 0;
- if (!ParseUint(args[0], &powerCycleArg)) {
- return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
- StringPrintf("Failed to parse power cycle argument %s",
- args[0].c_str()));
- }
- auto powerCycle = static_cast<PowerCycle>(powerCycleArg);
+ PowerCycle powerCycle = static_cast<PowerCycle>(static_cast<uint32_t>(arg1));
if (powerCycle >= PowerCycle::NUM_POWER_CYLES) {
return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
StringPrintf("Invalid power cycle %d", powerCycle));
@@ -169,26 +155,8 @@
return mWatchdogProcessService->notifyPowerCycleChange(powerCycle);
}
case StateType::USER_STATE: {
- if (args.size() != 2) {
- return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
- StringPrintf("Expected exactly two arguments for %s "
- "change, got %zu",
- toString(StateType::USER_STATE).c_str(),
- args.size()));
- }
- userid_t userId = 0;
- if (!ParseUint(args[0], &userId)) {
- return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
- StringPrintf("Failed to parse user ID argument %s",
- args[0].c_str()));
- }
- uint32_t userStateArg = 0;
- if (!ParseUint(args[1], &userStateArg)) {
- return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
- StringPrintf("Failed to parse user state argument %s",
- args[0].c_str()));
- }
- auto userState = static_cast<UserState>(userStateArg);
+ userid_t userId = static_cast<userid_t>(arg1);
+ UserState userState = static_cast<UserState>(static_cast<uint32_t>(arg2));
if (userState >= UserState::NUM_USER_STATES) {
return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
StringPrintf("Invalid user state %d", userState));
@@ -196,20 +164,8 @@
return mWatchdogProcessService->notifyUserStateChange(userId, userState);
}
case StateType::BOOT_PHASE: {
- if (args.size() != 1) {
- return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
- StringPrintf("Expacted exactly one argument for %s "
- "change, got %zu",
- toString(StateType::BOOT_PHASE).c_str(),
- args.size()));
- }
- uint32_t phase = 0;
- if (!ParseUint(args[0], &phase)) {
- return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
- StringPrintf("Failed to parse boot phase argument %s",
- args[0].c_str()));
- }
- if (static_cast<BootPhase>(phase) >= BootPhase::BOOT_COMPLETED) {
+ BootPhase phase = static_cast<BootPhase>(static_cast<uint32_t>(arg1));
+ if (phase >= BootPhase::BOOT_COMPLETED) {
/*auto ret = mIoPerfCollection->onBootFinished();
if (!ret.ok()) {
return fromExceptionCode(ret.error().code(), ret.error().message());
diff --git a/watchdog/server/src/WatchdogBinderMediator.h b/watchdog/server/src/WatchdogBinderMediator.h
index 1041c8e..a3b19a2 100644
--- a/watchdog/server/src/WatchdogBinderMediator.h
+++ b/watchdog/server/src/WatchdogBinderMediator.h
@@ -69,8 +69,7 @@
int32_t pid) override {
return mWatchdogProcessService->tellDumpFinished(monitor, pid);
}
- binder::Status notifySystemStateChange(StateType type,
- const std::vector<std::string>& args) override;
+ binder::Status notifySystemStateChange(StateType type, int32_t arg1, int32_t arg2) override;
protected:
android::base::Result<void> init(android::sp<WatchdogProcessService> watchdogProcessService,
diff --git a/watchdog/server/src/WatchdogProcessService.cpp b/watchdog/server/src/WatchdogProcessService.cpp
index bbb08c5..51d1f07 100644
--- a/watchdog/server/src/WatchdogProcessService.cpp
+++ b/watchdog/server/src/WatchdogProcessService.cpp
@@ -21,6 +21,7 @@
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <binder/IPCThreadState.h>
@@ -30,6 +31,7 @@
using std::literals::chrono_literals::operator""s;
using android::base::Error;
+using android::base::GetProperty;
using android::base::Result;
using android::base::StringAppendF;
using android::base::StringPrintf;
@@ -67,14 +69,22 @@
return buffer;
}
+bool isSystemShuttingDown() {
+ std::string sysPowerCtl;
+ std::istringstream tokenStream(GetProperty("sys.powerctl", ""));
+ std::getline(tokenStream, sysPowerCtl, ',');
+ return sysPowerCtl == "reboot" || sysPowerCtl == "shutdown";
+}
+
} // namespace
WatchdogProcessService::WatchdogProcessService(const sp<Looper>& handlerLooper) :
mHandlerLooper(handlerLooper), mLastSessionId(0) {
mMessageHandler = new MessageHandlerImpl(this);
+ mWatchdogEnabled = true;
for (const auto& timeout : kTimeouts) {
mClients.insert(std::make_pair(timeout, std::vector<ClientInfo>()));
- mPingedClients.insert(std::make_pair(timeout, PingedClientSet()));
+ mPingedClients.insert(std::make_pair(timeout, PingedClientMap()));
}
}
@@ -187,8 +197,35 @@
}
Status WatchdogProcessService::notifyPowerCycleChange(PowerCycle cycle) {
- // TODO(b/148884065): implement this method.
- (void)cycle;
+ std::string buffer;
+ Mutex::Autolock lock(mMutex);
+ bool oldStatus = mWatchdogEnabled;
+ switch (cycle) {
+ case PowerCycle::POWER_CYCLE_SHUTDOWN:
+ mWatchdogEnabled = false;
+ buffer = "SHUTDOWN power cycle";
+ break;
+ case PowerCycle::POWER_CYCLE_SUSPEND:
+ mWatchdogEnabled = false;
+ buffer = "SUSPEND power cycle";
+ break;
+ case PowerCycle::POWER_CYCLE_RESUME:
+ mWatchdogEnabled = true;
+ for (const auto& timeout : kTimeouts) {
+ startHealthCheckingLocked(timeout);
+ }
+ buffer = "RESUME power cycle";
+ break;
+ default:
+ ALOGW("Unsupported power cycle: %d", cycle);
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
+ "The monitor is not registered or an invalid monitor "
+ "is given");
+ }
+ ALOGI("Received %s", buffer.c_str());
+ if (oldStatus != mWatchdogEnabled) {
+ ALOGI("Car watchdog is %s", mWatchdogEnabled ? "enabled" : "disabled");
+ }
return Status::ok();
}
@@ -201,55 +238,65 @@
Result<void> WatchdogProcessService::dump(int fd, const Vector<String16>& /*args*/) {
Mutex::Autolock lock(mMutex);
+ const char* indent = " ";
+ const char* doubleIndent = " ";
std::string buffer;
WriteStringToFd("CAR WATCHDOG PROCESS SERVICE\n", fd);
- WriteStringToFd(" Registered clients\n", fd);
+ WriteStringToFd(StringPrintf("%sWatchdog enabled: %s\n", indent,
+ mWatchdogEnabled ? "true" : "false"),
+ fd);
+ WriteStringToFd(StringPrintf("%sRegistered clients\n", indent), fd);
int count = 1;
for (const auto& timeout : kTimeouts) {
std::vector<ClientInfo>& clients = mClients[timeout];
for (auto it = clients.begin(); it != clients.end(); it++, count++) {
- WriteStringToFd(StringPrintf(" Client #%d: %s\n", count, it->toString().c_str()),
+ WriteStringToFd(StringPrintf("%sClient #%d: %s\n", doubleIndent, count,
+ it->toString().c_str()),
fd);
}
}
- WriteStringToFd(StringPrintf("\n Monitor registered: %s\n",
+ WriteStringToFd(StringPrintf("\n%sMonitor registered: %s\n", indent,
mMonitor == nullptr ? "false" : "true"),
fd);
+ WriteStringToFd(StringPrintf("%sisSystemShuttingDown: %s\n", indent,
+ isSystemShuttingDown() ? "true" : "false"),
+ fd);
return {};
}
void WatchdogProcessService::doHealthCheck(int what) {
mHandlerLooper->removeMessages(mMessageHandler, what);
+ if (!isWatchdogEnabled()) {
+ return;
+ }
const TimeoutLength timeout = static_cast<TimeoutLength>(what);
- std::vector<ClientInfo> clientsToCheck;
- PingedClientSet& pingedClients = mPingedClients[timeout];
-
dumpAndKillClientsIfNotResponding(timeout);
/* Generates a temporary/local vector containing clients.
* Using a local copy may send unnecessary ping messages to clients after they are unregistered.
* Clients should be able to handle them.
*/
+ std::vector<ClientInfo> clientsToCheck;
+ PingedClientMap& pingedClients = mPingedClients[timeout];
{
Mutex::Autolock lock(mMutex);
- clientsToCheck = mClients[timeout];
pingedClients.clear();
+ clientsToCheck = mClients[timeout];
+ for (auto& clientInfo : clientsToCheck) {
+ int sessionId = getNewSessionId();
+ clientInfo.sessionId = sessionId;
+ pingedClients.insert(std::make_pair(sessionId, clientInfo));
+ }
}
for (const auto& clientInfo : clientsToCheck) {
- int32_t sessionId = getNewSessionId();
- PingedClient targetClient(clientInfo.client, sessionId);
- {
- Mutex::Autolock lock(mMutex);
- pingedClients.insert(targetClient);
- }
- Status status = clientInfo.client->checkIfAlive(sessionId, timeout);
+ Status status = clientInfo.client->checkIfAlive(clientInfo.sessionId, timeout);
if (!status.isOk()) {
ALOGW("Sending a ping message to client(pid: %d) failed: %s", clientInfo.pid,
status.exceptionMessage().c_str());
{
Mutex::Autolock lock(mMutex);
- pingedClients.erase(targetClient);
+ pingedClients.erase(clientInfo.sessionId);
}
}
}
@@ -318,7 +365,7 @@
// If the client array becomes non-empty, start health checking.
if (clients.size() == 1) {
- startHealthChecking(timeout);
+ startHealthCheckingLocked(timeout);
}
if (DEBUG) {
ALOGD("Car watchdog %s(pid: %d, timeout: %d) is registered", clientName, callingPid,
@@ -350,11 +397,11 @@
Status WatchdogProcessService::tellClientAliveLocked(const sp<ICarWatchdogClient>& client,
int32_t sessionId) {
+ const sp<IBinder> binder = BnCarWatchdog::asBinder(client);
for (const auto& timeout : kTimeouts) {
- PingedClientSet& clients = mPingedClients[timeout];
- PingedClient respondingClient(client, sessionId);
- PingedClientSet::const_iterator it = clients.find(respondingClient);
- if (it == clients.cend()) {
+ PingedClientMap& clients = mPingedClients[timeout];
+ PingedClientMap::const_iterator it = clients.find(sessionId);
+ if (it == clients.cend() || binder != BnCarWatchdog::asBinder(it->second.client)) {
continue;
}
clients.erase(it);
@@ -382,7 +429,9 @@
return false;
}
-Result<void> WatchdogProcessService::startHealthChecking(TimeoutLength timeout) {
+Result<void> WatchdogProcessService::startHealthCheckingLocked(TimeoutLength timeout) {
+ PingedClientMap& clients = mPingedClients[timeout];
+ clients.clear();
int what = static_cast<int>(timeout);
auto durationNs = timeoutToDurationNs(timeout);
mHandlerLooper->sendMessageDelayed(durationNs.count(), mMessageHandler, Message(what));
@@ -393,10 +442,10 @@
std::vector<int32_t> processIds;
{
Mutex::Autolock lock(mMutex);
- PingedClientSet& clients = mPingedClients[timeout];
- for (PingedClientSet::const_iterator it = clients.cbegin(); it != clients.cend(); it++) {
+ PingedClientMap& clients = mPingedClients[timeout];
+ for (PingedClientMap::const_iterator it = clients.cbegin(); it != clients.cend(); it++) {
pid_t pid = -1;
- sp<IBinder> binder = BnCarWatchdog::asBinder((*it).client);
+ sp<IBinder> binder = BnCarWatchdog::asBinder(it->second.client);
std::vector<TimeoutLength> timeouts = {timeout};
// Unhealthy clients are eventually removed from the list through binderDied when they
// are killed.
@@ -419,11 +468,11 @@
if (size == 0) {
return {};
}
+ std::string pidString = pidArrayToString(processesNotResponding);
sp<ICarWatchdogMonitor> monitor;
{
Mutex::Autolock lock(mMutex);
if (mMonitor == nullptr) {
- std::string pidString = pidArrayToString(processesNotResponding);
std::string errorMsg =
StringPrintf("Cannot dump and kill processes(pid = %s): Monitor is not set",
pidString.c_str());
@@ -432,9 +481,13 @@
}
monitor = mMonitor;
}
+ if (isSystemShuttingDown()) {
+ ALOGI("Skip dumping and killing processes(%s): The system is shutting down",
+ pidString.c_str());
+ return {};
+ }
monitor->onClientsNotResponding(processesNotResponding);
if (DEBUG) {
- std::string pidString = pidArrayToString(processesNotResponding);
ALOGD("Dumping and killing processes is requested: %s", pidString.c_str());
}
return {};
@@ -448,6 +501,11 @@
return mLastSessionId;
}
+bool WatchdogProcessService::isWatchdogEnabled() {
+ Mutex::Autolock lock(mMutex);
+ return mWatchdogEnabled;
+}
+
std::string WatchdogProcessService::ClientInfo::toString() {
std::string buffer;
StringAppendF(&buffer, "pid = %d, type = %s", pid, type == Regular ? "Regular" : "Mediator");
diff --git a/watchdog/server/src/WatchdogProcessService.h b/watchdog/server/src/WatchdogProcessService.h
index c76936e..d5e389a 100644
--- a/watchdog/server/src/WatchdogProcessService.h
+++ b/watchdog/server/src/WatchdogProcessService.h
@@ -77,26 +77,11 @@
android::sp<ICarWatchdogClient> client;
pid_t pid;
+ int sessionId;
ClientType type;
};
- struct PingedClient {
- PingedClient(const android::sp<ICarWatchdogClient>& client, int32_t sessionId) :
- client(client), sessionId(sessionId) {}
-
- bool operator==(const PingedClient& other) const { return sessionId == other.sessionId; }
-
- android::sp<ICarWatchdogClient> client;
- int32_t sessionId;
- };
-
- struct PingedClientHash {
- std::size_t operator()(const PingedClient& pingedClient) const {
- return pingedClient.sessionId;
- }
- };
-
- typedef std::unordered_set<PingedClient, PingedClientHash> PingedClientSet;
+ typedef std::unordered_map<int, ClientInfo> PingedClientMap;
class MessageHandlerImpl : public MessageHandler {
public:
@@ -116,10 +101,11 @@
bool isRegisteredLocked(const android::sp<ICarWatchdogClient>& client);
binder::Status tellClientAliveLocked(const android::sp<ICarWatchdogClient>& client,
int32_t sessionId);
- base::Result<void> startHealthChecking(TimeoutLength timeout);
+ base::Result<void> startHealthCheckingLocked(TimeoutLength timeout);
base::Result<void> dumpAndKillClientsIfNotResponding(TimeoutLength timeout);
base::Result<void> dumpAndKillAllProcesses(const std::vector<int32_t>& processesNotResponding);
int32_t getNewSessionId();
+ bool isWatchdogEnabled();
using Processor =
std::function<void(std::vector<ClientInfo>&, std::vector<ClientInfo>::const_iterator)>;
@@ -127,12 +113,13 @@
const android::sp<IBinder> binder, const Processor& processor);
private:
- Mutex mMutex;
sp<Looper> mHandlerLooper;
android::sp<MessageHandlerImpl> mMessageHandler;
+ Mutex mMutex;
std::unordered_map<TimeoutLength, std::vector<ClientInfo>> mClients GUARDED_BY(mMutex);
- std::unordered_map<TimeoutLength, PingedClientSet> mPingedClients GUARDED_BY(mMutex);
+ std::unordered_map<TimeoutLength, PingedClientMap> mPingedClients GUARDED_BY(mMutex);
android::sp<ICarWatchdogMonitor> mMonitor GUARDED_BY(mMutex);
+ bool mWatchdogEnabled GUARDED_BY(mMutex);
// mLastSessionId is accessed only within main thread. No need for mutual-exclusion.
int32_t mLastSessionId;
};
diff --git a/watchdog/server/tests/WatchdogBinderMediatorTest.cpp b/watchdog/server/tests/WatchdogBinderMediatorTest.cpp
index b2155c9..cb533a2 100644
--- a/watchdog/server/tests/WatchdogBinderMediatorTest.cpp
+++ b/watchdog/server/tests/WatchdogBinderMediatorTest.cpp
@@ -286,102 +286,61 @@
TEST_F(WatchdogBinderMediatorTest, TestErrorOnNotifyStateChangeWithNonSystemCallingUid) {
StateType type = StateType::POWER_CYCLE;
- std::vector<std::string> args = {
- std::to_string(static_cast<int32_t>(PowerCycle::POWER_CYCLE_SUSPEND))};
EXPECT_CALL(*mMockWatchdogProcessService, notifyPowerCycleChange(_)).Times(0);
- Status status = mWatchdogBinderMediator->notifySystemStateChange(type, args);
+ Status status =
+ mWatchdogBinderMediator
+ ->notifySystemStateChange(type,
+ static_cast<int32_t>(PowerCycle::POWER_CYCLE_SUSPEND),
+ -1);
ASSERT_FALSE(status.isOk()) << status;
}
TEST_F(WatchdogBinderMediatorTest, TestNotifyPowerCycleChange) {
setSystemCallingUid();
StateType type = StateType::POWER_CYCLE;
- std::vector<std::string> args = {
- std::to_string(static_cast<int32_t>(PowerCycle::POWER_CYCLE_SUSPEND))};
EXPECT_CALL(*mMockWatchdogProcessService,
notifyPowerCycleChange(PowerCycle::POWER_CYCLE_SUSPEND))
.WillOnce(Return(Status::ok()));
- Status status = mWatchdogBinderMediator->notifySystemStateChange(type, args);
+ Status status =
+ mWatchdogBinderMediator
+ ->notifySystemStateChange(type,
+ static_cast<int32_t>(PowerCycle::POWER_CYCLE_SUSPEND),
+ -1);
ASSERT_TRUE(status.isOk()) << status;
}
TEST_F(WatchdogBinderMediatorTest, TestErrorOnNotifyPowerCycleChangeWithInvalidArgs) {
EXPECT_CALL(*mMockWatchdogProcessService, notifyPowerCycleChange(_)).Times(0);
StateType type = StateType::POWER_CYCLE;
- std::vector<std::string> args = {std::to_string(
- static_cast<int32_t>(PowerCycle::POWER_CYCLE_SUSPEND)),
- std::to_string(
- static_cast<int32_t>(PowerCycle::POWER_CYCLE_RESUME))};
- Status status = mWatchdogBinderMediator->notifySystemStateChange(type, args);
+
+ Status status = mWatchdogBinderMediator->notifySystemStateChange(type, -1, -1);
ASSERT_FALSE(status.isOk()) << status;
- args.clear();
- args.push_back("-1");
- status = mWatchdogBinderMediator->notifySystemStateChange(type, args);
- ASSERT_FALSE(status.isOk()) << status;
-
- args.clear();
- args.push_back("3000");
- status = mWatchdogBinderMediator->notifySystemStateChange(type, args);
- ASSERT_FALSE(status.isOk()) << status;
-
- args.clear();
- args.push_back("invalid_power_cycle");
- status = mWatchdogBinderMediator->notifySystemStateChange(type, args);
+ status = mWatchdogBinderMediator->notifySystemStateChange(type, 3000, -1);
ASSERT_FALSE(status.isOk()) << status;
}
TEST_F(WatchdogBinderMediatorTest, TestNotifyUserStateChange) {
setSystemCallingUid();
StateType type = StateType::USER_STATE;
- std::vector<std::string> args = {"234567",
- std::to_string(
- static_cast<int32_t>(UserState::USER_STATE_STOPPED))};
EXPECT_CALL(*mMockWatchdogProcessService,
notifyUserStateChange(234567, UserState::USER_STATE_STOPPED))
.WillOnce(Return(Status::ok()));
- Status status = mWatchdogBinderMediator->notifySystemStateChange(type, args);
+ Status status =
+ mWatchdogBinderMediator
+ ->notifySystemStateChange(type, 234567,
+ static_cast<int32_t>(UserState::USER_STATE_STOPPED));
ASSERT_TRUE(status.isOk()) << status;
}
TEST_F(WatchdogBinderMediatorTest, TestErrorOnNotifyUserStateChangeWithInvalidArgs) {
EXPECT_CALL(*mMockWatchdogProcessService, notifyUserStateChange(_, _)).Times(0);
- StateType type = StateType::POWER_CYCLE;
- std::vector<std::string> args = {"234567",
- std::to_string(
- static_cast<int32_t>(UserState::USER_STATE_STOPPED)),
- "extra_arg"};
- Status status = mWatchdogBinderMediator->notifySystemStateChange(type, args);
+ StateType type = StateType::USER_STATE;
+
+ Status status = mWatchdogBinderMediator->notifySystemStateChange(type, 234567, -1);
ASSERT_FALSE(status.isOk()) << status;
- args.clear();
- args.push_back("-1");
- args.push_back(std::to_string(static_cast<int32_t>(UserState::USER_STATE_STOPPED)));
- status = mWatchdogBinderMediator->notifySystemStateChange(type, args);
- ASSERT_FALSE(status.isOk()) << status;
-
- args.clear();
- args.push_back("invalid_user_id");
- args.push_back(std::to_string(static_cast<int32_t>(UserState::USER_STATE_STOPPED)));
- status = mWatchdogBinderMediator->notifySystemStateChange(type, args);
- ASSERT_FALSE(status.isOk()) << status;
-
- args.clear();
- args.push_back("234567");
- args.push_back("-1");
- status = mWatchdogBinderMediator->notifySystemStateChange(type, args);
- ASSERT_FALSE(status.isOk()) << status;
-
- args.clear();
- args.push_back("234567");
- args.push_back("3000");
- status = mWatchdogBinderMediator->notifySystemStateChange(type, args);
- ASSERT_FALSE(status.isOk()) << status;
-
- args.clear();
- args.push_back("234567");
- args.push_back("invalid_user_state");
- status = mWatchdogBinderMediator->notifySystemStateChange(type, args);
+ status = mWatchdogBinderMediator->notifySystemStateChange(type, 234567, 3000);
ASSERT_FALSE(status.isOk()) << status;
}
diff --git a/watchdog/testclient/src/WatchdogClient.cpp b/watchdog/testclient/src/WatchdogClient.cpp
index abc10ef..41a2b26 100644
--- a/watchdog/testclient/src/WatchdogClient.cpp
+++ b/watchdog/testclient/src/WatchdogClient.cpp
@@ -49,6 +49,9 @@
}
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);
@@ -74,6 +77,7 @@
mIsClientActive = true;
}
mForcedKill = param.forcedKill;
+ mVerbose = param.verbose;
registerClient(param.timeout);
if (param.inactiveAfterInSec >= 0) {
@@ -115,11 +119,17 @@
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() {
diff --git a/watchdog/testclient/src/WatchdogClient.h b/watchdog/testclient/src/WatchdogClient.h
index 2073598..95f11ca 100644
--- a/watchdog/testclient/src/WatchdogClient.h
+++ b/watchdog/testclient/src/WatchdogClient.h
@@ -33,6 +33,7 @@
int inactiveAfterInSec;
int terminateAfterInSec;
bool forcedKill;
+ bool verbose;
};
struct HealthCheckSession {
@@ -75,6 +76,7 @@
::android::sp<::android::Looper> mHandlerLooper;
::android::sp<MessageHandlerImpl> mMessageHandler;
bool mForcedKill;
+ bool mVerbose;
::android::Mutex mMutex;
std::shared_ptr<ICarWatchdog> mWatchdogServer GUARDED_BY(mMutex);
std::shared_ptr<ICarWatchdogClient> mTestClient GUARDED_BY(mMutex);
diff --git a/watchdog/testclient/src/main.cpp b/watchdog/testclient/src/main.cpp
index 5b24173..440069d 100644
--- a/watchdog/testclient/src/main.cpp
+++ b/watchdog/testclient/src/main.cpp
@@ -34,7 +34,7 @@
Result<CommandParam> checkArgument(int argc, char** argv) {
CommandParam param;
- if (argc != 4 && argc != 5) {
+ if (argc < 4) {
return Error() << "Invalid syntax";
}
if (strcmp(argv[1], "critical") && strcmp(argv[1], "moderate") && strcmp(argv[1], "normal")) {
@@ -49,22 +49,27 @@
if (!ParseInt(strValue, ¶m.terminateAfterInSec)) {
return Error() << "Invalid terminate after time";
}
- if (argc == 5) {
- if (strcmp(argv[4], "--forcedkill")) {
+ param.forcedKill = false;
+ param.verbose = false;
+ for (int i = 4; i < argc; i++) {
+ if (!strcmp(argv[i], "--forcedkill")) {
+ param.forcedKill = true;
+ } else if (!strcmp(argv[i], "--verbose")) {
+ param.verbose = true;
+ } else {
return Error() << "Invalid option";
}
- param.forcedKill = true;
- } else {
- param.forcedKill = false;
}
return param;
}
/**
* Usage: carwatchdog_testclient [timeout] [inactive_after] [terminate_after] [--forcedkill]
+ * [--verbose]
* timeout: critical|moderate|normal
* inactive_after: number in seconds. -1 for never being inactive.
* terminate_after: number in seconds. -1 for running forever.
* --forcedkill: terminate without unregistering from car watchdog daemon.
+ * --verbose: output verbose logs.
*/
int main(int argc, char** argv) {
sp<Looper> looper(Looper::prepare(/*opts=*/0));
@@ -81,7 +86,8 @@
ALOGE("timeout: critical|moderate|normal");
ALOGE("inactive_after: number in seconds (-1 for never being inactive)");
ALOGE("terminate_after: number in seconds (-1 for running forever)");
- ALOGE("--forcedkill: terminate without unregistering from car watchdog daemone");
+ ALOGE("--forcedkill: terminate without unregistering from car watchdog daemon");
+ ALOGE("--verbose: output verbose logs");
return 1;
}
if (!service->initialize(*param)) {