Merge "Update PowerCycle and GarageMode handling in watchdog." into sc-dev
diff --git a/cpp/watchdog/aidl/android/automotive/watchdog/internal/GarageMode.aidl b/cpp/watchdog/aidl/android/automotive/watchdog/internal/GarageMode.aidl
new file mode 100644
index 0000000..9bb7d86
--- /dev/null
+++ b/cpp/watchdog/aidl/android/automotive/watchdog/internal/GarageMode.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+package android.automotive.watchdog.internal;
+
+/**
+ * Used by ICarWatchdog to describe the garage mode status.
+ */
+@Backing(type="int")
+enum GarageMode {
+ /**
+ * The system is in normal mode.
+ */
+ GARAGE_MODE_OFF,
+
+ /**
+ * The system is in garage mode.
+ */
+ GARAGE_MODE_ON,
+}
diff --git a/cpp/watchdog/aidl/android/automotive/watchdog/internal/PowerCycle.aidl b/cpp/watchdog/aidl/android/automotive/watchdog/internal/PowerCycle.aidl
index 2539892..a23fa4e 100644
--- a/cpp/watchdog/aidl/android/automotive/watchdog/internal/PowerCycle.aidl
+++ b/cpp/watchdog/aidl/android/automotive/watchdog/internal/PowerCycle.aidl
@@ -22,14 +22,14 @@
@Backing(type="int")
enum PowerCycle {
/**
- * The system is about to shut down.
+ * The system prepares for shutdown or suspend.
*/
- POWER_CYCLE_SHUTDOWN,
+ POWER_CYCLE_SHUTDOWN_PREPARE,
/**
- * The system is being suspended.
+ * The system enters shutdown or suspend.
*/
- POWER_CYCLE_SUSPEND,
+ POWER_CYCLE_SHUTDOWN_ENTER,
/**
* The system resumes working.
diff --git a/cpp/watchdog/aidl/android/automotive/watchdog/internal/StateType.aidl b/cpp/watchdog/aidl/android/automotive/watchdog/internal/StateType.aidl
index 16a35a7..4ec001e 100644
--- a/cpp/watchdog/aidl/android/automotive/watchdog/internal/StateType.aidl
+++ b/cpp/watchdog/aidl/android/automotive/watchdog/internal/StateType.aidl
@@ -35,4 +35,9 @@
* Boot phase change.
*/
BOOT_PHASE,
+
+ /**
+ * Garage mode change.
+ */
+ GARAGE_MODE,
}
\ No newline at end of file
diff --git a/cpp/watchdog/server/src/WatchdogInternalHandler.cpp b/cpp/watchdog/server/src/WatchdogInternalHandler.cpp
index 68bb489..6da5fb5 100644
--- a/cpp/watchdog/server/src/WatchdogInternalHandler.cpp
+++ b/cpp/watchdog/server/src/WatchdogInternalHandler.cpp
@@ -21,6 +21,7 @@
#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>
@@ -33,6 +34,7 @@
namespace aawi = ::android::automotive::watchdog::internal;
using aawi::ComponentType;
+using aawi::GarageMode;
using aawi::ICarWatchdogServiceForSystem;
using aawi::PackageResourceOveruseAction;
using aawi::PowerCycle;
@@ -171,6 +173,13 @@
}
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));
@@ -196,19 +205,18 @@
Status WatchdogInternalHandler::handlePowerCycleChange(PowerCycle powerCycle) {
switch (powerCycle) {
- case PowerCycle::POWER_CYCLE_SHUTDOWN:
- ALOGI("Received SHUTDOWN power cycle");
+ 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_SUSPEND:
- ALOGI("Received SUSPEND power cycle");
+ case PowerCycle::POWER_CYCLE_SHUTDOWN_ENTER:
+ ALOGI("Received SHUTDOWN_ENTER power cycle");
mWatchdogProcessService->setEnabled(/*isEnabled=*/false);
- mWatchdogPerfService->setSystemState(SystemState::GARAGE_MODE);
break;
case PowerCycle::POWER_CYCLE_RESUME:
ALOGI("Received RESUME power cycle");
mWatchdogProcessService->setEnabled(/*isEnabled=*/true);
- mWatchdogPerfService->setSystemState(SystemState::NORMAL_MODE);
break;
default:
ALOGW("Unsupported power cycle: %d", powerCycle);
diff --git a/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp b/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp
index 92a4098..efa9eef 100644
--- a/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp
+++ b/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp
@@ -24,6 +24,7 @@
#include <android-base/result.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/IBinder.h>
@@ -41,6 +42,7 @@
namespace aawi = ::android::automotive::watchdog::internal;
+using aawi::GarageMode;
using aawi::ICarWatchdogServiceForSystem;
using aawi::ICarWatchdogServiceForSystemDefault;
using aawi::PackageResourceOveruseAction;
@@ -291,27 +293,27 @@
ASSERT_FALSE(status.isOk()) << status;
}
-TEST_F(WatchdogInternalHandlerTest, TestNotifyPowerCycleChangeToSuspend) {
+TEST_F(WatchdogInternalHandlerTest, TestNotifyPowerCycleChangeToShutdownPrepare) {
setSystemCallingUid();
EXPECT_CALL(*mMockWatchdogProcessService, setEnabled(/*isEnabled=*/false)).Times(1);
- EXPECT_CALL(*mMockWatchdogPerfService, setSystemState(SystemState::GARAGE_MODE)).Times(1);
Status status =
mWatchdogInternalHandler
->notifySystemStateChange(aawi::StateType::POWER_CYCLE,
- static_cast<int32_t>(PowerCycle::POWER_CYCLE_SUSPEND),
+ static_cast<int32_t>(
+ PowerCycle::POWER_CYCLE_SHUTDOWN_PREPARE),
-1);
ASSERT_TRUE(status.isOk()) << status;
}
-TEST_F(WatchdogInternalHandlerTest, TestNotifyPowerCycleChangeToShutdown) {
+TEST_F(WatchdogInternalHandlerTest, TestNotifyPowerCycleChangeToShutdownEnter) {
setSystemCallingUid();
EXPECT_CALL(*mMockWatchdogProcessService, setEnabled(/*isEnabled=*/false)).Times(1);
- EXPECT_CALL(*mMockWatchdogPerfService, setSystemState(_)).Times(0);
- Status status = mWatchdogInternalHandler
- ->notifySystemStateChange(aawi::StateType::POWER_CYCLE,
- static_cast<int32_t>(
- PowerCycle::POWER_CYCLE_SHUTDOWN),
- -1);
+ Status status =
+ mWatchdogInternalHandler
+ ->notifySystemStateChange(aawi::StateType::POWER_CYCLE,
+ static_cast<int32_t>(
+ PowerCycle::POWER_CYCLE_SHUTDOWN_ENTER),
+ -1);
ASSERT_TRUE(status.isOk()) << status;
}
@@ -339,6 +341,28 @@
ASSERT_FALSE(status.isOk()) << status;
}
+TEST_F(WatchdogInternalHandlerTest, TestNotifyGarageModeOn) {
+ setSystemCallingUid();
+ EXPECT_CALL(*mMockWatchdogPerfService, setSystemState(SystemState::GARAGE_MODE)).Times(1);
+ Status status =
+ mWatchdogInternalHandler->notifySystemStateChange(aawi::StateType::GARAGE_MODE,
+ static_cast<int32_t>(
+ GarageMode::GARAGE_MODE_ON),
+ -1);
+ ASSERT_TRUE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogInternalHandlerTest, TestNotifyGarageModeOff) {
+ setSystemCallingUid();
+ EXPECT_CALL(*mMockWatchdogPerfService, setSystemState(SystemState::NORMAL_MODE)).Times(1);
+ Status status =
+ mWatchdogInternalHandler->notifySystemStateChange(aawi::StateType::GARAGE_MODE,
+ static_cast<int32_t>(
+ GarageMode::GARAGE_MODE_OFF),
+ -1);
+ ASSERT_TRUE(status.isOk()) << status;
+}
+
TEST_F(WatchdogInternalHandlerTest, TestNotifyUserStateChange) {
setSystemCallingUid();
aawi::StateType type = aawi::StateType::USER_STATE;
@@ -390,7 +414,8 @@
Status status =
mWatchdogInternalHandler
->notifySystemStateChange(type,
- static_cast<int32_t>(PowerCycle::POWER_CYCLE_SUSPEND),
+ static_cast<int32_t>(
+ PowerCycle::POWER_CYCLE_SHUTDOWN_PREPARE),
-1);
ASSERT_FALSE(status.isOk()) << status;
}
diff --git a/service/src/com/android/car/watchdog/CarWatchdogService.java b/service/src/com/android/car/watchdog/CarWatchdogService.java
index 86858d4..fccaa8b 100644
--- a/service/src/com/android/car/watchdog/CarWatchdogService.java
+++ b/service/src/com/android/car/watchdog/CarWatchdogService.java
@@ -22,6 +22,7 @@
import static com.android.car.CarLog.TAG_WATCHDOG;
import android.annotation.NonNull;
+import android.automotive.watchdog.internal.GarageMode;
import android.automotive.watchdog.internal.ICarWatchdogServiceForSystem;
import android.automotive.watchdog.internal.PackageInfo;
import android.automotive.watchdog.internal.PackageIoOveruseStats;
@@ -39,7 +40,10 @@
import android.car.watchdog.ResourceOveruseConfiguration;
import android.car.watchdog.ResourceOveruseStats;
import android.car.watchdoglib.CarWatchdogDaemonHelper;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.UserInfo;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -68,6 +72,10 @@
public final class CarWatchdogService extends ICarWatchdogService.Stub implements CarServiceBase {
static final boolean DEBUG = false; // STOPSHIP if true
static final String TAG = CarLog.tagFor(CarWatchdogService.class);
+ static final String ACTION_GARAGE_MODE_ON =
+ "com.android.server.jobscheduler.GARAGE_MODE_ON";
+ static final String ACTION_GARAGE_MODE_OFF =
+ "com.android.server.jobscheduler.GARAGE_MODE_OFF";
private final Context mContext;
private final ICarWatchdogServiceForSystemImpl mWatchdogServiceForSystem;
@@ -76,6 +84,35 @@
private final WatchdogPerfHandler mWatchdogPerfHandler;
private final CarWatchdogDaemonHelper mCarWatchdogDaemonHelper;
private final CarWatchdogDaemonHelper.OnConnectionChangeListener mConnectionListener;
+ /*
+ * TODO(b/192481350): Listen for GarageMode change notification rather than depending on the
+ * system_server broadcast when the CarService internal API for listening GarageMode change is
+ * implemented.
+ */
+ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ boolean isGarageMode = false;
+ if (action.equals(ACTION_GARAGE_MODE_ON)) {
+ isGarageMode = true;
+ } else if (!action.equals(ACTION_GARAGE_MODE_OFF)) {
+ return;
+ }
+ try {
+ mCarWatchdogDaemonHelper.notifySystemStateChange(StateType.GARAGE_MODE,
+ isGarageMode ? GarageMode.GARAGE_MODE_ON : GarageMode.GARAGE_MODE_OFF,
+ /* arg2= */ -1);
+ if (DEBUG) {
+ Slogf.d(TAG, "Notified car watchdog daemon of garage mode(%s)",
+ isGarageMode ? "ON" : "OFF");
+ }
+ } catch (RemoteException | RuntimeException e) {
+ Slogf.w(TAG, "Notifying garage mode state change failed: %s", e);
+ }
+ }
+ };
+
private final Object mLock = new Object();
@GuardedBy("mLock")
private boolean mReadyToRespond;
@@ -105,6 +142,7 @@
mWatchdogProcessHandler.init();
subscribePowerCycleChange();
subscribeUserStateChange();
+ subscribeBroadcastReceiver();
mCarWatchdogDaemonHelper.addOnConnectionChangeListener(mConnectionListener);
mCarWatchdogDaemonHelper.connect();
mWatchdogPerfHandler.init();
@@ -119,6 +157,7 @@
@Override
public void release() {
+ mContext.unregisterReceiver(mBroadcastReceiver);
mWatchdogPerfHandler.release();
unregisterFromDaemon();
mCarWatchdogDaemonHelper.disconnect();
@@ -355,8 +394,11 @@
switch (state) {
// SHUTDOWN_PREPARE covers suspend and shutdown.
case CarPowerStateListener.SHUTDOWN_PREPARE:
- powerCycle = PowerCycle.POWER_CYCLE_SUSPEND;
+ powerCycle = PowerCycle.POWER_CYCLE_SHUTDOWN_PREPARE;
break;
+ case CarPowerStateListener.SHUTDOWN_ENTER:
+ case CarPowerStateListener.SUSPEND_ENTER:
+ powerCycle = PowerCycle.POWER_CYCLE_SHUTDOWN_ENTER;
// ON covers resume.
case CarPowerStateListener.ON:
powerCycle = PowerCycle.POWER_CYCLE_RESUME;
@@ -371,10 +413,10 @@
mCarWatchdogDaemonHelper.notifySystemStateChange(StateType.POWER_CYCLE,
powerCycle, /* arg2= */ -1);
if (DEBUG) {
- Slogf.d(TAG, "Notified car watchdog daemon a power cycle(%d)", powerCycle);
+ Slogf.d(TAG, "Notified car watchdog daemon of power cycle(%d)", powerCycle);
}
} catch (RemoteException | RuntimeException e) {
- Slogf.w(TAG, "Notifying system state change failed: %s", e);
+ Slogf.w(TAG, "Notifying power cycle state change failed: %s", e);
}
}
});
@@ -412,11 +454,19 @@
userId, userStateDesc);
}
} catch (RemoteException | RuntimeException e) {
- Slogf.w(TAG, "Notifying system state change failed: %s", e);
+ Slogf.w(TAG, "Notifying user state change failed: %s", e);
}
});
}
+ private void subscribeBroadcastReceiver() {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ACTION_GARAGE_MODE_ON);
+ filter.addAction(ACTION_GARAGE_MODE_OFF);
+
+ mContext.registerReceiverForAllUsers(mBroadcastReceiver, filter, null, null);
+ }
+
private static final class ICarWatchdogServiceForSystemImpl
extends ICarWatchdogServiceForSystem.Stub {
private final WeakReference<CarWatchdogService> mService;
diff --git a/tests/carservice_unit_test/src/android/car/watchdoglib/CarWatchdogDaemonHelperTest.java b/tests/carservice_unit_test/src/android/car/watchdoglib/CarWatchdogDaemonHelperTest.java
index c644f77..c67d3d8 100644
--- a/tests/carservice_unit_test/src/android/car/watchdoglib/CarWatchdogDaemonHelperTest.java
+++ b/tests/carservice_unit_test/src/android/car/watchdoglib/CarWatchdogDaemonHelperTest.java
@@ -153,10 +153,10 @@
@Test
public void testIndirectCall_NotifySystemStateChange() throws Exception {
mCarWatchdogDaemonHelper.notifySystemStateChange(StateType.POWER_CYCLE,
- PowerCycle.POWER_CYCLE_SUSPEND, -1);
+ PowerCycle.POWER_CYCLE_SHUTDOWN_PREPARE, -1);
verify(mFakeCarWatchdog).notifySystemStateChange(StateType.POWER_CYCLE,
- PowerCycle.POWER_CYCLE_SUSPEND, -1);
+ PowerCycle.POWER_CYCLE_SHUTDOWN_PREPARE, -1);
}
@Test
diff --git a/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java b/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java
index 0014d57..b12aa27 100644
--- a/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java
@@ -49,6 +49,7 @@
import android.automotive.watchdog.ResourceType;
import android.automotive.watchdog.internal.ApplicationCategoryType;
import android.automotive.watchdog.internal.ComponentType;
+import android.automotive.watchdog.internal.GarageMode;
import android.automotive.watchdog.internal.ICarWatchdog;
import android.automotive.watchdog.internal.ICarWatchdogServiceForSystem;
import android.automotive.watchdog.internal.PackageIdentifier;
@@ -58,6 +59,7 @@
import android.automotive.watchdog.internal.PackageResourceOveruseAction;
import android.automotive.watchdog.internal.PerStateIoOveruseThreshold;
import android.automotive.watchdog.internal.ResourceSpecificConfiguration;
+import android.automotive.watchdog.internal.StateType;
import android.automotive.watchdog.internal.UidType;
import android.car.test.mocks.AbstractExtendedMockitoTestCase;
import android.car.watchdog.CarWatchdogManager;
@@ -70,7 +72,9 @@
import android.car.watchdog.PerStateBytes;
import android.car.watchdog.ResourceOveruseConfiguration;
import android.car.watchdog.ResourceOveruseStats;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
@@ -128,6 +132,7 @@
private CarWatchdogService mCarWatchdogService;
private ICarWatchdogServiceForSystem mWatchdogServiceForSystemImpl;
private IBinder.DeathRecipient mCarWatchdogDaemonBinderDeathRecipient;
+ private BroadcastReceiver mBroadcastReceiver;
private final SparseArray<String> mPackageNamesByUids = new SparseArray<>();
private final SparseArray<String[]> mSharedPackagesByUids = new SparseArray<>();
private final ArrayMap<String, ApplicationInfo> mApplicationInfosByPackages = new ArrayMap<>();
@@ -153,6 +158,7 @@
setupUsers();
mCarWatchdogService.init();
mWatchdogServiceForSystemImpl = registerCarWatchdogService();
+ captureBroadcastReceiver();
captureDaemonBinderDeathRecipient();
mockPackageManager();
}
@@ -203,6 +209,24 @@
}
@Test
+ public void testGarageModeStateChangeToOn() throws Exception {
+ mBroadcastReceiver.onReceive(mMockContext,
+ new Intent().setAction(CarWatchdogService.ACTION_GARAGE_MODE_ON));
+ verify(mMockCarWatchdogDaemon)
+ .notifySystemStateChange(
+ eq(StateType.GARAGE_MODE), eq(GarageMode.GARAGE_MODE_ON), eq(-1));
+ }
+
+ @Test
+ public void testGarageModeStateChangeToOff() throws Exception {
+ mBroadcastReceiver.onReceive(mMockContext,
+ new Intent().setAction(CarWatchdogService.ACTION_GARAGE_MODE_OFF));
+ verify(mMockCarWatchdogDaemon)
+ .notifySystemStateChange(
+ eq(StateType.GARAGE_MODE), eq(GarageMode.GARAGE_MODE_OFF), eq(-1));
+ }
+
+ @Test
public void testGetResourceOveruseStats() throws Exception {
mPackageNamesByUids.put(Binder.getCallingUid(), mMockContext.getPackageName());
@@ -1255,6 +1279,16 @@
});
}
+ private void captureBroadcastReceiver() {
+ ArgumentCaptor<BroadcastReceiver> receiverArgumentCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ verify(mMockContext)
+ .registerReceiverForAllUsers(receiverArgumentCaptor.capture(), any(), any(), any());
+ mBroadcastReceiver = receiverArgumentCaptor.getValue();
+ assertWithMessage("Broadcast receiver must be non-null").that(mBroadcastReceiver)
+ .isNotEqualTo(null);
+ }
+
private void captureDaemonBinderDeathRecipient() throws Exception {
ArgumentCaptor<IBinder.DeathRecipient> deathRecipientCaptor =
ArgumentCaptor.forClass(IBinder.DeathRecipient.class);