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 package com.android.car.watchdog;
18 
19 import static android.app.StatsManager.PULL_SKIP;
20 import static android.app.StatsManager.PULL_SUCCESS;
21 import static android.car.drivingstate.CarUxRestrictions.UX_RESTRICTIONS_BASELINE;
22 import static android.car.test.mocks.AndroidMockitoHelper.mockAmGetCurrentUser;
23 import static android.car.test.mocks.AndroidMockitoHelper.mockUmGetAllUsers;
24 import static android.car.test.mocks.AndroidMockitoHelper.mockUmGetUserHandles;
25 import static android.car.test.mocks.AndroidMockitoHelper.mockUmIsUserRunning;
26 import static android.car.watchdog.CarWatchdogManager.TIMEOUT_CRITICAL;
27 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
28 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
29 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
30 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
31 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
32 import static android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS;
33 
34 import static com.android.car.CarStatsLog.CAR_WATCHDOG_KILL_STATS_REPORTED__KILL_REASON__KILLED_ON_IO_OVERUSE;
35 import static com.android.car.CarStatsLog.CAR_WATCHDOG_KILL_STATS_REPORTED__SYSTEM_STATE__GARAGE_MODE;
36 import static com.android.car.CarStatsLog.CAR_WATCHDOG_KILL_STATS_REPORTED__SYSTEM_STATE__USER_NO_INTERACTION_MODE;
37 import static com.android.car.CarStatsLog.CAR_WATCHDOG_KILL_STATS_REPORTED__UID_STATE__UNKNOWN_UID_STATE;
38 import static com.android.car.CarStatsLog.CAR_WATCHDOG_SYSTEM_IO_USAGE_SUMMARY;
39 import static com.android.car.CarStatsLog.CAR_WATCHDOG_UID_IO_USAGE_SUMMARY;
40 import static com.android.car.admin.NotificationHelper.RESOURCE_OVERUSE_NOTIFICATION_BASE_ID;
41 import static com.android.car.watchdog.CarWatchdogService.ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION;
42 import static com.android.car.watchdog.CarWatchdogService.ACTION_LAUNCH_APP_SETTINGS;
43 import static com.android.car.watchdog.CarWatchdogService.ACTION_RESOURCE_OVERUSE_DISABLE_APP;
44 import static com.android.car.watchdog.CarWatchdogService.MISSING_ARG_VALUE;
45 import static com.android.car.watchdog.TimeSource.ZONE_OFFSET;
46 import static com.android.car.watchdog.WatchdogPerfHandler.INTENT_EXTRA_ID;
47 import static com.android.car.watchdog.WatchdogPerfHandler.UID_IO_USAGE_SUMMARY_MIN_SYSTEM_TOTAL_WEEKLY_WRITTEN_BYTES;
48 import static com.android.car.watchdog.WatchdogStorage.RETENTION_PERIOD;
49 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
50 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
51 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
52 
53 import static com.google.common.truth.Truth.assertThat;
54 import static com.google.common.truth.Truth.assertWithMessage;
55 
56 import static org.junit.Assert.assertThrows;
57 import static org.mockito.AdditionalMatchers.or;
58 import static org.mockito.ArgumentMatchers.anyBoolean;
59 import static org.mockito.ArgumentMatchers.anyLong;
60 import static org.mockito.Mockito.any;
61 import static org.mockito.Mockito.anyInt;
62 import static org.mockito.Mockito.anyList;
63 import static org.mockito.Mockito.anyString;
64 import static org.mockito.Mockito.atLeastOnce;
65 import static org.mockito.Mockito.eq;
66 import static org.mockito.Mockito.mock;
67 import static org.mockito.Mockito.never;
68 import static org.mockito.Mockito.spy;
69 import static org.mockito.Mockito.timeout;
70 import static org.mockito.Mockito.times;
71 import static org.mockito.Mockito.verifyNoMoreInteractions;
72 import static org.mockito.Mockito.when;
73 
74 import android.app.ActivityManager;
75 import android.app.ActivityThread;
76 import android.app.NotificationManager;
77 import android.app.StatsManager;
78 import android.app.StatsManager.PullAtomMetadata;
79 import android.app.StatsManager.StatsPullAtomCallback;
80 import android.automotive.watchdog.internal.ApplicationCategoryType;
81 import android.automotive.watchdog.internal.ComponentType;
82 import android.automotive.watchdog.internal.GarageMode;
83 import android.automotive.watchdog.internal.ICarWatchdog;
84 import android.automotive.watchdog.internal.ICarWatchdogServiceForSystem;
85 import android.automotive.watchdog.internal.IoUsageStats;
86 import android.automotive.watchdog.internal.PackageIdentifier;
87 import android.automotive.watchdog.internal.PackageInfo;
88 import android.automotive.watchdog.internal.PackageIoOveruseStats;
89 import android.automotive.watchdog.internal.PackageMetadata;
90 import android.automotive.watchdog.internal.PerStateIoOveruseThreshold;
91 import android.automotive.watchdog.internal.PowerCycle;
92 import android.automotive.watchdog.internal.ResourceSpecificConfiguration;
93 import android.automotive.watchdog.internal.StateType;
94 import android.automotive.watchdog.internal.UidType;
95 import android.automotive.watchdog.internal.UserPackageIoUsageStats;
96 import android.automotive.watchdog.internal.UserState;
97 import android.car.drivingstate.CarUxRestrictions;
98 import android.car.drivingstate.ICarUxRestrictionsChangeListener;
99 import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
100 import android.car.hardware.power.CarPowerPolicy;
101 import android.car.hardware.power.ICarPowerPolicyListener;
102 import android.car.hardware.power.ICarPowerStateListener;
103 import android.car.hardware.power.PowerComponent;
104 import android.car.test.mocks.AbstractExtendedMockitoTestCase;
105 import android.car.watchdog.CarWatchdogManager;
106 import android.car.watchdog.ICarWatchdogServiceCallback;
107 import android.car.watchdog.IResourceOveruseListener;
108 import android.car.watchdog.IoOveruseAlertThreshold;
109 import android.car.watchdog.IoOveruseConfiguration;
110 import android.car.watchdog.IoOveruseStats;
111 import android.car.watchdog.PackageKillableState;
112 import android.car.watchdog.PerStateBytes;
113 import android.car.watchdog.ResourceOveruseConfiguration;
114 import android.car.watchdog.ResourceOveruseStats;
115 import android.content.BroadcastReceiver;
116 import android.content.Context;
117 import android.content.Intent;
118 import android.content.pm.ApplicationInfo;
119 import android.content.pm.IPackageManager;
120 import android.content.pm.PackageManager;
121 import android.content.pm.UserInfo;
122 import android.content.res.Resources;
123 import android.os.Binder;
124 import android.os.FileUtils;
125 import android.os.Handler;
126 import android.os.IBinder;
127 import android.os.Looper;
128 import android.os.RemoteException;
129 import android.os.ServiceManager;
130 import android.os.SystemClock;
131 import android.os.UserHandle;
132 import android.os.UserManager;
133 import android.util.ArrayMap;
134 import android.util.ArraySet;
135 import android.util.SparseArray;
136 import android.util.StatsEvent;
137 import android.view.Display;
138 
139 import com.android.car.CarLocalServices;
140 import com.android.car.CarServiceUtils;
141 import com.android.car.CarStatsLog;
142 import com.android.car.CarUxRestrictionsManagerService;
143 import com.android.car.power.CarPowerManagementService;
144 import com.android.car.systeminterface.SystemInterface;
145 
146 import com.google.common.truth.Correspondence;
147 
148 import org.junit.After;
149 import org.junit.Before;
150 import org.junit.Test;
151 import org.junit.runner.RunWith;
152 import org.mockito.ArgumentCaptor;
153 import org.mockito.Captor;
154 import org.mockito.Mock;
155 import org.mockito.junit.MockitoJUnitRunner;
156 
157 import java.io.File;
158 import java.nio.file.Files;
159 import java.time.Instant;
160 import java.time.ZonedDateTime;
161 import java.time.temporal.ChronoField;
162 import java.time.temporal.ChronoUnit;
163 import java.util.ArrayList;
164 import java.util.Arrays;
165 import java.util.Collections;
166 import java.util.Comparator;
167 import java.util.List;
168 import java.util.Map;
169 import java.util.Set;
170 import java.util.concurrent.CountDownLatch;
171 import java.util.concurrent.Executor;
172 import java.util.concurrent.TimeUnit;
173 import java.util.concurrent.atomic.AtomicBoolean;
174 import java.util.function.BiConsumer;
175 
176 /**
177  * <p>This class contains unit tests for the {@link CarWatchdogService}.
178  */
179 @RunWith(MockitoJUnitRunner.class)
180 public final class CarWatchdogServiceUnitTest extends AbstractExtendedMockitoTestCase {
181     private static final String CAR_WATCHDOG_DAEMON_INTERFACE = "carwatchdogd_system";
182     private static final int MAX_WAIT_TIME_MS = 3000;
183     private static final int INVALID_SESSION_ID = -1;
184     private static final int OVERUSE_HANDLING_DELAY_MILLS = 1000;
185     private static final int RECURRING_OVERUSE_TIMES = 2;
186     private static final int RECURRING_OVERUSE_PERIOD_IN_DAYS = 2;
187     private static final int UID_IO_USAGE_SUMMARY_TOP_COUNT = 3;
188     private static final long STATS_DURATION_SECONDS = 3 * 60 * 60;
189     private static final long SYSTEM_DAILY_IO_USAGE_SUMMARY_MULTIPLIER = 10_000;
190 
191     @Mock private Context mMockContext;
192     @Mock private NotificationManager mMockNotificationManager;
193     @Mock private PackageManager mMockPackageManager;
194     @Mock private StatsManager mMockStatsManager;
195     @Mock private UserManager mMockUserManager;
196     @Mock private SystemInterface mMockSystemInterface;
197     @Mock private CarPowerManagementService mMockCarPowerManagementService;
198     @Mock private CarUxRestrictionsManagerService mMockCarUxRestrictionsManagerService;
199     @Mock private Resources mMockResources;
200     @Mock private IBinder mMockBinder;
201     @Mock private ICarWatchdog mMockCarWatchdogDaemon;
202     @Mock private WatchdogStorage mMockWatchdogStorage;
203     @Mock private UserNotificationHelper mMockUserNotificationHelper;
204 
205     @Captor private ArgumentCaptor<ICarPowerStateListener> mICarPowerStateListenerCaptor;
206     @Captor private ArgumentCaptor<ICarPowerPolicyListener> mICarPowerPolicyListenerCaptor;
207     @Captor private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor;
208     @Captor private ArgumentCaptor<ICarUxRestrictionsChangeListener>
209             mICarUxRestrictionsChangeListener;
210     @Captor private ArgumentCaptor<IBinder.DeathRecipient> mDeathRecipientCaptor;
211     @Captor private ArgumentCaptor<ICarWatchdogServiceForSystem>
212             mICarWatchdogServiceForSystemCaptor;
213     @Captor private ArgumentCaptor<List<
214             android.automotive.watchdog.internal.ResourceOveruseConfiguration>>
215             mResourceOveruseConfigurationsCaptor;
216     @Captor private ArgumentCaptor<SparseArray<List<String>>> mPackagesByUserIdCaptor;
217     @Captor private ArgumentCaptor<StatsPullAtomCallback> mStatsPullAtomCallbackCaptor;
218     @Captor private ArgumentCaptor<List<UserNotificationHelper.PackageNotificationInfo>>
219             mPackageNotificationInfosCaptor;
220     @Captor private ArgumentCaptor<UserHandle> mUserHandleCaptor;
221     @Captor private ArgumentCaptor<Intent> mIntentCaptor;
222     @Captor private ArgumentCaptor<int[]> mIntArrayCaptor;
223     @Captor private ArgumentCaptor<byte[]> mOveruseStatsCaptor;
224     @Captor private ArgumentCaptor<byte[]> mKilledStatsCaptor;
225     @Captor private ArgumentCaptor<Integer> mOverusingUidCaptor;
226     @Captor private ArgumentCaptor<Integer> mKilledUidCaptor;
227     @Captor private ArgumentCaptor<Integer> mUidStateCaptor;
228     @Captor private ArgumentCaptor<Integer> mSystemStateCaptor;
229     @Captor private ArgumentCaptor<Integer> mKillReasonCaptor;
230 
231     private CarWatchdogService mCarWatchdogService;
232     private ICarWatchdogServiceForSystem mWatchdogServiceForSystemImpl;
233     private IBinder.DeathRecipient mCarWatchdogDaemonBinderDeathRecipient;
234     private BroadcastReceiver mBroadcastReceiver;
235     private boolean mIsDaemonCrashed;
236     private ICarPowerStateListener mCarPowerStateListener;
237     private ICarPowerPolicyListener mCarPowerPolicyListener;
238     private ICarUxRestrictionsChangeListener mCarUxRestrictionsChangeListener;
239     private StatsPullAtomCallback mStatsPullAtomCallback;
240     private File mTempSystemCarDir;
241 
242     private final TestTimeSource mTimeSource = new TestTimeSource();
243     private final SparseArray<String> mGenericPackageNameByUid = new SparseArray<>();
244     private final SparseArray<List<String>> mPackagesBySharedUid = new SparseArray<>();
245     private final ArrayMap<String, android.content.pm.PackageInfo> mPmPackageInfoByUserPackage =
246             new ArrayMap<>();
247     private final ArraySet<String> mDisabledUserPackages = new ArraySet<>();
248     private final List<WatchdogStorage.UserPackageSettingsEntry> mUserPackageSettingsEntries =
249             new ArrayList<>();
250     private final List<WatchdogStorage.IoUsageStatsEntry> mIoUsageStatsEntries = new ArrayList<>();
251     private final List<AtomsProto.CarWatchdogSystemIoUsageSummary> mPulledSystemIoUsageSummaries =
252             new ArrayList<>();
253     private final List<AtomsProto.CarWatchdogUidIoUsageSummary> mPulledUidIoUsageSummaries =
254             new ArrayList<>();
255     private final IPackageManager mSpiedPackageManager = spy(ActivityThread.getPackageManager());
256 
257     @Override
onSessionBuilder(CustomMockitoSessionBuilder builder)258     protected void onSessionBuilder(CustomMockitoSessionBuilder builder) {
259         builder
260             .spyStatic(ServiceManager.class)
261             .spyStatic(Binder.class)
262             .spyStatic(ActivityManager.class)
263             .spyStatic(ActivityThread.class)
264             .spyStatic(CarLocalServices.class)
265             .spyStatic(CarStatsLog.class);
266     }
267 
268     /**
269      * Initialize all of the objects with the @Mock annotation.
270      */
271     @Before
setUp()272     public void setUp() throws Exception {
273         when(mMockContext.getSystemService(NotificationManager.class))
274                 .thenReturn(mMockNotificationManager);
275         when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
276         when(mMockContext.getSystemService(StatsManager.class)).thenReturn(mMockStatsManager);
277         when(mMockContext.getPackageName()).thenReturn(
278                 CarWatchdogServiceUnitTest.class.getCanonicalName());
279         when(mMockContext.getResources()).thenReturn(mMockResources);
280         when(mMockResources.getInteger(
281                 eq(com.android.car.R.integer.recurringResourceOverusePeriodInDays)))
282                 .thenReturn(RECURRING_OVERUSE_PERIOD_IN_DAYS);
283         when(mMockResources.getInteger(
284                 eq(com.android.car.R.integer.recurringResourceOveruseTimes)))
285                 .thenReturn(RECURRING_OVERUSE_TIMES);
286         doReturn(mMockSystemInterface)
287                 .when(() -> CarLocalServices.getService(SystemInterface.class));
288         doReturn(mMockCarPowerManagementService)
289                 .when(() -> CarLocalServices.getService(CarPowerManagementService.class));
290         doReturn(mMockCarUxRestrictionsManagerService)
291                 .when(() -> CarLocalServices.getService(CarUxRestrictionsManagerService.class));
292         doReturn(mSpiedPackageManager).when(() -> ActivityThread.getPackageManager());
293 
294         when(mMockCarUxRestrictionsManagerService.getCurrentUxRestrictions())
295                 .thenReturn(new CarUxRestrictions.Builder(/* reqOpt= */ false,
296                         UX_RESTRICTIONS_BASELINE, /* time= */ 0).build());
297 
298         mTempSystemCarDir = Files.createTempDirectory("watchdog_test").toFile();
299         when(mMockSystemInterface.getSystemCarDir()).thenReturn(mTempSystemCarDir);
300 
301         setupUsers();
302         mockWatchdogDaemon();
303         mockWatchdogStorage();
304         mockPackageManager();
305         mockBuildStatsEventCalls();
306 
307         mCarWatchdogService = new CarWatchdogService(mMockContext, mMockWatchdogStorage,
308                 mMockUserNotificationHelper, mTimeSource);
309         initService(/* wantedInvocations= */ 1);
310     }
311 
312     /**
313      * Releases resources.
314      */
315     @After
tearDown()316     public void tearDown() throws Exception {
317         if (mIsDaemonCrashed) {
318             /* Note: On daemon crash, CarWatchdogService retries daemon connection on the main
319              * thread. This retry outlives the test and impacts other test runs. Thus always call
320              * restartWatchdogDaemonAndAwait after crashing the daemon and before completing
321              * teardown.
322              */
323             restartWatchdogDaemonAndAwait();
324         }
325         if (mTempSystemCarDir != null) {
326             FileUtils.deleteContentsAndDir(mTempSystemCarDir);
327         }
328     }
329 
330     @Test
testCarWatchdogServiceHealthCheck()331     public void testCarWatchdogServiceHealthCheck() throws Exception {
332         mWatchdogServiceForSystemImpl.checkIfAlive(123456, TIMEOUT_CRITICAL);
333         verify(mMockCarWatchdogDaemon,
334                 timeout(MAX_WAIT_TIME_MS)).tellCarWatchdogServiceAlive(
335                 eq(mWatchdogServiceForSystemImpl), any(int[].class), eq(123456));
336     }
337 
338     @Test
testRegisterClient()339     public void testRegisterClient() throws Exception {
340         TestClient client = new TestClient();
341         mCarWatchdogService.registerClient(client, TIMEOUT_CRITICAL);
342         mWatchdogServiceForSystemImpl.checkIfAlive(123456, TIMEOUT_CRITICAL);
343         // Checking client health is asynchronous, so wait at most 1 second.
344         int repeat = 10;
345         while (repeat > 0) {
346             int sessionId = client.getLastSessionId();
347             if (sessionId != INVALID_SESSION_ID) {
348                 return;
349             }
350             SystemClock.sleep(100L);
351             repeat--;
352         }
353         assertThat(client.getLastSessionId()).isNotEqualTo(INVALID_SESSION_ID);
354     }
355 
356     @Test
testUnregisterUnregisteredClient()357     public void testUnregisterUnregisteredClient() throws Exception {
358         TestClient client = new TestClient();
359         mCarWatchdogService.registerClient(client, TIMEOUT_CRITICAL);
360         mCarWatchdogService.unregisterClient(client);
361         mWatchdogServiceForSystemImpl.checkIfAlive(123456, TIMEOUT_CRITICAL);
362         assertThat(client.getLastSessionId()).isEqualTo(INVALID_SESSION_ID);
363     }
364 
365     @Test
testGoodClientHealthCheck()366     public void testGoodClientHealthCheck() throws Exception {
367         testClientHealthCheck(new TestClient(), 0);
368     }
369 
370     @Test
testBadClientHealthCheck()371     public void testBadClientHealthCheck() throws Exception {
372         testClientHealthCheck(new BadTestClient(), 1);
373     }
374 
375     @Test
testGarageModeStateChangeToOn()376     public void testGarageModeStateChangeToOn() throws Exception {
377         mBroadcastReceiver.onReceive(mMockContext,
378                 new Intent().setAction(CarWatchdogService.ACTION_GARAGE_MODE_ON));
379         verify(mMockCarWatchdogDaemon).notifySystemStateChange(StateType.GARAGE_MODE,
380                 GarageMode.GARAGE_MODE_ON, MISSING_ARG_VALUE);
381         verify(mMockWatchdogStorage).shrinkDatabase();
382     }
383 
384     @Test
testGarageModeStateChangeToOff()385     public void testGarageModeStateChangeToOff() throws Exception {
386         mBroadcastReceiver.onReceive(mMockContext,
387                 new Intent().setAction(CarWatchdogService.ACTION_GARAGE_MODE_OFF));
388         // GARAGE_MODE_OFF is notified twice: Once during the initial daemon connect and once when
389         // the ACTION_GARAGE_MODE_OFF intent is received.
390         verify(mMockCarWatchdogDaemon, times(2)).notifySystemStateChange(StateType.GARAGE_MODE,
391                 GarageMode.GARAGE_MODE_OFF, MISSING_ARG_VALUE);
392         verify(mMockWatchdogStorage, never()).shrinkDatabase();
393     }
394 
395     @Test
testWatchdogDaemonRestart()396     public void testWatchdogDaemonRestart() throws Exception {
397         crashWatchdogDaemon();
398 
399         mockUmGetAllUsers(mMockUserManager, new UserInfo(101, "", 0), new UserInfo(102, "", 0));
400         mockUmIsUserRunning(mMockUserManager, /* userId= */ 101, /* isRunning= */ false);
401         mockUmIsUserRunning(mMockUserManager, /* userId= */ 102, /* isRunning= */ true);
402         setCarPowerState(CarPowerStateListener.SHUTDOWN_ENTER);
403         mBroadcastReceiver.onReceive(mMockContext,
404                 new Intent().setAction(CarWatchdogService.ACTION_GARAGE_MODE_ON));
405 
406         restartWatchdogDaemonAndAwait();
407 
408         verify(mMockCarWatchdogDaemon).notifySystemStateChange(StateType.USER_STATE, 101,
409                 UserState.USER_STATE_STOPPED);
410         verify(mMockCarWatchdogDaemon).notifySystemStateChange(StateType.USER_STATE, 102,
411                 UserState.USER_STATE_STARTED);
412         verify(mMockCarWatchdogDaemon).notifySystemStateChange(StateType.POWER_CYCLE,
413                 PowerCycle.POWER_CYCLE_SHUTDOWN_ENTER, MISSING_ARG_VALUE);
414         verify(mMockCarWatchdogDaemon).notifySystemStateChange(StateType.GARAGE_MODE,
415                 GarageMode.GARAGE_MODE_ON, MISSING_ARG_VALUE);
416     }
417 
418     @Test
testUserRemovedBroadcast()419     public void testUserRemovedBroadcast() throws Exception {
420         mockUmGetUserHandles(mMockUserManager, /* excludeDying= */ true, 101, 102);
421         mBroadcastReceiver.onReceive(mMockContext,
422                 new Intent().setAction(Intent.ACTION_USER_REMOVED)
423                         .putExtra(Intent.EXTRA_USER, UserHandle.of(100)));
424         verify(mMockCarWatchdogDaemon).notifySystemStateChange(StateType.USER_STATE, 100,
425                 UserState.USER_STATE_REMOVED);
426         verify(mMockWatchdogStorage).syncUsers(new int[] {101, 102});
427     }
428 
429     @Test
testDisableAppBroadcast()430     public void testDisableAppBroadcast() throws Exception {
431         String packageName = "system_package";
432         UserHandle userHandle = UserHandle.of(100);
433         int id = 150;
434 
435         mBroadcastReceiver.onReceive(mMockContext, new Intent(ACTION_RESOURCE_OVERUSE_DISABLE_APP)
436                 .putExtra(Intent.EXTRA_PACKAGE_NAME, packageName)
437                 .putExtra(Intent.EXTRA_USER, userHandle)
438                 .putExtra(INTENT_EXTRA_ID, id));
439 
440         verify(mSpiedPackageManager).getApplicationEnabledSetting(packageName,
441                 userHandle.getIdentifier());
442 
443         verify(mSpiedPackageManager).setApplicationEnabledSetting(eq(packageName),
444                 eq(COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED), eq(0),
445                 eq(userHandle.getIdentifier()), anyString());
446 
447         verify(mMockNotificationManager).cancelAsUser(CarWatchdogService.TAG, id, userHandle);
448 
449         verifyNoMoreInteractions(mSpiedPackageManager);
450         verifyNoMoreInteractions(mMockNotificationManager);
451     }
452 
453     @Test
testDisableAppBroadcastWithDisabledPackage()454     public void testDisableAppBroadcastWithDisabledPackage() throws Exception {
455         String packageName = "system_package";
456         UserHandle userHandle = UserHandle.of(100);
457 
458         doReturn(COMPONENT_ENABLED_STATE_DISABLED).when(mSpiedPackageManager)
459                 .getApplicationEnabledSetting(packageName, userHandle.getIdentifier());
460 
461         mBroadcastReceiver.onReceive(mMockContext, new Intent(ACTION_RESOURCE_OVERUSE_DISABLE_APP)
462                 .putExtra(Intent.EXTRA_PACKAGE_NAME, packageName)
463                 .putExtra(Intent.EXTRA_USER, userHandle)
464                 .putExtra(INTENT_EXTRA_ID, RESOURCE_OVERUSE_NOTIFICATION_BASE_ID));
465 
466         verify(mSpiedPackageManager).getApplicationEnabledSetting(packageName,
467                 userHandle.getIdentifier());
468 
469         verify(mMockNotificationManager).cancelAsUser(CarWatchdogService.TAG,
470                 RESOURCE_OVERUSE_NOTIFICATION_BASE_ID, userHandle);
471 
472         verifyNoMoreInteractions(mSpiedPackageManager);
473         verifyNoMoreInteractions(mMockNotificationManager);
474     }
475 
476     @Test
testLaunchAppSettingsBroadcast()477     public void testLaunchAppSettingsBroadcast() throws Exception {
478         String packageName = "system_package";
479         UserHandle userHandle = UserHandle.of(100);
480 
481         mBroadcastReceiver.onReceive(mMockContext, new Intent(ACTION_LAUNCH_APP_SETTINGS)
482                 .putExtra(Intent.EXTRA_PACKAGE_NAME, packageName)
483                 .putExtra(Intent.EXTRA_USER, userHandle)
484                 .putExtra(INTENT_EXTRA_ID, RESOURCE_OVERUSE_NOTIFICATION_BASE_ID));
485 
486         verify(mMockContext).startActivityAsUser(mIntentCaptor.capture(), eq(userHandle));
487 
488         Intent actualIntent = mIntentCaptor.getValue();
489 
490         assertWithMessage("Launch app settings intent action").that(actualIntent.getAction())
491                 .isEqualTo(ACTION_APPLICATION_DETAILS_SETTINGS);
492 
493         assertWithMessage("Launch app settings intent data string")
494                 .that(actualIntent.getDataString()).contains(packageName);
495 
496         assertWithMessage("Launch app settings intent flags")
497                 .that(actualIntent.getFlags())
498                 .isEqualTo(FLAG_ACTIVITY_CLEAR_TASK | FLAG_ACTIVITY_NEW_TASK);
499 
500         verify(mMockNotificationManager).cancelAsUser(CarWatchdogService.TAG,
501                 RESOURCE_OVERUSE_NOTIFICATION_BASE_ID, userHandle);
502 
503         verifyNoMoreInteractions(mSpiedPackageManager);
504         verifyNoMoreInteractions(mMockNotificationManager);
505     }
506 
507     @Test
testDismissUserNotificationBroadcast()508     public void testDismissUserNotificationBroadcast() throws Exception {
509         String packageName = "system_package";
510         UserHandle userHandle = UserHandle.of(100);
511 
512         mBroadcastReceiver.onReceive(mMockContext,
513                 new Intent(ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION)
514                         .putExtra(Intent.EXTRA_PACKAGE_NAME, packageName)
515                         .putExtra(Intent.EXTRA_USER, userHandle)
516                         .putExtra(INTENT_EXTRA_ID, RESOURCE_OVERUSE_NOTIFICATION_BASE_ID));
517 
518         verify(mMockNotificationManager).cancelAsUser(CarWatchdogService.TAG,
519                 RESOURCE_OVERUSE_NOTIFICATION_BASE_ID, userHandle);
520 
521         verifyNoMoreInteractions(mSpiedPackageManager);
522         verifyNoMoreInteractions(mMockNotificationManager);
523     }
524 
525     @Test
testUserNotificationActionBroadcastsWithNullPackageName()526     public void testUserNotificationActionBroadcastsWithNullPackageName() throws Exception {
527         List<String> actions = Arrays.asList(ACTION_RESOURCE_OVERUSE_DISABLE_APP,
528                 ACTION_LAUNCH_APP_SETTINGS, ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION);
529 
530         for (String action : actions) {
531             mBroadcastReceiver.onReceive(mMockContext, new Intent(action)
532                     .putExtra(Intent.EXTRA_USER, UserHandle.of(100))
533                     .putExtra(INTENT_EXTRA_ID, RESOURCE_OVERUSE_NOTIFICATION_BASE_ID));
534         }
535 
536         verify(mMockContext, never()).startActivityAsUser(any(), any());
537         verifyNoMoreInteractions(mSpiedPackageManager);
538         verifyNoMoreInteractions(mMockNotificationManager);
539     }
540 
541     @Test
testUserNotificationActionBroadcastsWithInvalidUserId()542     public void testUserNotificationActionBroadcastsWithInvalidUserId() throws Exception {
543         List<String> actions = Arrays.asList(ACTION_RESOURCE_OVERUSE_DISABLE_APP,
544                 ACTION_LAUNCH_APP_SETTINGS, ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION);
545 
546         for (String action : actions) {
547             mBroadcastReceiver.onReceive(mMockContext, new Intent(action)
548                     .putExtra(Intent.EXTRA_PACKAGE_NAME, "system_package")
549                     .putExtra(Intent.EXTRA_USER, UserHandle.of(-1))
550                     .putExtra(INTENT_EXTRA_ID, RESOURCE_OVERUSE_NOTIFICATION_BASE_ID));
551         }
552 
553         verify(mMockContext, never()).startActivityAsUser(any(), any());
554         verifyNoMoreInteractions(mSpiedPackageManager);
555         verifyNoMoreInteractions(mMockNotificationManager);
556     }
557 
558     @Test
testUserNotificationActionBroadcastsWithMissingNotificationId()559     public void testUserNotificationActionBroadcastsWithMissingNotificationId() throws Exception {
560         String packageName = "system_package";
561         UserHandle userHandle = UserHandle.of(100);
562 
563         List<String> actions = Arrays.asList(ACTION_RESOURCE_OVERUSE_DISABLE_APP,
564                 ACTION_LAUNCH_APP_SETTINGS, ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION);
565 
566         for (String action : actions) {
567             mBroadcastReceiver.onReceive(mMockContext, new Intent(action)
568                     .putExtra(Intent.EXTRA_PACKAGE_NAME, packageName)
569                     .putExtra(Intent.EXTRA_USER, userHandle));
570         }
571 
572         verify(mSpiedPackageManager).getApplicationEnabledSetting(packageName,
573                 userHandle.getIdentifier());
574 
575         verify(mSpiedPackageManager).setApplicationEnabledSetting(eq(packageName),
576                 eq(COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED), eq(0),
577                 eq(userHandle.getIdentifier()), anyString());
578 
579         verify(mMockContext).startActivityAsUser(any(), any());
580 
581         verifyNoMoreInteractions(mSpiedPackageManager);
582         verifyNoMoreInteractions(mMockNotificationManager);
583     }
584 
585     @Test
testGetResourceOveruseStats()586     public void testGetResourceOveruseStats() throws Exception {
587         int uid = Binder.getCallingUid();
588         injectPackageInfos(Collections.singletonList(
589                 constructPackageManagerPackageInfo(
590                         mMockContext.getPackageName(), uid, null, ApplicationInfo.FLAG_SYSTEM, 0)));
591 
592         SparseArray<PackageIoOveruseStats> packageIoOveruseStatsByUid =
593                 injectIoOveruseStatsForPackages(
594                         mGenericPackageNameByUid, /* killablePackages= */ new ArraySet<>(),
595                         /* shouldNotifyPackages= */ new ArraySet<>());
596 
597         ResourceOveruseStats expectedStats =
598                 constructResourceOveruseStats(uid, mMockContext.getPackageName(),
599                         packageIoOveruseStatsByUid.get(uid).ioOveruseStats);
600 
601         ResourceOveruseStats actualStats = mCarWatchdogService.getResourceOveruseStats(
602                 CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
603                 CarWatchdogManager.STATS_PERIOD_CURRENT_DAY);
604 
605         ResourceOveruseStatsSubject.assertEquals(actualStats, expectedStats);
606 
607         verifyNoMoreInteractions(mMockWatchdogStorage);
608     }
609 
610     @Test
testGetResourceOveruseStatsForPast7days()611     public void testGetResourceOveruseStatsForPast7days() throws Exception {
612         int uid = Binder.getCallingUid();
613         String packageName = mMockContext.getPackageName();
614         injectPackageInfos(Collections.singletonList(constructPackageManagerPackageInfo(
615                 packageName, uid, null, ApplicationInfo.FLAG_SYSTEM, 0)));
616 
617         long startTime = mTimeSource.getCurrentDateTime().minusDays(4).toEpochSecond();
618         long duration = mTimeSource.now().getEpochSecond() - startTime;
619         when(mMockWatchdogStorage.getHistoricalIoOveruseStats(
620                 UserHandle.getUserId(uid), packageName, 6))
621                 .thenReturn(new IoOveruseStats.Builder(startTime, duration).setTotalOveruses(5)
622                         .setTotalTimesKilled(2).setTotalBytesWritten(24_000).build());
623 
624         injectIoOveruseStatsForPackages(mGenericPackageNameByUid,
625                 /* killablePackages= */ Collections.singleton(packageName),
626                 /* shouldNotifyPackages= */ new ArraySet<>());
627 
628         ResourceOveruseStats actualStats = mCarWatchdogService.getResourceOveruseStats(
629                 CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
630                 CarWatchdogManager.STATS_PERIOD_PAST_7_DAYS);
631 
632         IoOveruseStats ioOveruseStats =
633                 new IoOveruseStats.Builder(startTime, duration + STATS_DURATION_SECONDS)
634                         .setKillableOnOveruse(true).setTotalOveruses(8).setTotalBytesWritten(24_600)
635                         .setTotalTimesKilled(2)
636                         .setRemainingWriteBytes(new PerStateBytes(20, 20, 20)).build();
637 
638         ResourceOveruseStats expectedStats =
639                 new ResourceOveruseStats.Builder(packageName, UserHandle.getUserHandleForUid(uid))
640                         .setIoOveruseStats(ioOveruseStats).build();
641 
642         ResourceOveruseStatsSubject.assertEquals(actualStats, expectedStats);
643     }
644 
645     @Test
testGetResourceOveruseStatsForPast7daysWithNoHistory()646     public void testGetResourceOveruseStatsForPast7daysWithNoHistory() throws Exception {
647         int uid = Binder.getCallingUid();
648         String packageName = mMockContext.getPackageName();
649         injectPackageInfos(Collections.singletonList(constructPackageManagerPackageInfo(
650                 packageName, uid, null, ApplicationInfo.FLAG_SYSTEM, 0)));
651 
652         when(mMockWatchdogStorage.getHistoricalIoOveruseStats(
653                 UserHandle.getUserId(uid), packageName, 6)).thenReturn(null);
654 
655         injectIoOveruseStatsForPackages(mGenericPackageNameByUid,
656                 /* killablePackages= */ Collections.singleton(packageName),
657                 /* shouldNotifyPackages= */ new ArraySet<>());
658 
659         ResourceOveruseStats actualStats = mCarWatchdogService.getResourceOveruseStats(
660                 CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
661                 CarWatchdogManager.STATS_PERIOD_PAST_7_DAYS);
662 
663         ResourceOveruseStats expectedStats =
664                 new ResourceOveruseStats.Builder(packageName, UserHandle.getUserHandleForUid(uid))
665                         .setIoOveruseStats(new IoOveruseStats.Builder(
666                                 mTimeSource.now().getEpochSecond(), STATS_DURATION_SECONDS)
667                                 .setKillableOnOveruse(true).setTotalOveruses(3)
668                                 .setTotalBytesWritten(600)
669                                 .setRemainingWriteBytes(new PerStateBytes(20, 20, 20)).build())
670                         .build();
671 
672         ResourceOveruseStatsSubject.assertEquals(actualStats, expectedStats);
673     }
674 
675     @Test
testGetResourceOveruseStatsForPast7daysWithNoCurrentStats()676     public void testGetResourceOveruseStatsForPast7daysWithNoCurrentStats() throws Exception {
677         int uid = Binder.getCallingUid();
678         String packageName = mMockContext.getPackageName();
679         injectPackageInfos(Collections.singletonList(constructPackageManagerPackageInfo(
680                 packageName, uid, null, ApplicationInfo.FLAG_SYSTEM, 0)));
681 
682         long startTime = mTimeSource.getCurrentDateTime().minusDays(4).toEpochSecond();
683         long duration = mTimeSource.now().getEpochSecond() - startTime;
684         when(mMockWatchdogStorage.getHistoricalIoOveruseStats(
685                 UserHandle.getUserId(uid), packageName, 6))
686                 .thenReturn(new IoOveruseStats.Builder(startTime, duration).setTotalOveruses(5)
687                         .setTotalTimesKilled(2).setTotalBytesWritten(24_000).build());
688 
689         ResourceOveruseStats actualStats = mCarWatchdogService.getResourceOveruseStats(
690                 CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
691                 CarWatchdogManager.STATS_PERIOD_PAST_7_DAYS);
692 
693         ResourceOveruseStats expectedStats =
694                 new ResourceOveruseStats.Builder(packageName, UserHandle.getUserHandleForUid(uid))
695                 .build();
696 
697         ResourceOveruseStatsSubject.assertEquals(actualStats, expectedStats);
698     }
699 
700     @Test
testGetResourceOveruseStatsForSharedUid()701     public void testGetResourceOveruseStatsForSharedUid() throws Exception {
702         int sharedUid = Binder.getCallingUid();
703         injectPackageInfos(Collections.singletonList(
704                 constructPackageManagerPackageInfo(
705                         mMockContext.getPackageName(), sharedUid, "system_shared_package",
706                         ApplicationInfo.FLAG_SYSTEM, 0)));
707 
708         SparseArray<PackageIoOveruseStats> packageIoOveruseStatsByUid =
709                 injectIoOveruseStatsForPackages(
710                         mGenericPackageNameByUid, /* killablePackages= */ new ArraySet<>(),
711                         /* shouldNotifyPackages= */ new ArraySet<>());
712 
713         ResourceOveruseStats expectedStats =
714                 constructResourceOveruseStats(sharedUid, "shared:system_shared_package",
715                         packageIoOveruseStatsByUid.get(sharedUid).ioOveruseStats);
716 
717         ResourceOveruseStats actualStats = mCarWatchdogService.getResourceOveruseStats(
718                 CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
719                 CarWatchdogManager.STATS_PERIOD_CURRENT_DAY);
720 
721         ResourceOveruseStatsSubject.assertEquals(actualStats, expectedStats);
722     }
723 
724     @Test
testFailsGetResourceOveruseStatsWithInvalidArgs()725     public void testFailsGetResourceOveruseStatsWithInvalidArgs() throws Exception {
726         assertThrows(IllegalArgumentException.class,
727                 () -> mCarWatchdogService.getResourceOveruseStats(/* resourceOveruseFlag= */ 0,
728                         CarWatchdogManager.STATS_PERIOD_CURRENT_DAY));
729 
730         assertThrows(IllegalArgumentException.class,
731                 () -> mCarWatchdogService.getResourceOveruseStats(
732                         CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO, /* maxStatsPeriod= */ 0));
733     }
734 
735     @Test
testGetAllResourceOveruseStatsWithNoMinimum()736     public void testGetAllResourceOveruseStatsWithNoMinimum() throws Exception {
737         injectPackageInfos(Arrays.asList(
738                 constructPackageManagerPackageInfo("third_party_package", 1103456, null),
739                 constructPackageManagerPackageInfo("vendor_package.critical", 1201278, null)));
740 
741         List<PackageIoOveruseStats> packageIoOveruseStats = Arrays.asList(
742                 constructPackageIoOveruseStats(1103456,
743                         /* shouldNotify= */ true,
744                         /* forgivenWriteBytes= */ constructPerStateBytes(100, 200, 300),
745                         constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
746                                 /* remainingWriteBytes= */ constructPerStateBytes(0, 0, 0),
747                                 /* writtenBytes= */ constructPerStateBytes(100, 200, 300),
748                                 /* totalOveruses= */ 3)),
749                 constructPackageIoOveruseStats(1201278,
750                         /* shouldNotify= */ false,
751                         /* forgivenWriteBytes= */ constructPerStateBytes(5000, 6000, 9000),
752                         constructInternalIoOveruseStats(/* killableOnOveruse= */ false,
753                                 /* remainingWriteBytes= */ constructPerStateBytes(450, 120, 340),
754                                 /* writtenBytes= */ constructPerStateBytes(5000, 6000, 9000),
755                                 /* totalOveruses= */ 3)));
756         pushLatestIoOveruseStatsAndWait(packageIoOveruseStats);
757 
758         List<ResourceOveruseStats> expectedStats = Arrays.asList(
759                 constructResourceOveruseStats(1103456, "third_party_package",
760                         packageIoOveruseStats.get(0).ioOveruseStats),
761                 constructResourceOveruseStats(1201278, "vendor_package.critical",
762                         packageIoOveruseStats.get(1).ioOveruseStats));
763 
764         List<ResourceOveruseStats> actualStats = mCarWatchdogService.getAllResourceOveruseStats(
765                 CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO, /* minimumStatsFlag= */ 0,
766                 CarWatchdogManager.STATS_PERIOD_CURRENT_DAY);
767 
768         ResourceOveruseStatsSubject.assertThat(actualStats)
769                 .containsExactlyElementsIn(expectedStats);
770 
771         verifyNoMoreInteractions(mMockWatchdogStorage);
772     }
773 
774     @Test
testGetAllResourceOveruseStatsWithNoMinimumForPast7days()775     public void testGetAllResourceOveruseStatsWithNoMinimumForPast7days() throws Exception {
776         injectPackageInfos(Arrays.asList(
777                 constructPackageManagerPackageInfo("third_party_package", 1103456, null),
778                 constructPackageManagerPackageInfo("vendor_package.critical", 1201278, null)));
779 
780         List<PackageIoOveruseStats> packageIoOveruseStats = Arrays.asList(
781                 constructPackageIoOveruseStats(1103456,
782                         /* shouldNotify= */ true,
783                         /* forgivenWriteBytes= */ constructPerStateBytes(100, 200, 300),
784                         constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
785                                 /* remainingWriteBytes= */ constructPerStateBytes(0, 0, 0),
786                                 /* writtenBytes= */ constructPerStateBytes(100, 200, 300),
787                                 /* totalOveruses= */ 3)),
788                 constructPackageIoOveruseStats(1201278,
789                         /* shouldNotify= */ false,
790                         /* forgivenWriteBytes= */ constructPerStateBytes(0, 0, 0),
791                         constructInternalIoOveruseStats(/* killableOnOveruse= */ false,
792                                 /* remainingWriteBytes= */ constructPerStateBytes(450, 120, 340),
793                                 /* writtenBytes= */ constructPerStateBytes(5000, 6000, 9000),
794                                 /* totalOveruses= */ 0)));
795         pushLatestIoOveruseStatsAndWait(packageIoOveruseStats);
796 
797         ZonedDateTime now = mTimeSource.getCurrentDateTime();
798         long startTime = now.minusDays(4).toEpochSecond();
799         IoOveruseStats thirdPartyPkgOldStats = new IoOveruseStats.Builder(
800                 startTime, now.toEpochSecond() - startTime).setTotalOveruses(5)
801                 .setTotalTimesKilled(2).setTotalBytesWritten(24_000).build();
802         when(mMockWatchdogStorage.getHistoricalIoOveruseStats(11, "third_party_package", 6))
803                 .thenReturn(thirdPartyPkgOldStats);
804 
805         startTime = now.minusDays(6).toEpochSecond();
806         IoOveruseStats vendorPkgOldStats = new IoOveruseStats.Builder(
807                 startTime, now.toEpochSecond() - startTime).setTotalOveruses(2)
808                 .setTotalTimesKilled(0).setTotalBytesWritten(35_000).build();
809         when(mMockWatchdogStorage.getHistoricalIoOveruseStats(12, "vendor_package.critical", 6))
810                 .thenReturn(vendorPkgOldStats);
811 
812 
813         List<ResourceOveruseStats> actualStats = mCarWatchdogService.getAllResourceOveruseStats(
814                 CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO, /* minimumStatsFlag= */ 0,
815                 CarWatchdogManager.STATS_PERIOD_PAST_7_DAYS);
816 
817         IoOveruseStats thirdPartyIoStats = new IoOveruseStats.Builder(
818                 thirdPartyPkgOldStats.getStartTime(),
819                 thirdPartyPkgOldStats.getDurationInSeconds() + STATS_DURATION_SECONDS)
820                 .setKillableOnOveruse(true).setTotalOveruses(8).setTotalBytesWritten(24_600)
821                 .setTotalTimesKilled(2).setRemainingWriteBytes(new PerStateBytes(0, 0, 0))
822                 .build();
823         IoOveruseStats vendorIoStats = new IoOveruseStats.Builder(
824                 vendorPkgOldStats.getStartTime(),
825                 vendorPkgOldStats.getDurationInSeconds() + STATS_DURATION_SECONDS)
826                 .setKillableOnOveruse(false).setTotalOveruses(2).setTotalBytesWritten(55_000)
827                 .setTotalTimesKilled(0).setRemainingWriteBytes(new PerStateBytes(450, 120, 340))
828                 .build();
829 
830         List<ResourceOveruseStats> expectedStats = Arrays.asList(
831                 new ResourceOveruseStats.Builder("third_party_package", new UserHandle(11))
832                         .setIoOveruseStats(thirdPartyIoStats).build(),
833                 new ResourceOveruseStats.Builder("vendor_package.critical", new UserHandle(12))
834                         .setIoOveruseStats(vendorIoStats).build());
835 
836         ResourceOveruseStatsSubject.assertThat(actualStats)
837                 .containsExactlyElementsIn(expectedStats);
838     }
839 
840     @Test
testGetAllResourceOveruseStatsForSharedPackage()841     public void testGetAllResourceOveruseStatsForSharedPackage() throws Exception {
842         injectPackageInfos(Arrays.asList(
843                 constructPackageManagerPackageInfo(
844                         "vendor_package.A", 1103456, "vendor_shared_package"),
845                 constructPackageManagerPackageInfo(
846                         "third_party_package.B", 1103456, "vendor_shared_package"),
847                 constructPackageManagerPackageInfo(
848                         "system_package.C", 1201000, "system_shared_package"),
849                 constructPackageManagerPackageInfo(
850                         "system_package.D", 1201000, "system_shared_package"),
851                 constructPackageManagerPackageInfo(
852                         "third_party_package.A", 1303456, "vendor_shared_package"),
853                 constructPackageManagerPackageInfo(
854                         "vendor_package.B", 1303456, "vendor_shared_package")));
855 
856         List<PackageIoOveruseStats> packageIoOveruseStats = Arrays.asList(
857                 constructPackageIoOveruseStats(1103456,
858                         /* shouldNotify= */ false,
859                         /* forgivenWriteBytes= */ constructPerStateBytes(50, 100, 150),
860                         constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
861                                 /* remainingWriteBytes= */ constructPerStateBytes(20, 20, 20),
862                                 /* writtenBytes= */ constructPerStateBytes(100, 200, 300),
863                                 /* totalOveruses= */ 3)),
864                 constructPackageIoOveruseStats(1201000,
865                         /* shouldNotify= */ false,
866                         /* forgivenWriteBytes= */ constructPerStateBytes(0, 0, 0),
867                         constructInternalIoOveruseStats(/* killableOnOveruse= */ false,
868                                 /* remainingWriteBytes= */ constructPerStateBytes(450, 120, 340),
869                                 /* writtenBytes= */ constructPerStateBytes(5000, 6000, 9000),
870                                 /* totalOveruses= */ 0)),
871                 constructPackageIoOveruseStats(1303456,
872                         /* shouldNotify= */ true,
873                         /* forgivenWriteBytes= */ constructPerStateBytes(80, 170, 260),
874                         constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
875                                 /* remainingWriteBytes= */ constructPerStateBytes(0, 0, 0),
876                                 /* writtenBytes= */ constructPerStateBytes(80, 170, 260),
877                                 /* totalOveruses= */ 1)));
878 
879         pushLatestIoOveruseStatsAndWait(packageIoOveruseStats);
880 
881         List<ResourceOveruseStats> expectedStats = Arrays.asList(
882                 constructResourceOveruseStats(1103456, "shared:vendor_shared_package",
883                         packageIoOveruseStats.get(0).ioOveruseStats),
884                 constructResourceOveruseStats(1201278, "shared:system_shared_package",
885                         packageIoOveruseStats.get(1).ioOveruseStats),
886                 constructResourceOveruseStats(1303456, "shared:vendor_shared_package",
887                         packageIoOveruseStats.get(2).ioOveruseStats));
888 
889         List<ResourceOveruseStats> actualStats = mCarWatchdogService.getAllResourceOveruseStats(
890                 CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO, /* minimumStatsFlag= */ 0,
891                 CarWatchdogManager.STATS_PERIOD_CURRENT_DAY);
892 
893         ResourceOveruseStatsSubject.assertThat(actualStats)
894                 .containsExactlyElementsIn(expectedStats);
895 
896         verifyNoMoreInteractions(mMockWatchdogStorage);
897     }
898 
899     @Test
testFailsGetAllResourceOveruseStatsWithInvalidArgs()900     public void testFailsGetAllResourceOveruseStatsWithInvalidArgs() throws Exception {
901         assertThrows(IllegalArgumentException.class,
902                 () -> mCarWatchdogService.getAllResourceOveruseStats(0, /* minimumStatsFlag= */ 0,
903                         CarWatchdogManager.STATS_PERIOD_CURRENT_DAY));
904 
905         assertThrows(IllegalArgumentException.class,
906                 () -> mCarWatchdogService.getAllResourceOveruseStats(
907                         CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
908                         CarWatchdogManager.FLAG_MINIMUM_STATS_IO_1_MB
909                                 | CarWatchdogManager.FLAG_MINIMUM_STATS_IO_100_MB,
910                         CarWatchdogManager.STATS_PERIOD_CURRENT_DAY));
911 
912         assertThrows(IllegalArgumentException.class,
913                 () -> mCarWatchdogService.getAllResourceOveruseStats(
914                         CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO, /* minimumStatsFlag= */ 1 << 5,
915                         CarWatchdogManager.STATS_PERIOD_CURRENT_DAY));
916 
917         assertThrows(IllegalArgumentException.class,
918                 () -> mCarWatchdogService.getAllResourceOveruseStats(
919                         CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO, /* minimumStatsFlag= */ 0,
920                         /* maxStatsPeriod= */ 0));
921     }
922 
923     @Test
testGetAllResourceOveruseStatsWithMinimum()924     public void testGetAllResourceOveruseStatsWithMinimum() throws Exception {
925         injectPackageInfos(Arrays.asList(
926                 constructPackageManagerPackageInfo("third_party_package", 1103456, null),
927                 constructPackageManagerPackageInfo("vendor_package.critical", 1201278, null)));
928 
929         List<PackageIoOveruseStats> packageIoOveruseStats = Arrays.asList(
930                 constructPackageIoOveruseStats(1103456, /* shouldNotify= */ false,
931                         /* forgivenWriteBytes= */ constructPerStateBytes(80, 170, 260),
932                         constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
933                                 /* remainingWriteBytes= */ constructPerStateBytes(20, 20, 20),
934                                 /* writtenBytes= */ constructPerStateBytes(100, 200, 300),
935                                 /* totalOveruses= */ 3)),
936                 constructPackageIoOveruseStats(1201278, /* shouldNotify= */ false,
937                         /* forgivenWriteBytes= */ constructPerStateBytes(5_070_000, 4500, 7000),
938                         constructInternalIoOveruseStats(/* killableOnOveruse= */ false,
939                                 /* remainingWriteBytes= */ constructPerStateBytes(450, 120, 340),
940                                 /* writtenBytes= */ constructPerStateBytes(7_000_000, 6000, 9000),
941                                 /* totalOveruses= */ 3)));
942         pushLatestIoOveruseStatsAndWait(packageIoOveruseStats);
943 
944         List<ResourceOveruseStats> expectedStats = Collections.singletonList(
945                 constructResourceOveruseStats(1201278, "vendor_package.critical",
946                         packageIoOveruseStats.get(1).ioOveruseStats));
947 
948         List<ResourceOveruseStats> actualStats = mCarWatchdogService.getAllResourceOveruseStats(
949                 CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
950                 CarWatchdogManager.FLAG_MINIMUM_STATS_IO_1_MB,
951                 CarWatchdogManager.STATS_PERIOD_CURRENT_DAY);
952 
953         ResourceOveruseStatsSubject.assertThat(actualStats)
954                 .containsExactlyElementsIn(expectedStats);
955 
956         verifyNoMoreInteractions(mMockWatchdogStorage);
957     }
958 
959     @Test
testGetAllResourceOveruseStatsWithMinimumForPast7days()960     public void testGetAllResourceOveruseStatsWithMinimumForPast7days() throws Exception {
961         injectPackageInfos(Arrays.asList(
962                 constructPackageManagerPackageInfo("third_party_package", 1103456, null),
963                 constructPackageManagerPackageInfo("vendor_package.critical", 1201278, null)));
964 
965         List<PackageIoOveruseStats> packageIoOveruseStats = Arrays.asList(
966                 constructPackageIoOveruseStats(1103456,
967                         /* shouldNotify= */ true,
968                         /* forgivenWriteBytes= */ constructPerStateBytes(80, 170, 260),
969                         constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
970                                 /* remainingWriteBytes= */ constructPerStateBytes(20, 20, 20),
971                                 /* writtenBytes= */ constructPerStateBytes(100, 200, 300),
972                                 /* totalOveruses= */ 3)),
973                 constructPackageIoOveruseStats(1201278,
974                         /* shouldNotify= */ false,
975                         /* forgivenWriteBytes= */ constructPerStateBytes(0, 0, 0),
976                         constructInternalIoOveruseStats(/* killableOnOveruse= */ false,
977                                 /* remainingWriteBytes= */ constructPerStateBytes(450, 120, 340),
978                                 /* writtenBytes= */ constructPerStateBytes(100_000, 6000, 9000),
979                                 /* totalOveruses= */ 0)));
980         pushLatestIoOveruseStatsAndWait(packageIoOveruseStats);
981 
982         ZonedDateTime now = mTimeSource.getCurrentDateTime();
983         long startTime = now.minusDays(4).toEpochSecond();
984         IoOveruseStats thirdPartyPkgOldStats = new IoOveruseStats.Builder(
985                 startTime, now.toEpochSecond() - startTime).setTotalOveruses(5)
986                 .setTotalTimesKilled(2).setTotalBytesWritten(24_000).build();
987         when(mMockWatchdogStorage.getHistoricalIoOveruseStats(11, "third_party_package", 6))
988                 .thenReturn(thirdPartyPkgOldStats);
989 
990         startTime = now.minusDays(6).toEpochSecond();
991         IoOveruseStats vendorPkgOldStats = new IoOveruseStats.Builder(
992                 startTime, now.toEpochSecond() - startTime).setTotalOveruses(2)
993                 .setTotalTimesKilled(0).setTotalBytesWritten(6_900_000).build();
994         when(mMockWatchdogStorage.getHistoricalIoOveruseStats(12, "vendor_package.critical", 6))
995                 .thenReturn(vendorPkgOldStats);
996 
997         List<ResourceOveruseStats> actualStats = mCarWatchdogService.getAllResourceOveruseStats(
998                 CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
999                 CarWatchdogManager.FLAG_MINIMUM_STATS_IO_1_MB,
1000                 CarWatchdogManager.STATS_PERIOD_PAST_7_DAYS);
1001 
1002         IoOveruseStats vendorIoStats = new IoOveruseStats.Builder(
1003                 vendorPkgOldStats.getStartTime(),
1004                 vendorPkgOldStats.getDurationInSeconds() + STATS_DURATION_SECONDS)
1005                 .setKillableOnOveruse(false).setTotalOveruses(2).setTotalBytesWritten(7_015_000)
1006                 .setTotalTimesKilled(0).setRemainingWriteBytes(new PerStateBytes(450, 120, 340))
1007                 .build();
1008 
1009         List<ResourceOveruseStats> expectedStats = Collections.singletonList(
1010                 new ResourceOveruseStats.Builder("vendor_package.critical", new UserHandle(12))
1011                         .setIoOveruseStats(vendorIoStats).build());
1012 
1013         ResourceOveruseStatsSubject.assertThat(actualStats)
1014                 .containsExactlyElementsIn(expectedStats);
1015     }
1016 
1017     @Test
testGetResourceOveruseStatsForUserPackage()1018     public void testGetResourceOveruseStatsForUserPackage() throws Exception {
1019         injectPackageInfos(Arrays.asList(
1020                 constructPackageManagerPackageInfo("third_party_package", 1103456, null),
1021                 constructPackageManagerPackageInfo("vendor_package.critical", 1201278, null)));
1022 
1023         List<PackageIoOveruseStats> packageIoOveruseStats = Arrays.asList(
1024                 constructPackageIoOveruseStats(1103456,
1025                         /* shouldNotify= */ false,
1026                         /* forgivenWriteBytes= */ constructPerStateBytes(80, 170, 260),
1027                         constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
1028                                 /* remainingWriteBytes= */ constructPerStateBytes(20, 20, 20),
1029                                 /* writtenBytes= */ constructPerStateBytes(100, 200, 300),
1030                                 /* totalOveruses= */ 3)),
1031                 constructPackageIoOveruseStats(1201278,
1032                         /* shouldNotify= */ false,
1033                         /* forgivenWriteBytes= */ constructPerStateBytes(300, 400, 700),
1034                         constructInternalIoOveruseStats(/* killableOnOveruse= */ false,
1035                                 /* remainingWriteBytes= */ constructPerStateBytes(450, 120, 340),
1036                                 /* writtenBytes= */ constructPerStateBytes(500, 600, 900),
1037                                 /* totalOveruses= */ 3)));
1038         pushLatestIoOveruseStatsAndWait(packageIoOveruseStats);
1039 
1040         ResourceOveruseStats expectedStats =
1041                 constructResourceOveruseStats(1201278, "vendor_package.critical",
1042                         packageIoOveruseStats.get(1).ioOveruseStats);
1043 
1044         ResourceOveruseStats actualStats =
1045                 mCarWatchdogService.getResourceOveruseStatsForUserPackage(
1046                         "vendor_package.critical", new UserHandle(12),
1047                         CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
1048                         CarWatchdogManager.STATS_PERIOD_CURRENT_DAY);
1049 
1050         ResourceOveruseStatsSubject.assertEquals(actualStats, expectedStats);
1051     }
1052 
1053     @Test
testGetResourceOveruseStatsForUserPackageForPast7days()1054     public void testGetResourceOveruseStatsForUserPackageForPast7days() throws Exception {
1055         injectPackageInfos(Arrays.asList(
1056                 constructPackageManagerPackageInfo("third_party_package", 1103456, null),
1057                 constructPackageManagerPackageInfo("vendor_package.critical", 1201278, null)));
1058 
1059         List<PackageIoOveruseStats> packageIoOveruseStats = Arrays.asList(
1060                 constructPackageIoOveruseStats(1103456,
1061                         /* shouldNotify= */ false,
1062                         /* forgivenWriteBytes= */ constructPerStateBytes(80, 170, 260),
1063                         constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
1064                                 /* remainingWriteBytes= */ constructPerStateBytes(20, 20, 20),
1065                                 /* writtenBytes= */ constructPerStateBytes(100, 200, 300),
1066                                 /* totalOveruses= */ 3)),
1067                 constructPackageIoOveruseStats(1201278,
1068                         /* shouldNotify= */ false,
1069                         /* forgivenWriteBytes= */ constructPerStateBytes(300, 400, 700),
1070                         constructInternalIoOveruseStats(/* killableOnOveruse= */ false,
1071                                 /* remainingWriteBytes= */ constructPerStateBytes(450, 120, 340),
1072                                 /* writtenBytes= */ constructPerStateBytes(500, 600, 900),
1073                                 /* totalOveruses= */ 3)));
1074         pushLatestIoOveruseStatsAndWait(packageIoOveruseStats);
1075 
1076         ZonedDateTime now = mTimeSource.getCurrentDateTime();
1077         long startTime = now.minusDays(4).toEpochSecond();
1078         IoOveruseStats vendorPkgOldStats = new IoOveruseStats.Builder(
1079                 startTime, now.toEpochSecond() - startTime).setTotalOveruses(2)
1080                 .setTotalTimesKilled(0).setTotalBytesWritten(6_900_000).build();
1081         when(mMockWatchdogStorage.getHistoricalIoOveruseStats(12, "vendor_package.critical", 6))
1082                 .thenReturn(vendorPkgOldStats);
1083 
1084         ResourceOveruseStats actualStats =
1085                 mCarWatchdogService.getResourceOveruseStatsForUserPackage(
1086                         "vendor_package.critical", new UserHandle(12),
1087                         CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
1088                         CarWatchdogManager.STATS_PERIOD_PAST_7_DAYS);
1089 
1090         IoOveruseStats vendorIoStats = new IoOveruseStats.Builder(
1091                 vendorPkgOldStats.getStartTime(),
1092                 vendorPkgOldStats.getDurationInSeconds() + STATS_DURATION_SECONDS)
1093                 .setKillableOnOveruse(false).setTotalOveruses(5).setTotalBytesWritten(6_902_000)
1094                 .setTotalTimesKilled(0).setRemainingWriteBytes(new PerStateBytes(450, 120, 340))
1095                 .build();
1096 
1097         ResourceOveruseStats expectedStats = new ResourceOveruseStats.Builder(
1098                 "vendor_package.critical", new UserHandle(12)).setIoOveruseStats(vendorIoStats)
1099                 .build();
1100 
1101         ResourceOveruseStatsSubject.assertEquals(actualStats, expectedStats);
1102     }
1103 
1104     @Test
testGetResourceOveruseStatsForUserPackageWithSharedUids()1105     public void testGetResourceOveruseStatsForUserPackageWithSharedUids() throws Exception {
1106         injectPackageInfos(Arrays.asList(
1107                 constructPackageManagerPackageInfo(
1108                         "third_party_package", 1103456, "vendor_shared_package"),
1109                 constructPackageManagerPackageInfo(
1110                         "vendor_package", 1103456, "vendor_shared_package"),
1111                 constructPackageManagerPackageInfo("system_package", 1101100,
1112                         "shared_system_package")));
1113 
1114         SparseArray<PackageIoOveruseStats> packageIoOveruseStatsByUid =
1115                 injectIoOveruseStatsForPackages(
1116                         mGenericPackageNameByUid, /* killablePackages= */ new ArraySet<>(
1117                                 Collections.singleton("shared:vendor_shared_package")),
1118                         /* shouldNotifyPackages= */ new ArraySet<>());
1119 
1120         ResourceOveruseStats expectedStats =
1121                 constructResourceOveruseStats(1103456, "shared:vendor_shared_package",
1122                         packageIoOveruseStatsByUid.get(1103456).ioOveruseStats);
1123 
1124         ResourceOveruseStats actualStats =
1125                 mCarWatchdogService.getResourceOveruseStatsForUserPackage(
1126                         "vendor_package", new UserHandle(11),
1127                         CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
1128                         CarWatchdogManager.STATS_PERIOD_CURRENT_DAY);
1129 
1130         ResourceOveruseStatsSubject.assertEquals(actualStats, expectedStats);
1131     }
1132 
1133     @Test
testFailsGetResourceOveruseStatsForUserPackageWithInvalidArgs()1134     public void testFailsGetResourceOveruseStatsForUserPackageWithInvalidArgs() throws Exception {
1135         assertThrows(NullPointerException.class,
1136                 () -> mCarWatchdogService.getResourceOveruseStatsForUserPackage(
1137                         /* packageName= */ null, new UserHandle(10),
1138                         CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
1139                         CarWatchdogManager.STATS_PERIOD_CURRENT_DAY));
1140 
1141         assertThrows(NullPointerException.class,
1142                 () -> mCarWatchdogService.getResourceOveruseStatsForUserPackage("some.package",
1143                         /* userHandle= */ null, CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
1144                         CarWatchdogManager.STATS_PERIOD_CURRENT_DAY));
1145 
1146         assertThrows(IllegalArgumentException.class,
1147                 () -> mCarWatchdogService.getResourceOveruseStatsForUserPackage("some.package",
1148                         UserHandle.ALL, CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
1149                         CarWatchdogManager.STATS_PERIOD_CURRENT_DAY));
1150 
1151         assertThrows(IllegalArgumentException.class,
1152                 () -> mCarWatchdogService.getResourceOveruseStatsForUserPackage("some.package",
1153                         new UserHandle(10), /* resourceOveruseFlag= */ 0,
1154                         CarWatchdogManager.STATS_PERIOD_CURRENT_DAY));
1155 
1156         assertThrows(IllegalArgumentException.class,
1157                 () -> mCarWatchdogService.getResourceOveruseStatsForUserPackage("some.package",
1158                         new UserHandle(10), CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
1159                         /* maxStatsPeriod= */ 0));
1160     }
1161 
1162     @Test
testAddResourceOveruseListenerThrowsWithInvalidFlag()1163     public void testAddResourceOveruseListenerThrowsWithInvalidFlag() throws Exception {
1164         IResourceOveruseListener mockListener = createMockResourceOveruseListener();
1165         assertThrows(IllegalArgumentException.class, () -> {
1166             mCarWatchdogService.addResourceOveruseListener(0, mockListener);
1167         });
1168     }
1169 
1170     @Test
testResourceOveruseListener()1171     public void testResourceOveruseListener() throws Exception {
1172         mGenericPackageNameByUid.put(Binder.getCallingUid(), mMockContext.getPackageName());
1173 
1174         IResourceOveruseListener mockListener = createMockResourceOveruseListener();
1175         IBinder mockBinder = mockListener.asBinder();
1176 
1177         mCarWatchdogService.addResourceOveruseListener(CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
1178                 mockListener);
1179 
1180         verify(mockBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
1181 
1182         injectIoOveruseStatsForPackages(
1183                 mGenericPackageNameByUid, /* killablePackages= */ new ArraySet<>(),
1184                 /* shouldNotifyPackages= */ new ArraySet<>(
1185                         Collections.singleton(mMockContext.getPackageName())));
1186 
1187         verify(mockListener).onOveruse(any());
1188 
1189         mCarWatchdogService.removeResourceOveruseListener(mockListener);
1190 
1191         verify(mockListener, atLeastOnce()).asBinder();
1192         verify(mockBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
1193 
1194         injectIoOveruseStatsForPackages(
1195                 mGenericPackageNameByUid, /* killablePackages= */ new ArraySet<>(),
1196                 /* shouldNotifyPackages= */ new ArraySet<>(
1197                         Collections.singletonList(mMockContext.getPackageName())));
1198 
1199         verifyNoMoreInteractions(mockListener);
1200     }
1201 
1202     @Test
testDuplicateAddResourceOveruseListener()1203     public void testDuplicateAddResourceOveruseListener() throws Exception {
1204         mGenericPackageNameByUid.put(Binder.getCallingUid(), mMockContext.getPackageName());
1205 
1206         IResourceOveruseListener mockListener = createMockResourceOveruseListener();
1207         IBinder mockBinder = mockListener.asBinder();
1208 
1209         mCarWatchdogService.addResourceOveruseListener(CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
1210                 mockListener);
1211 
1212         assertThrows(IllegalStateException.class,
1213                 () -> mCarWatchdogService.addResourceOveruseListener(
1214                         CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO, mockListener));
1215 
1216         verify(mockBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
1217 
1218         mCarWatchdogService.removeResourceOveruseListener(mockListener);
1219 
1220         verify(mockListener, atLeastOnce()).asBinder();
1221         verify(mockBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
1222 
1223         verifyNoMoreInteractions(mockListener);
1224     }
1225 
1226     @Test
testAddMultipleResourceOveruseListeners()1227     public void testAddMultipleResourceOveruseListeners() throws Exception {
1228         mGenericPackageNameByUid.put(Binder.getCallingUid(), mMockContext.getPackageName());
1229 
1230         IResourceOveruseListener firstMockListener = createMockResourceOveruseListener();
1231         IBinder firstMockBinder = firstMockListener.asBinder();
1232         IResourceOveruseListener secondMockListener = createMockResourceOveruseListener();
1233         IBinder secondMockBinder = secondMockListener.asBinder();
1234 
1235         mCarWatchdogService.addResourceOveruseListener(CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
1236                 firstMockListener);
1237         mCarWatchdogService.addResourceOveruseListener(CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
1238                 secondMockListener);
1239 
1240         verify(firstMockBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
1241         verify(secondMockBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
1242 
1243         injectIoOveruseStatsForPackages(
1244                 mGenericPackageNameByUid, /* killablePackages= */ new ArraySet<>(),
1245                 /* shouldNotifyPackages= */ new ArraySet<>(
1246                         Collections.singleton(mMockContext.getPackageName())));
1247 
1248         verify(firstMockListener).onOveruse(any());
1249 
1250         mCarWatchdogService.removeResourceOveruseListener(firstMockListener);
1251 
1252         verify(firstMockListener, atLeastOnce()).asBinder();
1253         verify(firstMockBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
1254 
1255         injectIoOveruseStatsForPackages(
1256                 mGenericPackageNameByUid, /* killablePackages= */ new ArraySet<>(),
1257                 /* shouldNotifyPackages= */ new ArraySet<>(
1258                         Collections.singletonList(mMockContext.getPackageName())));
1259 
1260         verify(secondMockListener, times(2)).onOveruse(any());
1261 
1262         mCarWatchdogService.removeResourceOveruseListener(secondMockListener);
1263 
1264         verify(secondMockListener, atLeastOnce()).asBinder();
1265         verify(secondMockBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
1266 
1267         injectIoOveruseStatsForPackages(
1268                 mGenericPackageNameByUid, /* killablePackages= */ new ArraySet<>(),
1269                 /* shouldNotifyPackages= */ new ArraySet<>(
1270                         Collections.singletonList(mMockContext.getPackageName())));
1271 
1272         verifyNoMoreInteractions(firstMockListener);
1273         verifyNoMoreInteractions(secondMockListener);
1274     }
1275 
1276     @Test
testAddResourceOveruseListenerForSystemThrowsWithInvalidFlag()1277     public void testAddResourceOveruseListenerForSystemThrowsWithInvalidFlag() throws Exception {
1278         IResourceOveruseListener mockListener = createMockResourceOveruseListener();
1279         assertThrows(IllegalArgumentException.class, () -> {
1280             mCarWatchdogService.addResourceOveruseListenerForSystem(0, mockListener);
1281         });
1282     }
1283 
1284     @Test
testResourceOveruseListenerForSystem()1285     public void testResourceOveruseListenerForSystem() throws Exception {
1286         int callingUid = Binder.getCallingUid();
1287         mGenericPackageNameByUid.put(callingUid, "system_package.critical");
1288 
1289         IResourceOveruseListener mockListener = createMockResourceOveruseListener();
1290         mCarWatchdogService.addResourceOveruseListenerForSystem(
1291                 CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO, mockListener);
1292 
1293         IBinder mockBinder = mockListener.asBinder();
1294         verify(mockBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
1295 
1296         List<PackageIoOveruseStats> packageIoOveruseStats = Collections.singletonList(
1297                 constructPackageIoOveruseStats(callingUid, /* shouldNotify= */ true,
1298                         /* forgivenWriteBytes= */ constructPerStateBytes(80, 170, 260),
1299                         constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
1300                                 /* remainingWriteBytes= */ constructPerStateBytes(20, 20, 20),
1301                                 /* writtenBytes= */ constructPerStateBytes(100, 200, 300),
1302                                 /* totalOveruses= */ 3)));
1303 
1304         pushLatestIoOveruseStatsAndWait(packageIoOveruseStats);
1305 
1306         verify(mockListener).onOveruse(any());
1307 
1308         mCarWatchdogService.removeResourceOveruseListenerForSystem(mockListener);
1309 
1310         verify(mockListener, atLeastOnce()).asBinder();
1311         verify(mockBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
1312 
1313         pushLatestIoOveruseStatsAndWait(packageIoOveruseStats);
1314 
1315         verifyNoMoreInteractions(mockListener);
1316     }
1317 
1318     @Test
testSetKillablePackageAsUser()1319     public void testSetKillablePackageAsUser() throws Exception {
1320         mockUmGetUserHandles(mMockUserManager, /* excludeDying= */ true, 11, 12);
1321         injectPackageInfos(Arrays.asList(
1322                 constructPackageManagerPackageInfo("third_party_package", 1103456, null),
1323                 constructPackageManagerPackageInfo("vendor_package.critical", 1101278, null),
1324                 constructPackageManagerPackageInfo("third_party_package", 1203456, null),
1325                 constructPackageManagerPackageInfo("vendor_package.critical", 1201278, null)));
1326 
1327         UserHandle userHandle = new UserHandle(11);
1328         mCarWatchdogService.setKillablePackageAsUser("third_party_package", userHandle,
1329                 /* isKillable= */ false);
1330         mCarWatchdogService.setKillablePackageAsUser("vendor_package.critical",
1331                 userHandle, /* isKillable= */ false);
1332 
1333         PackageKillableStateSubject.assertThat(
1334                 mCarWatchdogService.getPackageKillableStatesAsUser(UserHandle.ALL)).containsExactly(
1335                 new PackageKillableState("third_party_package", 11,
1336                         PackageKillableState.KILLABLE_STATE_NO),
1337                 new PackageKillableState("vendor_package.critical", 11,
1338                         PackageKillableState.KILLABLE_STATE_NEVER),
1339                 new PackageKillableState("third_party_package", 12,
1340                         PackageKillableState.KILLABLE_STATE_YES),
1341                 new PackageKillableState("vendor_package.critical", 12,
1342                         PackageKillableState.KILLABLE_STATE_NEVER));
1343 
1344         assertThrows(IllegalArgumentException.class,
1345                 () -> mCarWatchdogService.setKillablePackageAsUser("vendor_package.critical",
1346                         userHandle, /* isKillable= */ true));
1347 
1348         mockUmGetUserHandles(mMockUserManager, /* excludeDying= */ true, 11, 12, 13);
1349         injectPackageInfos(Collections.singletonList(
1350                 constructPackageManagerPackageInfo("third_party_package", 1303456, null)));
1351 
1352         PackageKillableStateSubject.assertThat(
1353                 mCarWatchdogService.getPackageKillableStatesAsUser(UserHandle.ALL)).containsExactly(
1354                 new PackageKillableState("third_party_package", 11,
1355                         PackageKillableState.KILLABLE_STATE_NO),
1356                 new PackageKillableState("vendor_package.critical", 11,
1357                         PackageKillableState.KILLABLE_STATE_NEVER),
1358                 new PackageKillableState("third_party_package", 12,
1359                         PackageKillableState.KILLABLE_STATE_YES),
1360                 new PackageKillableState("vendor_package.critical", 12,
1361                         PackageKillableState.KILLABLE_STATE_NEVER),
1362                 new PackageKillableState("third_party_package", 13,
1363                         PackageKillableState.KILLABLE_STATE_YES));
1364     }
1365 
1366     @Test
testSetKillablePackageAsUserWithSharedUids()1367     public void testSetKillablePackageAsUserWithSharedUids() throws Exception {
1368         mockUmGetUserHandles(mMockUserManager, /* excludeDying= */ true, 11, 12);
1369         injectPackageInfos(Arrays.asList(
1370                 constructPackageManagerPackageInfo(
1371                         "third_party_package.A", 1103456, "third_party_shared_package.A"),
1372                 constructPackageManagerPackageInfo(
1373                         "third_party_package.B", 1103456, "third_party_shared_package.A"),
1374                 constructPackageManagerPackageInfo(
1375                         "third_party_package.C", 1101356, "third_party_shared_package.B"),
1376                 constructPackageManagerPackageInfo(
1377                         "third_party_package.D", 1101356, "third_party_shared_package.B")));
1378 
1379         UserHandle userHandle = new UserHandle(11);
1380         mCarWatchdogService.setKillablePackageAsUser("third_party_package.A", userHandle,
1381                 /* isKillable= */ false);
1382 
1383         PackageKillableStateSubject.assertThat(
1384                 mCarWatchdogService.getPackageKillableStatesAsUser(UserHandle.ALL)).containsExactly(
1385                 new PackageKillableState("third_party_package.A", 11,
1386                         PackageKillableState.KILLABLE_STATE_NO),
1387                 new PackageKillableState("third_party_package.B", 11,
1388                         PackageKillableState.KILLABLE_STATE_NO),
1389                 new PackageKillableState("third_party_package.C", 11,
1390                         PackageKillableState.KILLABLE_STATE_YES),
1391                 new PackageKillableState("third_party_package.D", 11,
1392                         PackageKillableState.KILLABLE_STATE_YES));
1393 
1394         mCarWatchdogService.setKillablePackageAsUser("third_party_package.B", userHandle,
1395                 /* isKillable= */ true);
1396         mCarWatchdogService.setKillablePackageAsUser("third_party_package.C", userHandle,
1397                 /* isKillable= */ false);
1398 
1399         PackageKillableStateSubject.assertThat(
1400                 mCarWatchdogService.getPackageKillableStatesAsUser(UserHandle.ALL)).containsExactly(
1401                 new PackageKillableState("third_party_package.A", 11,
1402                         PackageKillableState.KILLABLE_STATE_YES),
1403                 new PackageKillableState("third_party_package.B", 11,
1404                         PackageKillableState.KILLABLE_STATE_YES),
1405                 new PackageKillableState("third_party_package.C", 11,
1406                         PackageKillableState.KILLABLE_STATE_NO),
1407                 new PackageKillableState("third_party_package.D", 11,
1408                         PackageKillableState.KILLABLE_STATE_NO));
1409     }
1410 
1411     @Test
testSetKillablePackageAsUserForAllUsers()1412     public void testSetKillablePackageAsUserForAllUsers() throws Exception {
1413         mockUmGetUserHandles(mMockUserManager, /* excludeDying= */ true, 11, 12);
1414         injectPackageInfos(Arrays.asList(
1415                 constructPackageManagerPackageInfo("third_party_package", 1103456, null),
1416                 constructPackageManagerPackageInfo("vendor_package.critical", 1101278, null),
1417                 constructPackageManagerPackageInfo("third_party_package", 1203456, null),
1418                 constructPackageManagerPackageInfo("vendor_package.critical", 1201278, null)));
1419 
1420         mCarWatchdogService.setKillablePackageAsUser("third_party_package", UserHandle.ALL,
1421                 /* isKillable= */ false);
1422         mCarWatchdogService.setKillablePackageAsUser("vendor_package.critical",
1423                 UserHandle.ALL, /* isKillable= */ false);
1424 
1425         PackageKillableStateSubject.assertThat(
1426                 mCarWatchdogService.getPackageKillableStatesAsUser(UserHandle.ALL)).containsExactly(
1427                 new PackageKillableState("third_party_package", 11,
1428                         PackageKillableState.KILLABLE_STATE_NO),
1429                 new PackageKillableState("vendor_package.critical", 11,
1430                         PackageKillableState.KILLABLE_STATE_NEVER),
1431                 new PackageKillableState("third_party_package", 12,
1432                         PackageKillableState.KILLABLE_STATE_NO),
1433                 new PackageKillableState("vendor_package.critical", 12,
1434                         PackageKillableState.KILLABLE_STATE_NEVER));
1435 
1436         assertThrows(IllegalArgumentException.class,
1437                 () -> mCarWatchdogService.setKillablePackageAsUser("vendor_package.critical",
1438                         UserHandle.ALL, /* isKillable= */ true));
1439 
1440         mockUmGetUserHandles(mMockUserManager, /* excludeDying= */ true, 11, 12, 13);
1441         injectPackageInfos(Collections.singletonList(
1442                 constructPackageManagerPackageInfo("third_party_package", 1303456, null)));
1443 
1444         PackageKillableStateSubject.assertThat(
1445                 mCarWatchdogService.getPackageKillableStatesAsUser(UserHandle.ALL)).containsExactly(
1446                 new PackageKillableState("third_party_package", 11,
1447                         PackageKillableState.KILLABLE_STATE_NO),
1448                 new PackageKillableState("vendor_package.critical", 11,
1449                         PackageKillableState.KILLABLE_STATE_NEVER),
1450                 new PackageKillableState("third_party_package", 12,
1451                         PackageKillableState.KILLABLE_STATE_NO),
1452                 new PackageKillableState("vendor_package.critical", 12,
1453                         PackageKillableState.KILLABLE_STATE_NEVER),
1454                 new PackageKillableState("third_party_package", 13,
1455                         PackageKillableState.KILLABLE_STATE_NO));
1456     }
1457 
1458     @Test
testSetKillablePackageAsUsersForAllUsersWithSharedUids()1459     public void testSetKillablePackageAsUsersForAllUsersWithSharedUids() throws Exception {
1460         mockUmGetUserHandles(mMockUserManager, /* excludeDying= */ true, 11, 12);
1461         injectPackageInfos(Arrays.asList(
1462                 constructPackageManagerPackageInfo(
1463                         "third_party_package.A", 1103456, "third_party_shared_package.A"),
1464                 constructPackageManagerPackageInfo(
1465                         "third_party_package.B", 1103456, "third_party_shared_package.A"),
1466                 constructPackageManagerPackageInfo(
1467                         "third_party_package.C", 1101356, "third_party_shared_package.B"),
1468                 constructPackageManagerPackageInfo(
1469                         "third_party_package.D", 1101356, "third_party_shared_package.B"),
1470                 constructPackageManagerPackageInfo(
1471                         "third_party_package.A", 1203456, "third_party_shared_package.A"),
1472                 constructPackageManagerPackageInfo(
1473                         "third_party_package.B", 1203456, "third_party_shared_package.A")));
1474 
1475         mCarWatchdogService.setKillablePackageAsUser("third_party_package.A", UserHandle.ALL,
1476                 /* isKillable= */ false);
1477 
1478         PackageKillableStateSubject.assertThat(
1479                 mCarWatchdogService.getPackageKillableStatesAsUser(UserHandle.ALL)).containsExactly(
1480                 new PackageKillableState("third_party_package.A", 11,
1481                         PackageKillableState.KILLABLE_STATE_NO),
1482                 new PackageKillableState("third_party_package.B", 11,
1483                         PackageKillableState.KILLABLE_STATE_NO),
1484                 new PackageKillableState("third_party_package.C", 11,
1485                         PackageKillableState.KILLABLE_STATE_YES),
1486                 new PackageKillableState("third_party_package.D", 11,
1487                         PackageKillableState.KILLABLE_STATE_YES),
1488                 new PackageKillableState("third_party_package.A", 12,
1489                         PackageKillableState.KILLABLE_STATE_NO),
1490                 new PackageKillableState("third_party_package.B", 12,
1491                         PackageKillableState.KILLABLE_STATE_NO));
1492 
1493         mockUmGetUserHandles(mMockUserManager, /* excludeDying= */ true, 11, 12, 13);
1494         injectPackageInfos(Arrays.asList(
1495                 constructPackageManagerPackageInfo(
1496                         "third_party_package.A", 1303456, "third_party_shared_package.A"),
1497                 constructPackageManagerPackageInfo(
1498                         "third_party_package.B", 1303456, "third_party_shared_package.A")));
1499 
1500         PackageKillableStateSubject.assertThat(
1501                 mCarWatchdogService.getPackageKillableStatesAsUser(new UserHandle(13)))
1502                 .containsExactly(
1503                 new PackageKillableState("third_party_package.A", 13,
1504                         PackageKillableState.KILLABLE_STATE_NO),
1505                 new PackageKillableState("third_party_package.B", 13,
1506                         PackageKillableState.KILLABLE_STATE_NO));
1507     }
1508 
1509     @Test
testGetPackageKillableStatesAsUser()1510     public void testGetPackageKillableStatesAsUser() throws Exception {
1511         mockUmGetUserHandles(mMockUserManager, /* excludeDying= */ true, 11, 12);
1512         injectPackageInfos(Arrays.asList(
1513                 constructPackageManagerPackageInfo("third_party_package", 1103456, null),
1514                 constructPackageManagerPackageInfo("vendor_package.critical", 1101278, null),
1515                 constructPackageManagerPackageInfo("third_party_package", 1203456, null),
1516                 constructPackageManagerPackageInfo("vendor_package.critical", 1201278, null)));
1517 
1518         PackageKillableStateSubject.assertThat(
1519                 mCarWatchdogService.getPackageKillableStatesAsUser(new UserHandle(11)))
1520                 .containsExactly(
1521                         new PackageKillableState("third_party_package", 11,
1522                                 PackageKillableState.KILLABLE_STATE_YES),
1523                         new PackageKillableState("vendor_package.critical", 11,
1524                                 PackageKillableState.KILLABLE_STATE_NEVER));
1525     }
1526 
1527     @Test
testGetPackageKillableStatesAsUserWithSafeToKillPackages()1528     public void testGetPackageKillableStatesAsUserWithSafeToKillPackages() throws Exception {
1529         mockUmGetUserHandles(mMockUserManager, /* excludeDying= */ true, 100, 101);
1530         injectPackageInfos(Arrays.asList(
1531                 constructPackageManagerPackageInfo("system_package.non_critical.A", 10002459, null),
1532                 constructPackageManagerPackageInfo("third_party_package", 10003456, null),
1533                 constructPackageManagerPackageInfo("vendor_package.critical.B", 10001278, null),
1534                 constructPackageManagerPackageInfo("vendor_package.non_critical.A", 10005573, null),
1535                 constructPackageManagerPackageInfo("third_party_package", 10103456, null),
1536                 constructPackageManagerPackageInfo("vendor_package.critical.B", 10101278, null)));
1537 
1538         PackageKillableStateSubject.assertThat(
1539                 mCarWatchdogService.getPackageKillableStatesAsUser(UserHandle.ALL))
1540                 .containsExactly(
1541                         new PackageKillableState("system_package.non_critical.A", 100,
1542                                 PackageKillableState.KILLABLE_STATE_YES),
1543                         new PackageKillableState("third_party_package", 100,
1544                                 PackageKillableState.KILLABLE_STATE_YES),
1545                         new PackageKillableState("vendor_package.critical.B", 100,
1546                                 PackageKillableState.KILLABLE_STATE_NEVER),
1547                         new PackageKillableState("vendor_package.non_critical.A", 100,
1548                                 PackageKillableState.KILLABLE_STATE_YES),
1549                         new PackageKillableState("third_party_package", 101,
1550                                 PackageKillableState.KILLABLE_STATE_YES),
1551                         new PackageKillableState("vendor_package.critical.B", 101,
1552                                 PackageKillableState.KILLABLE_STATE_NEVER));
1553     }
1554 
1555     @Test
testGetPackageKillableStatesAsUserWithVendorPackagePrefixes()1556     public void testGetPackageKillableStatesAsUserWithVendorPackagePrefixes() throws Exception {
1557         mockUmGetUserHandles(mMockUserManager, /* excludeDying= */ true, 100);
1558         injectPackageInfos(Collections.singletonList(constructPackageManagerPackageInfo(
1559                 "some_pkg_as_vendor_pkg", 10002459, /* sharedUserId= */ null, /* flags= */ 0,
1560                 ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT)));
1561 
1562         List<PackageKillableState> killableStates =
1563                 mCarWatchdogService.getPackageKillableStatesAsUser(new UserHandle(100));
1564 
1565         // The vendor package prefixes in the resource overuse configs help identify vendor
1566         // packages. The safe-to-kill list in the vendor configs helps identify safe-to-kill vendor
1567         // packages. |system_package_as_vendor| is a critical system package by default but with
1568         // the resource overuse configs, this package should be classified as a safe-to-kill vendor
1569         // package.
1570         PackageKillableStateSubject.assertThat(killableStates)
1571                 .containsExactly(new PackageKillableState("some_pkg_as_vendor_pkg", 100,
1572                         PackageKillableState.KILLABLE_STATE_YES));
1573     }
1574 
1575     @Test
testGetPackageKillableStatesAsUserWithSharedUids()1576     public void testGetPackageKillableStatesAsUserWithSharedUids() throws Exception {
1577         mockUmGetUserHandles(mMockUserManager, /* excludeDying= */ true, 11, 12);
1578         injectPackageInfos(Arrays.asList(
1579                 constructPackageManagerPackageInfo(
1580                         "system_package.A", 1103456, "vendor_shared_package.A"),
1581                 constructPackageManagerPackageInfo(
1582                         "vendor_package.B", 1103456, "vendor_shared_package.A"),
1583                 constructPackageManagerPackageInfo(
1584                         "third_party_package.C", 1105678, "third_party_shared_package"),
1585                 constructPackageManagerPackageInfo(
1586                         "third_party_package.D", 1105678, "third_party_shared_package"),
1587                 constructPackageManagerPackageInfo(
1588                         "system_package.A", 1203456, "vendor_shared_package.A"),
1589                 constructPackageManagerPackageInfo(
1590                         "vendor_package.B", 1203456, "vendor_shared_package.A")));
1591 
1592         PackageKillableStateSubject.assertThat(
1593                 mCarWatchdogService.getPackageKillableStatesAsUser(new UserHandle(11)))
1594                 .containsExactly(
1595                         new PackageKillableState("system_package.A", 11,
1596                                 PackageKillableState.KILLABLE_STATE_NEVER),
1597                         new PackageKillableState("vendor_package.B", 11,
1598                                 PackageKillableState.KILLABLE_STATE_NEVER),
1599                         new PackageKillableState("third_party_package.C", 11,
1600                                 PackageKillableState.KILLABLE_STATE_YES),
1601                         new PackageKillableState("third_party_package.D", 11,
1602                                 PackageKillableState.KILLABLE_STATE_YES));
1603     }
1604 
1605     @Test
testGetPackageKillableStatesAsUserWithSharedUidsAndSafeToKillPackages()1606     public void testGetPackageKillableStatesAsUserWithSharedUidsAndSafeToKillPackages()
1607             throws Exception {
1608         mockUmGetUserHandles(mMockUserManager, /* excludeDying= */ true, 100);
1609         injectPackageInfos(Arrays.asList(
1610                 constructPackageManagerPackageInfo(
1611                         "vendor_package.non_critical.A", 10003456, "vendor_shared_package.A"),
1612                 constructPackageManagerPackageInfo(
1613                         "system_package.A", 10003456, "vendor_shared_package.A"),
1614                 constructPackageManagerPackageInfo(
1615                         "vendor_package.B", 10003456, "vendor_shared_package.A"),
1616                 constructPackageManagerPackageInfo(
1617                         "third_party_package.C", 10005678, "third_party_shared_package"),
1618                 constructPackageManagerPackageInfo(
1619                         "third_party_package.D", 10005678, "third_party_shared_package")));
1620 
1621         PackageKillableStateSubject.assertThat(
1622                 mCarWatchdogService.getPackageKillableStatesAsUser(new UserHandle(100)))
1623                 .containsExactly(
1624                         new PackageKillableState("vendor_package.non_critical.A", 100,
1625                                 PackageKillableState.KILLABLE_STATE_YES),
1626                         new PackageKillableState("system_package.A", 100,
1627                                 PackageKillableState.KILLABLE_STATE_YES),
1628                         new PackageKillableState("vendor_package.B", 100,
1629                                 PackageKillableState.KILLABLE_STATE_YES),
1630                         new PackageKillableState("third_party_package.C", 100,
1631                                 PackageKillableState.KILLABLE_STATE_YES),
1632                         new PackageKillableState("third_party_package.D", 100,
1633                                 PackageKillableState.KILLABLE_STATE_YES));
1634     }
1635 
1636     @Test
testGetPackageKillableStatesAsUserWithSharedUidsAndSafeToKillSharedPackage()1637     public void testGetPackageKillableStatesAsUserWithSharedUidsAndSafeToKillSharedPackage()
1638             throws Exception {
1639         mockUmGetUserHandles(mMockUserManager, /* excludeDying= */ true, 100);
1640         injectPackageInfos(Arrays.asList(
1641                 constructPackageManagerPackageInfo(
1642                         "vendor_package.A", 10003456, "vendor_shared_package.non_critical.B"),
1643                 constructPackageManagerPackageInfo(
1644                         "system_package.A", 10003456, "vendor_shared_package.non_critical.B"),
1645                 constructPackageManagerPackageInfo(
1646                         "vendor_package.B", 10003456, "vendor_shared_package.non_critical.B")));
1647 
1648 
1649         PackageKillableStateSubject.assertThat(
1650                 mCarWatchdogService.getPackageKillableStatesAsUser(new UserHandle(100)))
1651                 .containsExactly(
1652                         new PackageKillableState("vendor_package.A", 100,
1653                                 PackageKillableState.KILLABLE_STATE_YES),
1654                         new PackageKillableState("system_package.A", 100,
1655                                 PackageKillableState.KILLABLE_STATE_YES),
1656                         new PackageKillableState("vendor_package.B", 100,
1657                                 PackageKillableState.KILLABLE_STATE_YES));
1658     }
1659 
1660     @Test
testGetPackageKillableStatesAsUserForAllUsers()1661     public void testGetPackageKillableStatesAsUserForAllUsers() throws Exception {
1662         mockUmGetUserHandles(mMockUserManager, /* excludeDying= */ true, 11, 12);
1663         injectPackageInfos(Arrays.asList(
1664                 constructPackageManagerPackageInfo("third_party_package", 1103456, null),
1665                 constructPackageManagerPackageInfo("vendor_package.critical", 1101278, null),
1666                 constructPackageManagerPackageInfo("third_party_package", 1203456, null),
1667                 constructPackageManagerPackageInfo("vendor_package.critical", 1201278, null)));
1668 
1669         PackageKillableStateSubject.assertThat(
1670                 mCarWatchdogService.getPackageKillableStatesAsUser(UserHandle.ALL)).containsExactly(
1671                 new PackageKillableState("third_party_package", 11,
1672                         PackageKillableState.KILLABLE_STATE_YES),
1673                 new PackageKillableState("vendor_package.critical", 11,
1674                         PackageKillableState.KILLABLE_STATE_NEVER),
1675                 new PackageKillableState("third_party_package", 12,
1676                         PackageKillableState.KILLABLE_STATE_YES),
1677                 new PackageKillableState("vendor_package.critical", 12,
1678                         PackageKillableState.KILLABLE_STATE_NEVER));
1679     }
1680 
1681     @Test
testGetPackageKillableStatesAsUserForAllUsersWithSharedUids()1682     public void testGetPackageKillableStatesAsUserForAllUsersWithSharedUids() throws Exception {
1683         mockUmGetUserHandles(mMockUserManager, /* excludeDying= */ true, 11, 12);
1684         injectPackageInfos(Arrays.asList(
1685                 constructPackageManagerPackageInfo(
1686                         "system_package.A", 1103456, "vendor_shared_package.A"),
1687                 constructPackageManagerPackageInfo(
1688                         "vendor_package.B", 1103456, "vendor_shared_package.A"),
1689                 constructPackageManagerPackageInfo(
1690                         "third_party_package.C", 1105678, "third_party_shared_package"),
1691                 constructPackageManagerPackageInfo(
1692                         "third_party_package.D", 1105678, "third_party_shared_package"),
1693                 constructPackageManagerPackageInfo(
1694                         "system_package.A", 1203456, "vendor_shared_package.A"),
1695                 constructPackageManagerPackageInfo(
1696                         "vendor_package.B", 1203456, "vendor_shared_package.A")));
1697 
1698         PackageKillableStateSubject.assertThat(
1699                 mCarWatchdogService.getPackageKillableStatesAsUser(UserHandle.ALL))
1700                 .containsExactly(
1701                         new PackageKillableState("system_package.A", 11,
1702                                 PackageKillableState.KILLABLE_STATE_NEVER),
1703                         new PackageKillableState("vendor_package.B", 11,
1704                                 PackageKillableState.KILLABLE_STATE_NEVER),
1705                         new PackageKillableState("third_party_package.C", 11,
1706                                 PackageKillableState.KILLABLE_STATE_YES),
1707                         new PackageKillableState("third_party_package.D", 11,
1708                                 PackageKillableState.KILLABLE_STATE_YES),
1709                         new PackageKillableState("system_package.A", 12,
1710                                 PackageKillableState.KILLABLE_STATE_NEVER),
1711                         new PackageKillableState("vendor_package.B", 12,
1712                                 PackageKillableState.KILLABLE_STATE_NEVER));
1713     }
1714 
1715     @Test
testSetResourceOveruseConfigurations()1716     public void testSetResourceOveruseConfigurations() throws Exception {
1717         assertThat(mCarWatchdogService.setResourceOveruseConfigurations(
1718                 sampleResourceOveruseConfigurations(), CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO))
1719                 .isEqualTo(CarWatchdogManager.RETURN_CODE_SUCCESS);
1720 
1721         InternalResourceOveruseConfigurationSubject
1722                 .assertThat(captureOnSetResourceOveruseConfigurations())
1723                 .containsExactlyElementsIn(sampleInternalResourceOveruseConfigurations());
1724 
1725         // CarService fetches and syncs resource overuse configuration on the main thread by posting
1726         // a new message. Wait until this completes.
1727         CarServiceUtils.runOnMainSync(() -> {});
1728 
1729         /* Expect two calls, the first is made at car watchdog service init */
1730         verify(mMockCarWatchdogDaemon, times(2)).getResourceOveruseConfigurations();
1731     }
1732 
1733     @Test
testSetResourceOveruseConfigurationsRetriedWithDisconnectedDaemon()1734     public void testSetResourceOveruseConfigurationsRetriedWithDisconnectedDaemon()
1735             throws Exception {
1736         crashWatchdogDaemon();
1737 
1738         assertThat(mCarWatchdogService.setResourceOveruseConfigurations(
1739                 sampleResourceOveruseConfigurations(), CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO))
1740                 .isEqualTo(CarWatchdogManager.RETURN_CODE_SUCCESS);
1741 
1742         restartWatchdogDaemonAndAwait();
1743 
1744         InternalResourceOveruseConfigurationSubject
1745                 .assertThat(captureOnSetResourceOveruseConfigurations())
1746                 .containsExactlyElementsIn(sampleInternalResourceOveruseConfigurations());
1747     }
1748 
1749     @Test
testSetResourceOveruseConfigurationsRetriedWithRepeatedRemoteException()1750     public void testSetResourceOveruseConfigurationsRetriedWithRepeatedRemoteException()
1751             throws Exception {
1752         CountDownLatch crashLatch = new CountDownLatch(2);
1753         doAnswer(args -> {
1754             crashWatchdogDaemon();
1755             crashLatch.countDown();
1756             throw new RemoteException();
1757         }).when(mMockCarWatchdogDaemon).updateResourceOveruseConfigurations(anyList());
1758 
1759         assertThat(mCarWatchdogService.setResourceOveruseConfigurations(
1760                 sampleResourceOveruseConfigurations(), CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO))
1761                 .isEqualTo(CarWatchdogManager.RETURN_CODE_SUCCESS);
1762 
1763         restartWatchdogDaemonAndAwait();
1764 
1765         /*
1766          * Wait until the daemon is crashed again during the latest
1767          * updateResourceOveruseConfigurations call so the test is deterministic.
1768          */
1769         crashLatch.await(MAX_WAIT_TIME_MS, TimeUnit.MILLISECONDS);
1770 
1771         /* The below final restart should set the resource overuse configurations successfully. */
1772         List<android.automotive.watchdog.internal.ResourceOveruseConfiguration> actualConfigs =
1773                 new ArrayList<>();
1774         doAnswer(args -> {
1775             List<android.automotive.watchdog.internal.ResourceOveruseConfiguration> configs =
1776                     args.getArgument(0);
1777             synchronized (actualConfigs) {
1778                 actualConfigs.addAll(configs);
1779                 actualConfigs.notify();
1780             }
1781             return null;
1782         }).when(mMockCarWatchdogDaemon).updateResourceOveruseConfigurations(anyList());
1783 
1784         restartWatchdogDaemonAndAwait();
1785 
1786         /* Wait until latest updateResourceOveruseConfigurations call is issued on reconnection. */
1787         synchronized (actualConfigs) {
1788             actualConfigs.wait(MAX_WAIT_TIME_MS);
1789             InternalResourceOveruseConfigurationSubject.assertThat(actualConfigs)
1790                     .containsExactlyElementsIn(sampleInternalResourceOveruseConfigurations());
1791         }
1792 
1793         verify(mMockCarWatchdogDaemon, times(3)).updateResourceOveruseConfigurations(anyList());
1794     }
1795 
1796     @Test
testFailsSetResourceOveruseConfigurationsWithPendingRequest()1797     public void testFailsSetResourceOveruseConfigurationsWithPendingRequest()
1798             throws Exception {
1799         crashWatchdogDaemon();
1800 
1801         assertThat(mCarWatchdogService.setResourceOveruseConfigurations(
1802                 sampleResourceOveruseConfigurations(), CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO))
1803                 .isEqualTo(CarWatchdogManager.RETURN_CODE_SUCCESS);
1804 
1805         assertThrows(IllegalStateException.class,
1806                 () -> mCarWatchdogService.setResourceOveruseConfigurations(
1807                         sampleResourceOveruseConfigurations(),
1808                         CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO));
1809     }
1810 
1811     @Test
testFailsSetResourceOveruseConfigurationsOnInvalidArgs()1812     public void testFailsSetResourceOveruseConfigurationsOnInvalidArgs() throws Exception {
1813         assertThrows(NullPointerException.class,
1814                 () -> mCarWatchdogService.setResourceOveruseConfigurations(null,
1815                         CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO));
1816 
1817         assertThrows(IllegalArgumentException.class,
1818                 () -> mCarWatchdogService.setResourceOveruseConfigurations(new ArrayList<>(),
1819                         CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO));
1820 
1821         List<ResourceOveruseConfiguration> resourceOveruseConfigs = Collections.singletonList(
1822                 sampleResourceOveruseConfigurationBuilder(ComponentType.SYSTEM,
1823                         sampleIoOveruseConfigurationBuilder(ComponentType.SYSTEM).build())
1824                         .build());
1825         assertThrows(IllegalArgumentException.class,
1826                 () -> mCarWatchdogService.setResourceOveruseConfigurations(resourceOveruseConfigs,
1827                         0));
1828     }
1829 
1830     @Test
testFailsSetResourceOveruseConfigurationsOnDuplicateComponents()1831     public void testFailsSetResourceOveruseConfigurationsOnDuplicateComponents() throws Exception {
1832         ResourceOveruseConfiguration config =
1833                 sampleResourceOveruseConfigurationBuilder(ComponentType.SYSTEM,
1834                         sampleIoOveruseConfigurationBuilder(ComponentType.SYSTEM).build()).build();
1835         List<ResourceOveruseConfiguration> resourceOveruseConfigs = Arrays.asList(config, config);
1836         assertThrows(IllegalArgumentException.class,
1837                 () -> mCarWatchdogService.setResourceOveruseConfigurations(resourceOveruseConfigs,
1838                         CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO));
1839     }
1840 
1841     @Test
testFailsSetResourceOveruseConfigurationsOnZeroComponentLevelIoOveruseThresholds()1842     public void testFailsSetResourceOveruseConfigurationsOnZeroComponentLevelIoOveruseThresholds()
1843             throws Exception {
1844         List<ResourceOveruseConfiguration> resourceOveruseConfigs =
1845                 Collections.singletonList(
1846                         sampleResourceOveruseConfigurationBuilder(ComponentType.SYSTEM,
1847                                 sampleIoOveruseConfigurationBuilder(ComponentType.SYSTEM)
1848                                         .setComponentLevelThresholds(new PerStateBytes(200, 0, 200))
1849                                         .build())
1850                                 .build());
1851         assertThrows(IllegalArgumentException.class,
1852                 () -> mCarWatchdogService.setResourceOveruseConfigurations(resourceOveruseConfigs,
1853                         CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO));
1854     }
1855 
1856     @Test
testFailsSetResourceOveruseConfigurationsOnEmptyIoOveruseSystemWideThresholds()1857     public void testFailsSetResourceOveruseConfigurationsOnEmptyIoOveruseSystemWideThresholds()
1858             throws Exception {
1859         List<ResourceOveruseConfiguration> resourceOveruseConfigs =
1860                 Collections.singletonList(
1861                         sampleResourceOveruseConfigurationBuilder(ComponentType.SYSTEM,
1862                                 sampleIoOveruseConfigurationBuilder(ComponentType.SYSTEM)
1863                                         .setSystemWideThresholds(new ArrayList<>())
1864                                         .build())
1865                                 .build());
1866         assertThrows(IllegalArgumentException.class,
1867                 () -> mCarWatchdogService.setResourceOveruseConfigurations(resourceOveruseConfigs,
1868                         CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO));
1869     }
1870 
1871     @Test
testFailsSetResourceOveruseConfigurationsOnIoOveruseInvalidSystemWideThreshold()1872     public void testFailsSetResourceOveruseConfigurationsOnIoOveruseInvalidSystemWideThreshold()
1873             throws Exception {
1874         List<ResourceOveruseConfiguration> resourceOveruseConfigs = new ArrayList<>();
1875         resourceOveruseConfigs.add(sampleResourceOveruseConfigurationBuilder(ComponentType.SYSTEM,
1876                 sampleIoOveruseConfigurationBuilder(ComponentType.SYSTEM)
1877                         .setSystemWideThresholds(Collections.singletonList(
1878                                 new IoOveruseAlertThreshold(30, 0)))
1879                         .build())
1880                 .build());
1881         assertThrows(IllegalArgumentException.class,
1882                 () -> mCarWatchdogService.setResourceOveruseConfigurations(
1883                         resourceOveruseConfigs,
1884                         CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO));
1885 
1886         resourceOveruseConfigs.set(0,
1887                 sampleResourceOveruseConfigurationBuilder(ComponentType.SYSTEM,
1888                         sampleIoOveruseConfigurationBuilder(ComponentType.SYSTEM)
1889                                 .setSystemWideThresholds(Collections.singletonList(
1890                                         new IoOveruseAlertThreshold(0, 300)))
1891                                 .build())
1892                         .build());
1893         assertThrows(IllegalArgumentException.class,
1894                 () -> mCarWatchdogService.setResourceOveruseConfigurations(
1895                         resourceOveruseConfigs,
1896                         CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO));
1897     }
1898 
1899     @Test
testFailsSetResourceOveruseConfigurationsOnNullIoOveruseConfiguration()1900     public void testFailsSetResourceOveruseConfigurationsOnNullIoOveruseConfiguration()
1901             throws Exception {
1902         List<ResourceOveruseConfiguration> resourceOveruseConfigs = Collections.singletonList(
1903                 sampleResourceOveruseConfigurationBuilder(ComponentType.SYSTEM, null).build());
1904         assertThrows(IllegalArgumentException.class,
1905                 () -> mCarWatchdogService.setResourceOveruseConfigurations(resourceOveruseConfigs,
1906                         CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO));
1907     }
1908 
1909     @Test
testGetResourceOveruseConfigurations()1910     public void testGetResourceOveruseConfigurations() throws Exception {
1911         List<ResourceOveruseConfiguration> actualConfigs =
1912                 mCarWatchdogService.getResourceOveruseConfigurations(
1913                         CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO);
1914 
1915         ResourceOveruseConfigurationSubject.assertThat(actualConfigs)
1916                 .containsExactlyElementsIn(sampleResourceOveruseConfigurations());
1917     }
1918 
1919     @Test
testGetResourceOveruseConfigurationsWithDisconnectedDaemon()1920     public void testGetResourceOveruseConfigurationsWithDisconnectedDaemon() throws Exception {
1921         crashWatchdogDaemon();
1922 
1923         assertThrows(IllegalStateException.class,
1924                 () -> mCarWatchdogService.getResourceOveruseConfigurations(
1925                         CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO));
1926 
1927         /* Method initially called in CarWatchdogService init */
1928         verify(mMockCarWatchdogDaemon).getResourceOveruseConfigurations();
1929     }
1930 
1931     @Test
testGetResourceOveruseConfigurationsWithReconnectedDaemon()1932     public void testGetResourceOveruseConfigurationsWithReconnectedDaemon() throws Exception {
1933         /*
1934          * Emulate daemon crash and restart during the get request. The below get request should be
1935          * waiting for daemon connection before the first call to ServiceManager.getService. But to
1936          * make sure the test is deterministic emulate daemon restart only on the second call to
1937          * ServiceManager.getService.
1938          */
1939         doReturn(null)
1940                 .doReturn(mMockBinder)
1941                 .when(() -> ServiceManager.getService(CAR_WATCHDOG_DAEMON_INTERFACE));
1942         mCarWatchdogDaemonBinderDeathRecipient.binderDied();
1943 
1944         List<ResourceOveruseConfiguration> actualConfigs =
1945                 mCarWatchdogService.getResourceOveruseConfigurations(
1946                         CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO);
1947 
1948         ResourceOveruseConfigurationSubject.assertThat(actualConfigs)
1949                 .containsExactlyElementsIn(sampleResourceOveruseConfigurations());
1950     }
1951 
1952     @Test
testConcurrentSetGetResourceOveruseConfigurationsWithReconnectedDaemon()1953     public void testConcurrentSetGetResourceOveruseConfigurationsWithReconnectedDaemon()
1954             throws Exception {
1955         /*
1956          * Emulate daemon crash and restart during the get and set requests. The below get request
1957          * should be waiting for daemon connection before the first call to
1958          * ServiceManager.getService. But to make sure the test is deterministic emulate daemon
1959          * restart only on the second call to ServiceManager.getService.
1960          */
1961         doReturn(null)
1962                 .doReturn(mMockBinder)
1963                 .when(() -> ServiceManager.getService(CAR_WATCHDOG_DAEMON_INTERFACE));
1964         mCarWatchdogDaemonBinderDeathRecipient.binderDied();
1965 
1966         /* Capture and respond with the configuration received in the set request. */
1967         List<android.automotive.watchdog.internal.ResourceOveruseConfiguration> internalConfigs =
1968                 new ArrayList<>();
1969         doAnswer(args -> {
1970             List<android.automotive.watchdog.internal.ResourceOveruseConfiguration> configs =
1971                     args.getArgument(0);
1972             internalConfigs.addAll(configs);
1973             return null;
1974         }).when(mMockCarWatchdogDaemon).updateResourceOveruseConfigurations(anyList());
1975         when(mMockCarWatchdogDaemon.getResourceOveruseConfigurations()).thenReturn(internalConfigs);
1976 
1977         /* Start a set request that will become pending and a blocking get request. */
1978         List<ResourceOveruseConfiguration> setConfigs = sampleResourceOveruseConfigurations();
1979         assertThat(mCarWatchdogService.setResourceOveruseConfigurations(
1980                 setConfigs, CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO))
1981                 .isEqualTo(CarWatchdogManager.RETURN_CODE_SUCCESS);
1982 
1983         List<ResourceOveruseConfiguration> getConfigs =
1984                 mCarWatchdogService.getResourceOveruseConfigurations(
1985                         CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO);
1986 
1987         ResourceOveruseConfigurationSubject.assertThat(getConfigs)
1988                 .containsExactlyElementsIn(setConfigs);
1989     }
1990 
1991     @Test
testFailsGetResourceOveruseConfigurationsOnInvalidArgs()1992     public void testFailsGetResourceOveruseConfigurationsOnInvalidArgs() throws Exception {
1993         assertThrows(IllegalArgumentException.class,
1994                 () -> mCarWatchdogService.getResourceOveruseConfigurations(0));
1995     }
1996 
1997     @Test
testLatestIoOveruseStats()1998     public void testLatestIoOveruseStats() throws Exception {
1999         setRequiresDistractionOptimization(true);
2000         setDisplayStateEnabled(false);
2001         int criticalSysPkgUid = Binder.getCallingUid();
2002         int nonCriticalSysPkgUid = 1001056;
2003         int nonCriticalVndrPkgUid = 1002564;
2004         int thirdPartyPkgUid = 1002044;
2005 
2006         injectPackageInfos(Arrays.asList(
2007                 constructPackageManagerPackageInfo(
2008                         "system_package.critical", criticalSysPkgUid, null),
2009                 constructPackageManagerPackageInfo(
2010                         "system_package.non_critical", nonCriticalSysPkgUid, null),
2011                 constructPackageManagerPackageInfo(
2012                         "vendor_package.non_critical", nonCriticalVndrPkgUid, null),
2013                 constructPackageManagerPackageInfo(
2014                         "third_party_package", thirdPartyPkgUid, null)));
2015 
2016         IResourceOveruseListener mockSystemListener = createMockResourceOveruseListener();
2017         mCarWatchdogService.addResourceOveruseListenerForSystem(
2018                 CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO, mockSystemListener);
2019 
2020         IResourceOveruseListener mockListener = createMockResourceOveruseListener();
2021         mCarWatchdogService.addResourceOveruseListener(
2022                 CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO, mockListener);
2023 
2024         List<PackageIoOveruseStats> packageIoOveruseStats = Arrays.asList(
2025                 /* Overuse occurred but cannot be killed/disabled. */
2026                 constructPackageIoOveruseStats(criticalSysPkgUid, /* shouldNotify= */ true,
2027                         /* forgivenWriteBytes= */ constructPerStateBytes(100, 200, 300),
2028                         constructInternalIoOveruseStats(/* killableOnOveruse= */ false,
2029                                 /* remainingWriteBytes= */ constructPerStateBytes(0, 0, 0),
2030                                 /* writtenBytes= */ constructPerStateBytes(100, 200, 300),
2031                                 /* totalOveruses= */ 3)),
2032                 /* No overuse occurred but should be notified. */
2033                 constructPackageIoOveruseStats(nonCriticalSysPkgUid, /* shouldNotify= */ true,
2034                         /* forgivenWriteBytes= */ constructPerStateBytes(50, 100, 150),
2035                         constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
2036                                 /* remainingWriteBytes= */ constructPerStateBytes(20, 30, 40),
2037                                 /* writtenBytes= */ constructPerStateBytes(100, 200, 300),
2038                                 /* totalOveruses= */ 3)),
2039                 /* Neither overuse occurred nor be notified. */
2040                 constructPackageIoOveruseStats(nonCriticalVndrPkgUid, /* shouldNotify= */ false,
2041                         /* forgivenWriteBytes= */ constructPerStateBytes(25, 50, 75),
2042                         constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
2043                                 /* remainingWriteBytes= */ constructPerStateBytes(200, 300, 400),
2044                                 /* writtenBytes= */ constructPerStateBytes(100, 200, 300),
2045                                 /* totalOveruses= */ 3)),
2046                 /* Overuse occurred and can be killed/disabled. */
2047                 constructPackageIoOveruseStats(thirdPartyPkgUid, /* shouldNotify= */ true,
2048                         /* forgivenWriteBytes= */ constructPerStateBytes(100, 200, 300),
2049                         constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
2050                                 /* remainingWriteBytes= */ constructPerStateBytes(0, 0, 0),
2051                                 /* writtenBytes= */ constructPerStateBytes(300, 600, 900),
2052                                 /* totalOveruses= */ 3)));
2053 
2054         pushLatestIoOveruseStatsAndWait(packageIoOveruseStats);
2055 
2056         assertThat(mDisabledUserPackages).containsExactlyElementsIn(Collections.singleton(
2057                 "10:third_party_package"));
2058 
2059         List<ResourceOveruseStats> expectedStats = new ArrayList<>();
2060 
2061         expectedStats.add(constructResourceOveruseStats(criticalSysPkgUid,
2062                 "system_package.critical", packageIoOveruseStats.get(0).ioOveruseStats));
2063 
2064         verifyOnOveruseCalled(expectedStats, mockListener);
2065 
2066         expectedStats.add(constructResourceOveruseStats(nonCriticalSysPkgUid,
2067                 "system_package.non_critical", packageIoOveruseStats.get(1).ioOveruseStats));
2068 
2069         /*
2070          * When the package receives overuse notification, the package is not yet killed so the
2071          * totalTimesKilled counter is not yet incremented.
2072          */
2073         expectedStats.add(constructResourceOveruseStats(thirdPartyPkgUid, "third_party_package",
2074                 packageIoOveruseStats.get(3).ioOveruseStats));
2075 
2076         verifyOnOveruseCalled(expectedStats, mockSystemListener);
2077 
2078         List<AtomsProto.CarWatchdogIoOveruseStatsReported> expectedReportedOveruseStats =
2079                 new ArrayList<>();
2080         expectedReportedOveruseStats.add(constructIoOveruseStatsReported(criticalSysPkgUid,
2081                 WatchdogPerfHandler.constructCarWatchdogPerStateBytes(10, 20, 30),
2082                 WatchdogPerfHandler.constructCarWatchdogPerStateBytes(100, 200, 300)));
2083         expectedReportedOveruseStats.add(constructIoOveruseStatsReported(thirdPartyPkgUid,
2084                 WatchdogPerfHandler.constructCarWatchdogPerStateBytes(30, 60, 90),
2085                 WatchdogPerfHandler.constructCarWatchdogPerStateBytes(300, 600, 900)));
2086 
2087         captureAndVerifyIoOveruseStatsReported(expectedReportedOveruseStats);
2088 
2089         List<AtomsProto.CarWatchdogKillStatsReported> expectedReportedKillStats =
2090                 Collections.singletonList(constructIoOveruseKillStatsReported(thirdPartyPkgUid,
2091                         CAR_WATCHDOG_KILL_STATS_REPORTED__SYSTEM_STATE__USER_NO_INTERACTION_MODE,
2092                         WatchdogPerfHandler.constructCarWatchdogPerStateBytes(30, 60, 90),
2093                         WatchdogPerfHandler.constructCarWatchdogPerStateBytes(300, 600, 900)));
2094 
2095         captureAndVerifyKillStatsReported(expectedReportedKillStats);
2096     }
2097 
2098     @Test
testLatestIoOveruseStatsWithSharedUid()2099     public void testLatestIoOveruseStatsWithSharedUid() throws Exception {
2100         setRequiresDistractionOptimization(true);
2101         setDisplayStateEnabled(false);
2102         int criticalSysSharedUid = Binder.getCallingUid();
2103         int nonCriticalVndrSharedUid = 1002564;
2104         int thirdPartySharedUid = 1002044;
2105 
2106         injectPackageInfos(Arrays.asList(
2107                 constructPackageManagerPackageInfo(
2108                         "system_package.A", criticalSysSharedUid, "system_shared_package"),
2109                 constructPackageManagerPackageInfo(
2110                         "system_package.B", criticalSysSharedUid, "system_shared_package"),
2111                 constructPackageManagerPackageInfo("vendor_package.non_critical",
2112                         nonCriticalVndrSharedUid, "vendor_shared_package"),
2113                 constructPackageManagerPackageInfo(
2114                         "third_party_package.A", thirdPartySharedUid, "third_party_shared_package"),
2115                 constructPackageManagerPackageInfo(
2116                         "third_party_package.B", thirdPartySharedUid, "third_party_shared_package")
2117         ));
2118 
2119         IResourceOveruseListener mockSystemListener = createMockResourceOveruseListener();
2120         mCarWatchdogService.addResourceOveruseListenerForSystem(
2121                 CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO, mockSystemListener);
2122 
2123         IResourceOveruseListener mockListener = createMockResourceOveruseListener();
2124         mCarWatchdogService.addResourceOveruseListener(
2125                 CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO, mockListener);
2126 
2127         List<PackageIoOveruseStats> packageIoOveruseStats = Arrays.asList(
2128                 /* Overuse occurred but cannot be killed/disabled. */
2129                 constructPackageIoOveruseStats(criticalSysSharedUid, /* shouldNotify= */ true,
2130                         /* forgivenWriteBytes= */ constructPerStateBytes(100, 200, 300),
2131                         constructInternalIoOveruseStats(/* killableOnOveruse= */ false,
2132                                 /* remainingWriteBytes= */ constructPerStateBytes(0, 0, 0),
2133                                 /* writtenBytes= */ constructPerStateBytes(100, 200, 300),
2134                                 /* totalOveruses= */ 3)),
2135                 /* No overuse occurred but should be notified. */
2136                 constructPackageIoOveruseStats(nonCriticalVndrSharedUid, /* shouldNotify= */ true,
2137                         /* forgivenWriteBytes= */ constructPerStateBytes(50, 100, 150),
2138                         constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
2139                                 /* remainingWriteBytes= */ constructPerStateBytes(200, 300, 400),
2140                                 /* writtenBytes= */ constructPerStateBytes(100, 200, 300),
2141                                 /* totalOveruses= */ 3)),
2142                 /* Overuse occurred and can be killed/disabled. */
2143                 constructPackageIoOveruseStats(thirdPartySharedUid, /* shouldNotify= */ true,
2144                         /* forgivenWriteBytes= */ constructPerStateBytes(100, 200, 300),
2145                         constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
2146                                 /* remainingWriteBytes= */ constructPerStateBytes(0, 0, 0),
2147                                 /* writtenBytes= */ constructPerStateBytes(300, 600, 900),
2148                                 /* totalOveruses= */ 3)));
2149 
2150         pushLatestIoOveruseStatsAndWait(packageIoOveruseStats);
2151 
2152         assertThat(mDisabledUserPackages).containsExactlyElementsIn(Arrays.asList(
2153                 "10:third_party_package.A", "10:third_party_package.B"));
2154 
2155         List<ResourceOveruseStats> expectedStats = new ArrayList<>();
2156 
2157         expectedStats.add(constructResourceOveruseStats(criticalSysSharedUid,
2158                 "shared:system_shared_package", packageIoOveruseStats.get(0).ioOveruseStats));
2159 
2160         verifyOnOveruseCalled(expectedStats, mockListener);
2161 
2162         expectedStats.add(constructResourceOveruseStats(nonCriticalVndrSharedUid,
2163                 "shared:vendor_shared_package", packageIoOveruseStats.get(1).ioOveruseStats));
2164 
2165         /*
2166          * When the package receives overuse notification, the package is not yet killed so the
2167          * totalTimesKilled counter is not yet incremented.
2168          */
2169         expectedStats.add(constructResourceOveruseStats(thirdPartySharedUid,
2170                 "shared:third_party_shared_package", packageIoOveruseStats.get(2).ioOveruseStats));
2171 
2172         verifyOnOveruseCalled(expectedStats, mockSystemListener);
2173 
2174         List<AtomsProto.CarWatchdogIoOveruseStatsReported> expectedReportedOveruseStats =
2175                 new ArrayList<>();
2176         expectedReportedOveruseStats.add(constructIoOveruseStatsReported(criticalSysSharedUid,
2177                 WatchdogPerfHandler.constructCarWatchdogPerStateBytes(10, 20, 30),
2178                 WatchdogPerfHandler.constructCarWatchdogPerStateBytes(100, 200, 300)));
2179         expectedReportedOveruseStats.add(constructIoOveruseStatsReported(thirdPartySharedUid,
2180                 WatchdogPerfHandler.constructCarWatchdogPerStateBytes(30, 60, 90),
2181                 WatchdogPerfHandler.constructCarWatchdogPerStateBytes(300, 600, 900)));
2182 
2183         captureAndVerifyIoOveruseStatsReported(expectedReportedOveruseStats);
2184 
2185         List<AtomsProto.CarWatchdogKillStatsReported> expectedReportedKillStats =
2186                 Collections.singletonList(constructIoOveruseKillStatsReported(thirdPartySharedUid,
2187                         CAR_WATCHDOG_KILL_STATS_REPORTED__SYSTEM_STATE__USER_NO_INTERACTION_MODE,
2188                         WatchdogPerfHandler.constructCarWatchdogPerStateBytes(30, 60, 90),
2189                         WatchdogPerfHandler.constructCarWatchdogPerStateBytes(300, 600, 900)));
2190 
2191         captureAndVerifyKillStatsReported(expectedReportedKillStats);
2192     }
2193 
2194     @Test
testGetTodayIoUsageStats()2195     public void testGetTodayIoUsageStats() throws Exception {
2196         List<WatchdogStorage.IoUsageStatsEntry> ioUsageStatsEntries = Arrays.asList(
2197                 WatchdogStorageUnitTest.constructIoUsageStatsEntry(
2198                         /* userId= */ 10, "system_package", /* startTime */ 0, /* duration= */ 1234,
2199                         /* remainingWriteBytes= */ constructPerStateBytes(200, 300, 400),
2200                         /* writtenBytes= */ constructPerStateBytes(1000, 2000, 3000),
2201                         /* forgivenWriteBytes= */ constructPerStateBytes(100, 100, 100),
2202                         /* totalOveruses= */ 2, /* forgivenOveruses= */ 0,
2203                         /* totalTimesKilled= */ 1),
2204                 WatchdogStorageUnitTest.constructIoUsageStatsEntry(
2205                         /* userId= */ 11, "vendor_package", /* startTime */ 0, /* duration= */ 1234,
2206                         /* remainingWriteBytes= */ constructPerStateBytes(500, 600, 700),
2207                         /* writtenBytes= */ constructPerStateBytes(1100, 2300, 4300),
2208                         /* forgivenWriteBytes= */ constructPerStateBytes(100, 100, 100),
2209                         /* totalOveruses= */ 4, /* forgivenOveruses= */ 1,
2210                         /* totalTimesKilled= */ 10));
2211         when(mMockWatchdogStorage.getTodayIoUsageStats()).thenReturn(ioUsageStatsEntries);
2212 
2213         List<UserPackageIoUsageStats> actualStats =
2214                 mWatchdogServiceForSystemImpl.getTodayIoUsageStats();
2215 
2216         List<UserPackageIoUsageStats> expectedStats = Arrays.asList(
2217                 constructUserPackageIoUsageStats(/* userId= */ 10, "system_package",
2218                         /* writtenBytes= */ constructPerStateBytes(1000, 2000, 3000),
2219                         /* forgivenWriteBytes= */ constructPerStateBytes(100, 100, 100),
2220                         /* totalOveruses= */ 2),
2221                 constructUserPackageIoUsageStats(/* userId= */ 11, "vendor_package",
2222                         /* writtenBytes= */ constructPerStateBytes(1100, 2300, 4300),
2223                         /* forgivenWriteBytes= */ constructPerStateBytes(100, 100, 100),
2224                         /* totalOveruses= */ 4));
2225 
2226         assertThat(actualStats).comparingElementsUsing(Correspondence.from(
2227                 CarWatchdogServiceUnitTest::isUserPackageIoUsageStatsEquals,
2228                 "is user package I/O usage stats equal to"))
2229                 .containsExactlyElementsIn(expectedStats);
2230     }
2231 
2232     @Test
testPersistStatsOnShutdownEnter()2233     public void testPersistStatsOnShutdownEnter() throws Exception {
2234         mockUmGetUserHandles(mMockUserManager, /* excludeDying= */ true, 10, 11, 12);
2235         injectPackageInfos(Arrays.asList(
2236                 constructPackageManagerPackageInfo(
2237                         "third_party_package", 1103456, "vendor_shared_package.critical"),
2238                 constructPackageManagerPackageInfo(
2239                         "vendor_package", 1103456, "vendor_shared_package.critical"),
2240                 constructPackageManagerPackageInfo("third_party_package.A", 1001100, null),
2241                 constructPackageManagerPackageInfo("third_party_package.A", 1201100, null)));
2242 
2243         SparseArray<PackageIoOveruseStats> packageIoOveruseStatsByUid =
2244                 injectIoOveruseStatsForPackages(
2245                         mGenericPackageNameByUid,
2246                         /* killablePackages= */ new ArraySet<>(Collections.singletonList(
2247                                 "third_party_package.A")),
2248                         /* shouldNotifyPackages= */ new ArraySet<>());
2249 
2250         mCarWatchdogService.setKillablePackageAsUser(
2251                 "third_party_package.A", new UserHandle(12), /* isKillable= */ false);
2252 
2253         restartService(/* totalRestarts= */ 1);
2254 
2255         List<ResourceOveruseStats> actualStats = mCarWatchdogService.getAllResourceOveruseStats(
2256                 CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO, /* minimumStatsFlag= */ 0,
2257                 CarWatchdogManager.STATS_PERIOD_CURRENT_DAY);
2258 
2259         List<ResourceOveruseStats> expectedStats = Arrays.asList(
2260                 constructResourceOveruseStats(
2261                         /* uid= */ 1103456, "shared:vendor_shared_package.critical",
2262                         packageIoOveruseStatsByUid.get(1103456).ioOveruseStats),
2263                 constructResourceOveruseStats(/* uid= */ 1001100, "third_party_package.A",
2264                         packageIoOveruseStatsByUid.get(1001100).ioOveruseStats),
2265                 constructResourceOveruseStats(/* uid= */ 1201100, "third_party_package.A",
2266                         packageIoOveruseStatsByUid.get(1201100).ioOveruseStats));
2267 
2268         PackageKillableStateSubject.assertThat(
2269                 mCarWatchdogService.getPackageKillableStatesAsUser(UserHandle.ALL))
2270                 .containsExactly(
2271                         new PackageKillableState("third_party_package", 11,
2272                                 PackageKillableState.KILLABLE_STATE_NEVER),
2273                         new PackageKillableState("vendor_package", 11,
2274                                 PackageKillableState.KILLABLE_STATE_NEVER),
2275                         new PackageKillableState("third_party_package.A", 10,
2276                                 PackageKillableState.KILLABLE_STATE_YES),
2277                         new PackageKillableState("third_party_package.A", 12,
2278                                 PackageKillableState.KILLABLE_STATE_NO));
2279 
2280         ResourceOveruseStatsSubject.assertThat(actualStats)
2281                 .containsExactlyElementsIn(expectedStats);
2282 
2283         verifyNoMoreInteractions(mMockWatchdogStorage);
2284     }
2285 
2286     @Test
testPersistIoOveruseStatsOnDateChange()2287     public void testPersistIoOveruseStatsOnDateChange() throws Exception {
2288         mockUmGetUserHandles(mMockUserManager, /* excludeDying= */ true, 10);
2289         injectPackageInfos(Arrays.asList(
2290                 constructPackageManagerPackageInfo("system_package", 1011200, null),
2291                 constructPackageManagerPackageInfo("third_party_package", 1001100, null)));
2292 
2293         setDisplayStateEnabled(false);
2294         mTimeSource.updateNow(/* numDaysAgo= */ 1);
2295         List<PackageIoOveruseStats> prevDayStats = Arrays.asList(
2296                 constructPackageIoOveruseStats(1011200, /* shouldNotify= */ false,
2297                         /* forgivenWriteBytes= */ constructPerStateBytes(600, 700, 800),
2298                         constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
2299                                 /* remainingWriteBytes= */ constructPerStateBytes(0, 0, 0),
2300                                 /* writtenBytes= */ constructPerStateBytes(600, 700, 800),
2301                                 /* totalOveruses= */ 3)),
2302                 constructPackageIoOveruseStats(1001100, /* shouldNotify= */ false,
2303                         /* forgivenWriteBytes= */ constructPerStateBytes(1050, 1100, 1200),
2304                         constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
2305                                 /* remainingWriteBytes= */ constructPerStateBytes(50, 60, 70),
2306                                 /* writtenBytes= */ constructPerStateBytes(1100, 1200, 1300),
2307                                 /* totalOveruses= */ 5)));
2308         pushLatestIoOveruseStatsAndWait(prevDayStats);
2309 
2310         List<WatchdogStorage.IoUsageStatsEntry> expectedSavedEntries = Arrays.asList(
2311                 new WatchdogStorage.IoUsageStatsEntry(/* userId= */ 10, "system_package",
2312                 new WatchdogPerfHandler.PackageIoUsage(prevDayStats.get(0).ioOveruseStats,
2313                         /* forgivenWriteBytes= */ constructPerStateBytes(600, 700, 800),
2314                         /* forgivenOveruses= */ 3, /* totalTimesKilled= */ 1)),
2315                 new WatchdogStorage.IoUsageStatsEntry(/* userId= */ 10, "third_party_package",
2316                         new WatchdogPerfHandler.PackageIoUsage(prevDayStats.get(1).ioOveruseStats,
2317                                 /* forgivenWriteBytes= */ constructPerStateBytes(1050, 1100, 1200),
2318                                 /* forgivenOveruses= */ 0, /* totalTimesKilled= */ 0)));
2319 
2320         setDisplayStateEnabled(true);
2321         mTimeSource.updateNow(/* numDaysAgo= */ 0);
2322         List<PackageIoOveruseStats> currentDayStats = Arrays.asList(
2323                 constructPackageIoOveruseStats(1011200, /* shouldNotify= */ false,
2324                         /* forgivenWriteBytes= */ constructPerStateBytes(0, 0, 0),
2325                         constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
2326                                 /* remainingWriteBytes= */ constructPerStateBytes(500, 550, 600),
2327                                 /* writtenBytes= */ constructPerStateBytes(100, 150, 200),
2328                                 /* totalOveruses= */ 0)),
2329                 constructPackageIoOveruseStats(1001100, /* shouldNotify= */ false,
2330                         /* forgivenWriteBytes= */ constructPerStateBytes(0, 0, 0),
2331                         constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
2332                                 /* remainingWriteBytes= */ constructPerStateBytes(250, 360, 470),
2333                                 /* writtenBytes= */ constructPerStateBytes(900, 900, 900),
2334                                 /* totalOveruses= */ 0)));
2335         pushLatestIoOveruseStatsAndWait(currentDayStats);
2336 
2337         IoUsageStatsEntrySubject.assertThat(mIoUsageStatsEntries)
2338                 .containsExactlyElementsIn(expectedSavedEntries);
2339 
2340         List<ResourceOveruseStats> actualCurrentDayStats =
2341                 mCarWatchdogService.getAllResourceOveruseStats(
2342                         CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO, /* minimumStatsFlag= */ 0,
2343                         CarWatchdogManager.STATS_PERIOD_CURRENT_DAY);
2344 
2345         List<ResourceOveruseStats> expectedCurrentDayStats = Arrays.asList(
2346                 constructResourceOveruseStats(/* uid= */ 1011200, "system_package",
2347                         currentDayStats.get(0).ioOveruseStats),
2348                 constructResourceOveruseStats(/* uid= */ 1001100, "third_party_package",
2349                         currentDayStats.get(1).ioOveruseStats));
2350 
2351         ResourceOveruseStatsSubject.assertThat(actualCurrentDayStats)
2352                 .containsExactlyElementsIn(expectedCurrentDayStats);
2353     }
2354 
2355     @Test
testNoUserNotificationWithNoRecurrentOveruse()2356     public void testNoUserNotificationWithNoRecurrentOveruse() throws Exception {
2357         mockAmGetCurrentUser(100);
2358         setDisplayStateEnabled(true);
2359         setRequiresDistractionOptimization(false);
2360 
2361         setUpSampleUserAndPackages();
2362 
2363         pushLatestIoOveruseStatsAndWait(
2364                 sampleIoOveruseStats(/* requireRecurrentOveruseStats= */ false));
2365 
2366         // Verify no notification is sent
2367         captureAndVerifyUserNotifications(Collections.emptyList());
2368     }
2369 
2370     @Test
testNoUserNotificationOnRecurrentOveruseWithDistractionOptimization()2371     public void testNoUserNotificationOnRecurrentOveruseWithDistractionOptimization()
2372             throws Exception {
2373         mockAmGetCurrentUser(100);
2374         setDisplayStateEnabled(true);
2375         setRequiresDistractionOptimization(true);
2376 
2377         setUpSampleUserAndPackages();
2378 
2379         pushLatestIoOveruseStatsAndWait(
2380                 sampleIoOveruseStats(/* requireRecurrentOveruseStats= */ true));
2381 
2382         // Verify no notification is sent
2383         captureAndVerifyUserNotifications(Collections.emptyList());
2384     }
2385 
2386     @Test
testUserNotificationOnRecurrentOveruseAfterNoDistractionOptimization()2387     public void testUserNotificationOnRecurrentOveruseAfterNoDistractionOptimization()
2388             throws Exception {
2389         mockAmGetCurrentUser(100);
2390         setDisplayStateEnabled(true);
2391         setRequiresDistractionOptimization(true);
2392 
2393         setUpSampleUserAndPackages();
2394 
2395         pushLatestIoOveruseStatsAndWait(
2396                 sampleIoOveruseStats(/* requireRecurrentOveruseStats= */ true));
2397 
2398         setRequiresDistractionOptimization(false);
2399 
2400         captureAndVerifyUserNotifications(Collections.singletonList(
2401                 new UserNotificationCall(UserHandle.of(100),
2402                         Arrays.asList("vendor_package.non_critical", "third_party_package.A",
2403                                 "third_party_package.B"), /* hasHeadsUpNotification= */ true,
2404                         /* notificationIds= */ Arrays.asList(150, 151, 152))));
2405     }
2406 
2407     @Test
testNoDuplicateUserNotificationOnRepeatedRecurrentOveruse()2408     public void testNoDuplicateUserNotificationOnRepeatedRecurrentOveruse()
2409             throws Exception {
2410         mockAmGetCurrentUser(100);
2411         setDisplayStateEnabled(true);
2412         setRequiresDistractionOptimization(false);
2413 
2414         setUpSampleUserAndPackages();
2415 
2416         pushLatestIoOveruseStatsAndWait(
2417                 sampleIoOveruseStats(/* requireRecurrentOveruseStats= */ true));
2418 
2419         captureAndVerifyUserNotifications(Collections.singletonList(
2420                 new UserNotificationCall(UserHandle.of(100),
2421                         Arrays.asList("vendor_package.non_critical", "third_party_package.A",
2422                                 "third_party_package.B"), /* hasHeadsUpNotification= */ true,
2423                         /* notificationIds= */ Arrays.asList(150, 151, 152))));
2424 
2425         pushLatestIoOveruseStatsAndWait(
2426                 sampleIoOveruseStats(/* requireRecurrentOveruseStats= */ true));
2427 
2428         verifyNoMoreInteractions(mMockUserNotificationHelper);
2429     }
2430 
2431     @Test
testImmediateUserNotificationOnRecurrentOveruseWhenNoDistractionOptimization()2432     public void testImmediateUserNotificationOnRecurrentOveruseWhenNoDistractionOptimization()
2433             throws Exception {
2434         mockAmGetCurrentUser(100);
2435         setDisplayStateEnabled(true);
2436         setRequiresDistractionOptimization(false);
2437 
2438         setUpSampleUserAndPackages();
2439 
2440         pushLatestIoOveruseStatsAndWait(
2441                 sampleIoOveruseStats(/* requireRecurrentOveruseStats= */ true));
2442 
2443         pushLatestIoOveruseStatsAndWait(Collections.singletonList(
2444                 constructPackageIoOveruseStats(/* uid= */ 10010002, /* shouldNotify= */ true,
2445                         /* forgivenWriteBytes= */ constructPerStateBytes(100, 200, 300),
2446                         constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
2447                                 /* remainingWriteBytes= */ constructPerStateBytes(0, 0, 0),
2448                                 /* writtenBytes= */ constructPerStateBytes(300, 600, 900),
2449                                 /* totalOveruses= */ 3))));
2450 
2451         List<UserNotificationCall> userNotificationCalls = Arrays.asList(
2452                 new UserNotificationCall(UserHandle.of(100),
2453                         Arrays.asList("vendor_package.non_critical", "third_party_package.A",
2454                                 "third_party_package.B"), /* hasHeadsUpNotification= */ true,
2455                         /* notificationIds= */ Arrays.asList(150, 151, 152)),
2456                 new UserNotificationCall(UserHandle.of(100),
2457                         Collections.singletonList("system_package.non_critical"),
2458                         /* hasHeadsUpNotification= */ false,
2459                         /* notificationIds= */ Arrays.asList(153)));
2460 
2461         captureAndVerifyUserNotifications(userNotificationCalls);
2462     }
2463 
2464     @Test
testNoUserNotificationOnRecurrentOveruseByPrePrioritizedApp()2465     public void testNoUserNotificationOnRecurrentOveruseByPrePrioritizedApp() throws Exception {
2466         mockAmGetCurrentUser(100);
2467         setDisplayStateEnabled(true);
2468         setRequiresDistractionOptimization(true);
2469 
2470         setUpSampleUserAndPackages();
2471 
2472         mCarWatchdogService.setKillablePackageAsUser("third_party_package.A", UserHandle.of(100),
2473                 /* isKillable= */ false);
2474 
2475         pushLatestIoOveruseStatsAndWait(Collections.singletonList(
2476                 constructPackageIoOveruseStats(/* uid= */ 10010005, /* shouldNotify= */ true,
2477                         /* forgivenWriteBytes= */ constructPerStateBytes(100, 200, 300),
2478                         constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
2479                                 /* remainingWriteBytes= */ constructPerStateBytes(0, 0, 0),
2480                                 /* writtenBytes= */ constructPerStateBytes(300, 600, 900),
2481                                 /* totalOveruses= */ 3))));
2482 
2483         setRequiresDistractionOptimization(false);
2484 
2485         // Verify no notification is sent
2486         captureAndVerifyUserNotifications(Collections.emptyList());
2487     }
2488 
2489     @Test
testNoUserNotificationOnRecurrentOveruseByPostPrioritizedApp()2490     public void testNoUserNotificationOnRecurrentOveruseByPostPrioritizedApp() throws Exception {
2491         mockAmGetCurrentUser(100);
2492         setDisplayStateEnabled(true);
2493         setRequiresDistractionOptimization(true);
2494 
2495         setUpSampleUserAndPackages();
2496 
2497         pushLatestIoOveruseStatsAndWait(Collections.singletonList(
2498                 constructPackageIoOveruseStats(/* uid= */ 10010005, /* shouldNotify= */ true,
2499                         /* forgivenWriteBytes= */ constructPerStateBytes(100, 200, 300),
2500                         constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
2501                                 /* remainingWriteBytes= */ constructPerStateBytes(0, 0, 0),
2502                                 /* writtenBytes= */ constructPerStateBytes(300, 600, 900),
2503                                 /* totalOveruses= */ 3))));
2504 
2505         mCarWatchdogService.setKillablePackageAsUser("third_party_package.A",
2506                 UserHandle.of(100), /* isKillable= */ false);
2507 
2508         setRequiresDistractionOptimization(false);
2509 
2510         // Verify no notification is sent
2511         captureAndVerifyUserNotifications(Collections.emptyList());
2512     }
2513 
2514     @Test
testUserNotificationOnRecurrentOveruseByPriorityResettedApp()2515     public void testUserNotificationOnRecurrentOveruseByPriorityResettedApp() throws Exception {
2516         mockAmGetCurrentUser(100);
2517         setDisplayStateEnabled(true);
2518         setRequiresDistractionOptimization(true);
2519 
2520         setUpSampleUserAndPackages();
2521 
2522         mCarWatchdogService.setKillablePackageAsUser("third_party_package.A",
2523                 UserHandle.of(100), /* isKillable= */ false);
2524 
2525         pushLatestIoOveruseStatsAndWait(Collections.singletonList(
2526                 constructPackageIoOveruseStats(/* uid= */ 10010005, /* shouldNotify= */ true,
2527                         /* forgivenWriteBytes= */ constructPerStateBytes(100, 200, 300),
2528                         constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
2529                                 /* remainingWriteBytes= */ constructPerStateBytes(0, 0, 0),
2530                                 /* writtenBytes= */ constructPerStateBytes(300, 600, 900),
2531                                 /* totalOveruses= */ 3))));
2532 
2533         mCarWatchdogService.setKillablePackageAsUser("third_party_package.A", UserHandle.of(100),
2534                 /* isKillable= */ true);
2535 
2536         setRequiresDistractionOptimization(false);
2537 
2538         captureAndVerifyUserNotifications(Collections.singletonList(
2539                 new UserNotificationCall(UserHandle.of(100),
2540                         Arrays.asList("third_party_package.A", "third_party_package.B"),
2541                         /* hasHeadsUpNotification= */ true,
2542                         /* notificationIds= */ Arrays.asList(150, 151))));
2543     }
2544 
2545     @Test
testUserNotificationOnHistoricalRecurrentOveruse()2546     public void testUserNotificationOnHistoricalRecurrentOveruse() throws Exception {
2547         when(mMockWatchdogStorage
2548                 .getNotForgivenHistoricalIoOveruses(RECURRING_OVERUSE_PERIOD_IN_DAYS))
2549                 .thenReturn(Arrays.asList(new WatchdogStorage.NotForgivenOverusesEntry(100,
2550                         "system_package.non_critical", 2)));
2551 
2552         // Force CarWatchdogService to fetch historical not forgiven overuses.
2553         restartService(/* totalRestarts= */ 1);
2554         mockAmGetCurrentUser(100);
2555         setDisplayStateEnabled(true);
2556         setRequiresDistractionOptimization(false);
2557 
2558         setUpSampleUserAndPackages();
2559 
2560         pushLatestIoOveruseStatsAndWait(Collections.singletonList(
2561                 constructPackageIoOveruseStats(/* uid= */ 10010002, /* shouldNotify= */ true,
2562                         /* forgivenWriteBytes= */ constructPerStateBytes(100, 200, 300),
2563                         constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
2564                                 /* remainingWriteBytes= */ constructPerStateBytes(0, 0, 0),
2565                                 /* writtenBytes= */ constructPerStateBytes(300, 600, 900),
2566                                 /* totalOveruses= */ 1))));
2567 
2568         captureAndVerifyUserNotifications(Collections.singletonList(
2569                 new UserNotificationCall(UserHandle.of(100),
2570                         Collections.singletonList("system_package.non_critical"),
2571                         /* hasHeadsUpNotification= */ true,
2572                         /* notificationIds= */ Collections.singletonList(150))));
2573     }
2574 
2575     @Test
testUserNotificationWithDisabledDisplay()2576     public void testUserNotificationWithDisabledDisplay() throws Exception {
2577         mockAmGetCurrentUser(100);
2578         setDisplayStateEnabled(false);
2579         setRequiresDistractionOptimization(false);
2580 
2581         setUpSampleUserAndPackages();
2582 
2583         pushLatestIoOveruseStatsAndWait(Collections.singletonList(
2584                 constructPackageIoOveruseStats(/* uid= */ 10010002, /* shouldNotify= */ true,
2585                         /* forgivenWriteBytes= */ constructPerStateBytes(100, 200, 300),
2586                         constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
2587                                 /* remainingWriteBytes= */ constructPerStateBytes(0, 0, 0),
2588                                 /* writtenBytes= */ constructPerStateBytes(300, 600, 900),
2589                                 /* totalOveruses= */ 3))));
2590 
2591         captureAndVerifyUserNotifications(Collections.singletonList(
2592                 new UserNotificationCall(UserHandle.of(100),
2593                         Collections.singletonList("system_package.non_critical"),
2594                         /* hasHeadsUpNotification= */ false,
2595                         /* notificationIds= */ Collections.singletonList(150))));
2596     }
2597 
2598     @Test
testNoDisableWithNoRecurrentOveruse()2599     public void testNoDisableWithNoRecurrentOveruse() throws Exception {
2600         setUpSampleUserAndPackages();
2601         setRequiresDistractionOptimization(false);
2602         setDisplayStateEnabled(false);
2603 
2604         List<PackageIoOveruseStats> packageIoOveruseStats =
2605                 sampleIoOveruseStats(/* requireRecurrentOveruseStats= */ false);
2606 
2607         pushLatestIoOveruseStatsAndWait(packageIoOveruseStats);
2608 
2609         captureAndVerifyIoOveruseStatsReported(sampleReportedOveruseStats());
2610 
2611         verify(() -> CarStatsLog.write(eq(CarStatsLog.CAR_WATCHDOG_KILL_STATS_REPORTED),
2612                 anyInt(), anyInt(), anyInt(), anyInt(), any(), any()), never());
2613 
2614         assertWithMessage("Disabled user packages").that(mDisabledUserPackages).isEmpty();
2615     }
2616 
2617     @Test
testNoDisableRecurrentlyOverusingAppWithDistractionOptimization()2618     public void testNoDisableRecurrentlyOverusingAppWithDistractionOptimization() throws Exception {
2619         setUpSampleUserAndPackages();
2620         setRequiresDistractionOptimization(true);
2621         setDisplayStateEnabled(true);
2622 
2623         List<PackageIoOveruseStats> packageIoOveruseStats =
2624                 sampleIoOveruseStats(/* requireRecurrentOveruseStats= */ true);
2625 
2626         pushLatestIoOveruseStatsAndWait(packageIoOveruseStats);
2627 
2628         captureAndVerifyIoOveruseStatsReported(sampleReportedOveruseStats());
2629 
2630         verify(() -> CarStatsLog.write(eq(CarStatsLog.CAR_WATCHDOG_KILL_STATS_REPORTED),
2631                 anyInt(), anyInt(), anyInt(), anyInt(), any(), any()), never());
2632 
2633         assertWithMessage("Disabled user packages").that(mDisabledUserPackages).isEmpty();
2634     }
2635 
2636     @Test
testNoDisableRecurrentlyOverusingAppWhenDisplayEnabled()2637     public void testNoDisableRecurrentlyOverusingAppWhenDisplayEnabled() throws Exception {
2638         setUpSampleUserAndPackages();
2639         setRequiresDistractionOptimization(false);
2640         setDisplayStateEnabled(true);
2641 
2642         List<PackageIoOveruseStats> packageIoOveruseStats =
2643                 sampleIoOveruseStats(/* requireRecurrentOveruseStats= */ true);
2644 
2645         pushLatestIoOveruseStatsAndWait(packageIoOveruseStats);
2646 
2647         captureAndVerifyIoOveruseStatsReported(sampleReportedOveruseStats());
2648 
2649         verify(() -> CarStatsLog.write(eq(CarStatsLog.CAR_WATCHDOG_KILL_STATS_REPORTED),
2650                 anyInt(), anyInt(), anyInt(), anyInt(), any(), any()), never());
2651 
2652         assertWithMessage("Disabled user packages").that(mDisabledUserPackages).isEmpty();
2653     }
2654 
2655     @Test
testDisableRecurrentlyOverusingAppAfterDisplayDisabled()2656     public void testDisableRecurrentlyOverusingAppAfterDisplayDisabled() throws Exception {
2657         setUpSampleUserAndPackages();
2658         setRequiresDistractionOptimization(true);
2659         setDisplayStateEnabled(true);
2660 
2661         List<PackageIoOveruseStats> packageIoOveruseStats =
2662                 sampleIoOveruseStats(/* requireRecurrentOveruseStats= */ true);
2663 
2664         pushLatestIoOveruseStatsAndWait(packageIoOveruseStats);
2665 
2666         assertWithMessage("Disabled user packages").that(mDisabledUserPackages).isEmpty();
2667 
2668         setRequiresDistractionOptimization(false);
2669 
2670         assertWithMessage("Disabled user packages").that(mDisabledUserPackages).isEmpty();
2671 
2672         setDisplayStateEnabled(false);
2673 
2674         captureAndVerifyIoOveruseStatsReported(sampleReportedOveruseStats());
2675 
2676         captureAndVerifyKillStatsReported(sampleReportedKillStats(
2677                 CAR_WATCHDOG_KILL_STATS_REPORTED__SYSTEM_STATE__USER_NO_INTERACTION_MODE,
2678                 /* killedUids= */ new int[]{10010004, 10110004, 10010005, 10110005}));
2679 
2680         assertWithMessage("Disabled user packages").that(mDisabledUserPackages).containsExactly(
2681                 "100:vendor_package.non_critical", "101:vendor_package.non_critical",
2682                 "100:third_party_package.A", "101:third_party_package.A",
2683                 "100:third_party_package.B", "101:third_party_package.B");
2684     }
2685 
2686     @Test
testImmediateDisableRecurrentlyOverusingAppDuringDisabledDisplay()2687     public void testImmediateDisableRecurrentlyOverusingAppDuringDisabledDisplay()
2688             throws Exception {
2689         setUpSampleUserAndPackages();
2690         setRequiresDistractionOptimization(false);
2691         setDisplayStateEnabled(false);
2692 
2693         List<PackageIoOveruseStats> packageIoOveruseStats =
2694                 sampleIoOveruseStats(/* requireRecurrentOveruseStats= */ true);
2695 
2696         pushLatestIoOveruseStatsAndWait(packageIoOveruseStats);
2697 
2698         captureAndVerifyIoOveruseStatsReported(sampleReportedOveruseStats());
2699 
2700         captureAndVerifyKillStatsReported(sampleReportedKillStats(
2701                 CAR_WATCHDOG_KILL_STATS_REPORTED__SYSTEM_STATE__USER_NO_INTERACTION_MODE,
2702                 /* killedUids= */ new int[]{10010004, 10110004, 10010005, 10110005}));
2703 
2704         assertWithMessage("Disabled user packages").that(mDisabledUserPackages).containsExactly(
2705                 "100:vendor_package.non_critical", "101:vendor_package.non_critical",
2706                 "100:third_party_package.A", "101:third_party_package.A",
2707                 "100:third_party_package.B", "101:third_party_package.B");
2708     }
2709 
2710     @Test
testDisableRecurrentlyOverusingAppWhenDisplayDisabledAfterDateChange()2711     public void testDisableRecurrentlyOverusingAppWhenDisplayDisabledAfterDateChange()
2712             throws Exception {
2713         mTimeSource.updateNow(/* numDaysAgo= */ 1);
2714         setUpSampleUserAndPackages();
2715         setRequiresDistractionOptimization(true);
2716         setDisplayStateEnabled(true);
2717 
2718         List<PackageIoOveruseStats> packageIoOveruseStats =
2719                 sampleIoOveruseStats(/* requireRecurrentOveruseStats= */ true);
2720 
2721         pushLatestIoOveruseStatsAndWait(packageIoOveruseStats);
2722 
2723         assertWithMessage("Disabled user packages").that(mDisabledUserPackages).isEmpty();
2724 
2725         mTimeSource.updateNow(/* numDaysAgo= */ 0);
2726 
2727         pushLatestIoOveruseStatsAndWait(new ArrayList<>());
2728 
2729         setRequiresDistractionOptimization(false);
2730         setDisplayStateEnabled(false);
2731 
2732         captureAndVerifyIoOveruseStatsReported(sampleReportedOveruseStats());
2733 
2734         captureAndVerifyKillStatsReported(sampleReportedKillStats(
2735                 CAR_WATCHDOG_KILL_STATS_REPORTED__SYSTEM_STATE__USER_NO_INTERACTION_MODE,
2736                 /* killedUids= */ new int[]{10010004, 10110004, 10010005, 10110005}));
2737 
2738         assertWithMessage("Disabled user packages").that(mDisabledUserPackages).containsExactly(
2739                 "100:vendor_package.non_critical", "101:vendor_package.non_critical",
2740                 "100:third_party_package.A", "101:third_party_package.A",
2741                 "100:third_party_package.B", "101:third_party_package.B");
2742     }
2743 
2744     @Test
testNoDisableRecurrentlyOverusingPrePrioritizedApp()2745     public void testNoDisableRecurrentlyOverusingPrePrioritizedApp() throws Exception {
2746         setUpSampleUserAndPackages();
2747         setRequiresDistractionOptimization(true);
2748         setDisplayStateEnabled(true);
2749 
2750         mCarWatchdogService.setKillablePackageAsUser(
2751                 "vendor_package.non_critical", new UserHandle(100), /* isKillable= */ false);
2752         mCarWatchdogService.setKillablePackageAsUser(
2753                 "third_party_package.A", new UserHandle(101), /* isKillable= */ false);
2754 
2755         List<PackageIoOveruseStats> packageIoOveruseStats =
2756                 sampleIoOveruseStats(/* requireRecurrentOveruseStats= */ true);
2757 
2758         pushLatestIoOveruseStatsAndWait(packageIoOveruseStats);
2759 
2760         assertWithMessage("Disabled user packages").that(mDisabledUserPackages).isEmpty();
2761 
2762         setRequiresDistractionOptimization(false);
2763         setDisplayStateEnabled(false);
2764 
2765         captureAndVerifyIoOveruseStatsReported(sampleReportedOveruseStats());
2766 
2767         captureAndVerifyKillStatsReported(sampleReportedKillStats(
2768                 CAR_WATCHDOG_KILL_STATS_REPORTED__SYSTEM_STATE__USER_NO_INTERACTION_MODE,
2769                 /* killedUids= */ new int[]{10110004, 10010005}));
2770 
2771         assertWithMessage("Disabled user packages").that(mDisabledUserPackages)
2772                 .containsExactly("101:vendor_package.non_critical", "100:third_party_package.A",
2773                         "100:third_party_package.B");
2774     }
2775 
2776     @Test
testNoDisableRecurrentlyOverusingPostPrioritizedApp()2777     public void testNoDisableRecurrentlyOverusingPostPrioritizedApp() throws Exception {
2778         setUpSampleUserAndPackages();
2779         setRequiresDistractionOptimization(true);
2780         setDisplayStateEnabled(true);
2781 
2782         List<PackageIoOveruseStats> packageIoOveruseStats =
2783                 sampleIoOveruseStats(/* requireRecurrentOveruseStats= */ true);
2784 
2785         pushLatestIoOveruseStatsAndWait(packageIoOveruseStats);
2786 
2787         assertWithMessage("Disabled user packages").that(mDisabledUserPackages).isEmpty();
2788 
2789         mCarWatchdogService.setKillablePackageAsUser(
2790                 "vendor_package.non_critical", new UserHandle(100), /* isKillable= */ false);
2791         mCarWatchdogService.setKillablePackageAsUser(
2792                 "third_party_package.A", new UserHandle(101), /* isKillable= */ false);
2793 
2794         setRequiresDistractionOptimization(false);
2795         setDisplayStateEnabled(false);
2796 
2797         captureAndVerifyIoOveruseStatsReported(sampleReportedOveruseStats());
2798 
2799         captureAndVerifyKillStatsReported(sampleReportedKillStats(
2800                 CAR_WATCHDOG_KILL_STATS_REPORTED__SYSTEM_STATE__USER_NO_INTERACTION_MODE,
2801                 /* killedUids= */ new int[]{10110004, 10010005}));
2802 
2803         assertWithMessage("Disabled user packages").that(mDisabledUserPackages)
2804                 .containsExactly("101:vendor_package.non_critical", "100:third_party_package.A",
2805                         "100:third_party_package.B");
2806     }
2807 
2808     @Test
testDisableRecurrentlyOverusingPriorityResettedApp()2809     public void testDisableRecurrentlyOverusingPriorityResettedApp() throws Exception {
2810         setUpSampleUserAndPackages();
2811         setRequiresDistractionOptimization(true);
2812         setDisplayStateEnabled(true);
2813 
2814         mCarWatchdogService.setKillablePackageAsUser(
2815                 "vendor_package.non_critical", new UserHandle(100), /* isKillable= */ false);
2816 
2817         List<PackageIoOveruseStats> packageIoOveruseStats =
2818                 sampleIoOveruseStats(/* requireRecurrentOveruseStats= */ true);
2819 
2820         pushLatestIoOveruseStatsAndWait(packageIoOveruseStats);
2821 
2822         assertWithMessage("Disabled user packages").that(mDisabledUserPackages).isEmpty();
2823 
2824         mCarWatchdogService.setKillablePackageAsUser(
2825                 "vendor_package.non_critical", new UserHandle(100), /* isKillable= */ true);
2826 
2827         setRequiresDistractionOptimization(false);
2828         setDisplayStateEnabled(false);
2829 
2830         captureAndVerifyIoOveruseStatsReported(sampleReportedOveruseStats());
2831 
2832         captureAndVerifyKillStatsReported(sampleReportedKillStats(
2833                 CAR_WATCHDOG_KILL_STATS_REPORTED__SYSTEM_STATE__USER_NO_INTERACTION_MODE,
2834                 /* killedUids= */ new int[]{10010004, 10110004, 10010005, 10110005}));
2835 
2836         assertWithMessage("Disabled user packages").that(mDisabledUserPackages).containsExactly(
2837                 "100:vendor_package.non_critical", "101:vendor_package.non_critical",
2838                 "100:third_party_package.A", "101:third_party_package.A",
2839                 "100:third_party_package.B", "101:third_party_package.B");
2840     }
2841 
2842     @Test
testImmediateDisableRecurrentlyOverusingAppDuringGarageMode()2843     public void testImmediateDisableRecurrentlyOverusingAppDuringGarageMode()
2844             throws Exception {
2845         setUpSampleUserAndPackages();
2846         setRequiresDistractionOptimization(false);
2847         setDisplayStateEnabled(false);
2848         mBroadcastReceiver.onReceive(mMockContext,
2849                 new Intent().setAction(CarWatchdogService.ACTION_GARAGE_MODE_ON));
2850 
2851         List<PackageIoOveruseStats> packageIoOveruseStats =
2852                 sampleIoOveruseStats(/* requireRecurrentOveruseStats= */ true);
2853 
2854         pushLatestIoOveruseStatsAndWait(packageIoOveruseStats);
2855 
2856         captureAndVerifyIoOveruseStatsReported(sampleReportedOveruseStats());
2857 
2858         captureAndVerifyKillStatsReported(sampleReportedKillStats(
2859                 CAR_WATCHDOG_KILL_STATS_REPORTED__SYSTEM_STATE__GARAGE_MODE,
2860                 /* killedUids= */ new int[]{10010004, 10110004, 10010005, 10110005}));
2861 
2862         assertWithMessage("Disabled user packages").that(mDisabledUserPackages).containsExactly(
2863                 "100:vendor_package.non_critical", "101:vendor_package.non_critical",
2864                 "100:third_party_package.A", "101:third_party_package.A",
2865                 "100:third_party_package.B", "101:third_party_package.B");
2866     }
2867 
2868     @Test
testDisableHistoricalRecurrentlyOverusingApp()2869     public void testDisableHistoricalRecurrentlyOverusingApp() throws Exception {
2870         when(mMockWatchdogStorage
2871                 .getNotForgivenHistoricalIoOveruses(RECURRING_OVERUSE_PERIOD_IN_DAYS))
2872                 .thenReturn(Arrays.asList(new WatchdogStorage.NotForgivenOverusesEntry(100,
2873                         "third_party_package", 2)));
2874 
2875         // Force CarWatchdogService to fetch historical not forgiven overuses.
2876         restartService(/* totalRestarts= */ 1);
2877         setRequiresDistractionOptimization(true);
2878         setDisplayStateEnabled(false);
2879         int thirdPartyPkgUid = UserHandle.getUid(100, 10005);
2880 
2881         injectPackageInfos(Collections.singletonList(constructPackageManagerPackageInfo(
2882                 "third_party_package", thirdPartyPkgUid, null)));
2883 
2884         pushLatestIoOveruseStatsAndWait(
2885                 sampleIoOveruseStats(/* requireRecurrentOveruseStats= */ false));
2886 
2887         // Third party package is disabled given the two historical overuses and one current
2888         // overuse.
2889         assertWithMessage("Disabled packages after recurring overuse with history")
2890                 .that(mDisabledUserPackages)
2891                 .containsExactlyElementsIn(Collections.singleton("100:third_party_package"));
2892 
2893         // Package was enabled again.
2894         mDisabledUserPackages.clear();
2895 
2896         PackageIoOveruseStats packageIoOveruseStats =
2897                 constructPackageIoOveruseStats(thirdPartyPkgUid, /* shouldNotify= */ true,
2898                         /* forgivenWriteBytes= */ constructPerStateBytes(200, 400, 600),
2899                         constructInternalIoOveruseStats(/* killableOnOveruse= */ true,
2900                                 /* remainingWriteBytes= */ constructPerStateBytes(0, 0, 0),
2901                                 /* writtenBytes= */ constructPerStateBytes(200, 400, 600),
2902                                 /* totalOveruses= */ 3));
2903 
2904         pushLatestIoOveruseStatsAndWait(Collections.singletonList(packageIoOveruseStats));
2905 
2906         // From the 3 total overuses, one overuse was forgiven previously.
2907         assertWithMessage("Disabled packages after non-recurring overuse")
2908                 .that(mDisabledUserPackages).isEmpty();
2909 
2910         // Add one overuse.
2911         packageIoOveruseStats.ioOveruseStats.totalOveruses = 4;
2912 
2913         pushLatestIoOveruseStatsAndWait(Collections.singletonList(packageIoOveruseStats));
2914 
2915         // Third party package is disabled again given the three current overuses. From the 4 total
2916         // overuses, one overuse was forgiven previously.
2917         assertWithMessage("Disabled packages after recurring overuse from the same day")
2918                 .that(mDisabledUserPackages)
2919                 .containsExactlyElementsIn(Collections.singleton("100:third_party_package"));
2920 
2921         // Force write to database
2922         restartService(/* totalRestarts= */ 2);
2923 
2924         verify(mMockWatchdogStorage).forgiveHistoricalOveruses(mPackagesByUserIdCaptor.capture(),
2925                 eq(RECURRING_OVERUSE_PERIOD_IN_DAYS));
2926 
2927         assertWithMessage("Forgiven packages")
2928                 .that(mPackagesByUserIdCaptor.getValue().get(100))
2929                 .containsExactlyElementsIn(Arrays.asList("third_party_package"));
2930     }
2931 
2932     @Test
testDisableHistoricalRecurrentlyOverusingAppAfterDateChange()2933     public void testDisableHistoricalRecurrentlyOverusingAppAfterDateChange() throws Exception {
2934         when(mMockWatchdogStorage.getNotForgivenHistoricalIoOveruses(
2935                 eq(RECURRING_OVERUSE_PERIOD_IN_DAYS)))
2936                 .thenReturn(Arrays.asList(new WatchdogStorage.NotForgivenOverusesEntry(100,
2937                         "third_party_package", 2)));
2938 
2939         mTimeSource.updateNow(/* numDaysAgo= */ 1);
2940         setRequiresDistractionOptimization(true);
2941         setDisplayStateEnabled(false);
2942         int thirdPartyPkgUid = UserHandle.getUid(100, 10005);
2943 
2944         injectPackageInfos(Collections.singletonList(constructPackageManagerPackageInfo(
2945                 "third_party_package", thirdPartyPkgUid, null)));
2946 
2947         List<PackageIoOveruseStats> ioOveruseStats =
2948                 sampleIoOveruseStats(/* requireRecurrentOveruseStats= */ false);
2949         pushLatestIoOveruseStatsAndWait(ioOveruseStats);
2950 
2951         // Third party package is disabled given the two historical overuses and one current
2952         // overuse.
2953         assertThat(mDisabledUserPackages)
2954                 .containsExactlyElementsIn(Collections.singleton("100:third_party_package"));
2955 
2956         // Force write to database by pushing non-overusing I/O overuse stats.
2957         mTimeSource.updateNow(/* numDaysAgo= */ 0);
2958         pushLatestIoOveruseStatsAndWait(Collections.singletonList(ioOveruseStats.get(0)));
2959 
2960         verify(mMockWatchdogStorage).forgiveHistoricalOveruses(mPackagesByUserIdCaptor.capture(),
2961                 eq(RECURRING_OVERUSE_PERIOD_IN_DAYS));
2962 
2963         assertWithMessage("Forgiven packages")
2964                 .that(mPackagesByUserIdCaptor.getValue().get(100))
2965                 .containsExactlyElementsIn(Arrays.asList("third_party_package"));
2966     }
2967 
2968 
2969     @Test
testResetResourceOveruseStatsResetsStats()2970     public void testResetResourceOveruseStatsResetsStats() throws Exception {
2971         UserHandle user = UserHandle.getUserHandleForUid(10003346);
2972         String packageName = mMockContext.getPackageName();
2973         mGenericPackageNameByUid.put(10003346, packageName);
2974         mGenericPackageNameByUid.put(10101278, "vendor_package.critical");
2975         injectIoOveruseStatsForPackages(
2976                 mGenericPackageNameByUid, /* killablePackages= */ new ArraySet<>(),
2977                 /* shouldNotifyPackages= */ new ArraySet<>());
2978 
2979         mWatchdogServiceForSystemImpl.resetResourceOveruseStats(
2980                 Collections.singletonList(packageName));
2981 
2982         ResourceOveruseStats actualStats =
2983                 mCarWatchdogService.getResourceOveruseStatsForUserPackage(
2984                         packageName, user,
2985                         CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
2986                         CarWatchdogManager.STATS_PERIOD_CURRENT_DAY);
2987 
2988         ResourceOveruseStats expectedStats = new ResourceOveruseStats.Builder(
2989                 packageName, user).build();
2990 
2991         ResourceOveruseStatsSubject.assertEquals(actualStats, expectedStats);
2992 
2993         verify(mMockWatchdogStorage).deleteUserPackage(eq(user.getIdentifier()), eq(packageName));
2994     }
2995 
2996     @Test
testResetResourceOveruseStatsEnablesPackage()2997     public void testResetResourceOveruseStatsEnablesPackage() throws Exception {
2998         injectPackageInfos(Arrays.asList(
2999                 constructPackageManagerPackageInfo("third_party_package.A", 10012345,
3000                         /* sharedUserId= */ null),
3001                 constructPackageManagerPackageInfo("vendor_package.critical.A", 10014567,
3002                         "vendor_shared_package.A"),
3003                 constructPackageManagerPackageInfo("vendor_package.critical.B", 10014567,
3004                         "vendor_shared_package.A"),
3005                 constructPackageManagerPackageInfo("system_package.critical.A", 10001278,
3006                         "system_shared_package.A"),
3007                 constructPackageManagerPackageInfo("third_party_package.B", 10056790,
3008                         /* sharedUserId= */ null),
3009                 constructPackageManagerPackageInfo("system_package.non_critical.B", 10007345,
3010                         "system_shared_package.B")));
3011 
3012         injectIoOveruseStatsForPackages(
3013                 mGenericPackageNameByUid, /* killablePackages= */ new ArraySet<>(),
3014                 /* shouldNotifyPackages= */ new ArraySet<>());
3015 
3016         doReturn(COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED).when(mSpiedPackageManager)
3017                 .getApplicationEnabledSetting(
3018                         or(or(eq("third_party_package.A"), eq("vendor_package.critical.A")),
3019                                 eq("vendor_package.critical.B")), eq(100));
3020 
3021         mWatchdogServiceForSystemImpl.resetResourceOveruseStats(
3022                 Arrays.asList("third_party_package.A", "shared:vendor_shared_package.A",
3023                         "shared:system_shared_package.A", "third_party_package.B"));
3024 
3025         verify(mSpiedPackageManager).getApplicationEnabledSetting("third_party_package.A", 100);
3026         verify(mSpiedPackageManager).getApplicationEnabledSetting("vendor_package.critical.A", 100);
3027         verify(mSpiedPackageManager).getApplicationEnabledSetting("vendor_package.critical.B", 100);
3028         verify(mSpiedPackageManager).getApplicationEnabledSetting("system_package.critical.A", 100);
3029         verify(mSpiedPackageManager).getApplicationEnabledSetting("third_party_package.B", 100);
3030 
3031         verify(mSpiedPackageManager).setApplicationEnabledSetting(eq("third_party_package.A"),
3032                 eq(COMPONENT_ENABLED_STATE_ENABLED), anyInt(), eq(100), anyString());
3033         verify(mSpiedPackageManager).setApplicationEnabledSetting(eq("vendor_package.critical.A"),
3034                 eq(COMPONENT_ENABLED_STATE_ENABLED), anyInt(), eq(100), anyString());
3035         verify(mSpiedPackageManager).setApplicationEnabledSetting(eq("vendor_package.critical.B"),
3036                 eq(COMPONENT_ENABLED_STATE_ENABLED), anyInt(), eq(100), anyString());
3037 
3038         verifyNoMoreInteractions(mSpiedPackageManager);
3039     }
3040 
3041     @Test
testResetResourceOveruseStatsResetsUserPackageSettings()3042     public void testResetResourceOveruseStatsResetsUserPackageSettings() throws Exception {
3043         mockUmGetUserHandles(mMockUserManager, /* excludeDying= */ true, 100, 101);
3044         injectPackageInfos(Arrays.asList(
3045                 constructPackageManagerPackageInfo("third_party_package.A", 10001278, null),
3046                 constructPackageManagerPackageInfo("third_party_package.A", 10101278, null),
3047                 constructPackageManagerPackageInfo("third_party_package.B", 10003346, null),
3048                 constructPackageManagerPackageInfo("third_party_package.B", 10103346, null)));
3049         injectIoOveruseStatsForPackages(mGenericPackageNameByUid,
3050                 /* killablePackages= */ Set.of("third_party_package.A", "third_party_package.B"),
3051                 /* shouldNotifyPackages= */ new ArraySet<>());
3052 
3053         mCarWatchdogService.setKillablePackageAsUser("third_party_package.A",
3054                 UserHandle.ALL, /* isKillable= */false);
3055         mCarWatchdogService.setKillablePackageAsUser("third_party_package.B",
3056                 UserHandle.ALL, /* isKillable= */false);
3057 
3058         mWatchdogServiceForSystemImpl.resetResourceOveruseStats(
3059                 Collections.singletonList("third_party_package.A"));
3060 
3061         PackageKillableStateSubject.assertThat(
3062                 mCarWatchdogService.getPackageKillableStatesAsUser(UserHandle.ALL)).containsExactly(
3063                 new PackageKillableState("third_party_package.A", 100,
3064                         PackageKillableState.KILLABLE_STATE_YES),
3065                 new PackageKillableState("third_party_package.A", 101,
3066                         PackageKillableState.KILLABLE_STATE_YES),
3067                 new PackageKillableState("third_party_package.B", 100,
3068                         PackageKillableState.KILLABLE_STATE_NO),
3069                 new PackageKillableState("third_party_package.B", 101,
3070                         PackageKillableState.KILLABLE_STATE_NO)
3071         );
3072 
3073         verify(mMockWatchdogStorage, times(2)).deleteUserPackage(anyInt(),
3074                 eq("third_party_package.A"));
3075     }
3076 
3077     @Test
testPullSystemIoUsageSummaryAtomsWithRestart()3078     public void testPullSystemIoUsageSummaryAtomsWithRestart() throws Exception {
3079         List<StatsEvent> events = new ArrayList<>();
3080         assertWithMessage("Stats pull atom callback status")
3081                 .that(mStatsPullAtomCallback.onPullAtom(CAR_WATCHDOG_SYSTEM_IO_USAGE_SUMMARY,
3082                         events)).isEqualTo(PULL_SUCCESS);
3083 
3084         List<AtomsProto.CarWatchdogSystemIoUsageSummary> expectedSummaries =
3085                 verifyAndGetSystemIoUsageSummaries(
3086                         mTimeSource.getCurrentDate().minus(RETENTION_PERIOD));
3087 
3088         assertWithMessage("First pulled system I/O usage summary atoms")
3089                 .that(mPulledSystemIoUsageSummaries).containsExactlyElementsIn(expectedSummaries);
3090         mPulledSystemIoUsageSummaries.clear();
3091 
3092         restartService(/* totalRestarts= */ 1);
3093 
3094         assertWithMessage("Status of stats pull atom callback after restart")
3095                 .that(mStatsPullAtomCallback.onPullAtom(CAR_WATCHDOG_SYSTEM_IO_USAGE_SUMMARY,
3096                         events)).isEqualTo(PULL_SUCCESS);
3097 
3098         assertWithMessage("Pulled system I/O usage summary atoms after restart")
3099                 .that(mPulledSystemIoUsageSummaries).isEmpty();
3100 
3101         verifyNoMoreInteractions(mMockWatchdogStorage);
3102     }
3103 
3104     @Test
testPullSystemIoUsageSummaryAtomsWithDateChange()3105     public void testPullSystemIoUsageSummaryAtomsWithDateChange() throws Exception {
3106         mTimeSource.updateNow(/* numDaysAgo= */ 7);
3107 
3108         List<StatsEvent> events = new ArrayList<>();
3109         assertWithMessage("Stats pull atom callback status")
3110                 .that(mStatsPullAtomCallback.onPullAtom(CAR_WATCHDOG_SYSTEM_IO_USAGE_SUMMARY,
3111                         events)).isEqualTo(PULL_SUCCESS);
3112 
3113         List<AtomsProto.CarWatchdogSystemIoUsageSummary> expectedSummaries =
3114                 verifyAndGetSystemIoUsageSummaries(
3115                         mTimeSource.getCurrentDate().minus(RETENTION_PERIOD));
3116 
3117         assertWithMessage("First pulled system I/O usage summary atoms")
3118                 .that(mPulledSystemIoUsageSummaries).containsExactlyElementsIn(expectedSummaries);
3119         mPulledSystemIoUsageSummaries.clear();
3120 
3121         mTimeSource.updateNow(/* numDaysAgo= */ 6);
3122 
3123         assertWithMessage("Status of stats pull atom callback within the same week")
3124                 .that(mStatsPullAtomCallback.onPullAtom(CAR_WATCHDOG_SYSTEM_IO_USAGE_SUMMARY,
3125                         events)).isEqualTo(PULL_SUCCESS);
3126 
3127         assertWithMessage("Pulled system I/O usage summary atoms within the same week")
3128                 .that(mPulledSystemIoUsageSummaries).isEmpty();
3129 
3130         mTimeSource.updateNow(/* numDaysAgo= */ 0);
3131 
3132         assertWithMessage("Status of stats pull atom callback after a week")
3133                 .that(mStatsPullAtomCallback.onPullAtom(CAR_WATCHDOG_SYSTEM_IO_USAGE_SUMMARY,
3134                         events)).isEqualTo(PULL_SUCCESS);
3135 
3136         expectedSummaries = verifyAndGetSystemIoUsageSummaries(
3137                 mTimeSource.getCurrentDate().minus(1, ChronoUnit.WEEKS));
3138 
3139         assertWithMessage("Pulled system I/O usage summary atoms after a week")
3140                 .that(mPulledSystemIoUsageSummaries).containsExactlyElementsIn(expectedSummaries);
3141 
3142         verifyNoMoreInteractions(mMockWatchdogStorage);
3143     }
3144 
3145     @Test
testPullUidIoUsageSummaryAtomsForTopUids()3146     public void testPullUidIoUsageSummaryAtomsForTopUids() throws Exception {
3147         injectPackageInfos(Arrays.asList(
3148                 constructPackageManagerPackageInfo("system_package.critical.A", 10000345, null),
3149                 constructPackageManagerPackageInfo("third_party_package.B", 10004675, null),
3150                 constructPackageManagerPackageInfo("system_package.critical.B", 10010001, null),
3151                 constructPackageManagerPackageInfo("vendor_package.non_critical", 10110004, null),
3152                 constructPackageManagerPackageInfo("third_party_package.A", 10110005,
3153                         "third_party_shared_package")));
3154 
3155         List<StatsEvent> events = new ArrayList<>();
3156         assertWithMessage("Stats pull atom callback status")
3157                 .that(mStatsPullAtomCallback.onPullAtom(CAR_WATCHDOG_UID_IO_USAGE_SUMMARY,
3158                         events)).isEqualTo(PULL_SUCCESS);
3159 
3160         List<AtomsProto.CarWatchdogUidIoUsageSummary> expectedSummaries =
3161                 verifyAndGetUidIoUsageSummaries(
3162                         mTimeSource.getCurrentDate().minus(RETENTION_PERIOD),
3163                         /* expectUids= */ Arrays.asList(10010001, 10110004, 10110005));
3164 
3165         assertWithMessage(String.format("Pulled uid I/O usage summary atoms for top %d UIDs",
3166                 UID_IO_USAGE_SUMMARY_TOP_COUNT)).that(mPulledUidIoUsageSummaries)
3167                 .containsExactlyElementsIn(expectedSummaries);
3168     }
3169 
3170     @Test
testPullUidIoUsageSummaryAtomsWithRestart()3171     public void testPullUidIoUsageSummaryAtomsWithRestart() throws Exception {
3172         injectPackageInfos(Arrays.asList(
3173                 constructPackageManagerPackageInfo("system_package.critical", 10010001, null),
3174                 constructPackageManagerPackageInfo("vendor_package.non_critical", 10110004, null),
3175                 constructPackageManagerPackageInfo("third_party_package.A", 10110005,
3176                         "third_party_shared_package")));
3177 
3178         List<StatsEvent> events = new ArrayList<>();
3179         assertWithMessage("Stats pull atom callback status")
3180                 .that(mStatsPullAtomCallback.onPullAtom(CAR_WATCHDOG_UID_IO_USAGE_SUMMARY,
3181                         events)).isEqualTo(PULL_SUCCESS);
3182 
3183         List<AtomsProto.CarWatchdogUidIoUsageSummary> expectedSummaries =
3184                 verifyAndGetUidIoUsageSummaries(
3185                         mTimeSource.getCurrentDate().minus(RETENTION_PERIOD),
3186                         /* expectUids= */ Arrays.asList(10010001, 10110004, 10110005));
3187 
3188         assertWithMessage("First pulled uid I/O usage summary atoms")
3189                 .that(mPulledUidIoUsageSummaries).containsExactlyElementsIn(expectedSummaries);
3190         mPulledUidIoUsageSummaries.clear();
3191 
3192         restartService(/* totalRestarts= */ 1);
3193 
3194         assertWithMessage("Status of stats pull atom callback after restart")
3195                 .that(mStatsPullAtomCallback.onPullAtom(CAR_WATCHDOG_UID_IO_USAGE_SUMMARY,
3196                         events)).isEqualTo(PULL_SUCCESS);
3197 
3198         assertWithMessage("Pulled uid I/O usage summary atoms after restart")
3199                 .that(mPulledUidIoUsageSummaries).isEmpty();
3200 
3201         verifyNoMoreInteractions(mMockWatchdogStorage);
3202     }
3203 
3204     @Test
testPullUidIoUsageSummaryAtomsWithDateChange()3205     public void testPullUidIoUsageSummaryAtomsWithDateChange() throws Exception {
3206         injectPackageInfos(Arrays.asList(
3207                 constructPackageManagerPackageInfo("system_package.critical", 10010001, null),
3208                 constructPackageManagerPackageInfo("vendor_package.non_critical", 10110004, null),
3209                 constructPackageManagerPackageInfo("third_party_package.A", 10110005,
3210                         "third_party_shared_package")));
3211 
3212         mTimeSource.updateNow(/* numDaysAgo= */ 7);
3213 
3214         List<StatsEvent> events = new ArrayList<>();
3215         assertWithMessage("Stats pull atom callback status")
3216                 .that(mStatsPullAtomCallback.onPullAtom(CAR_WATCHDOG_UID_IO_USAGE_SUMMARY,
3217                         events)).isEqualTo(PULL_SUCCESS);
3218 
3219         List<AtomsProto.CarWatchdogUidIoUsageSummary> expectedSummaries =
3220                 verifyAndGetUidIoUsageSummaries(
3221                         mTimeSource.getCurrentDate().minus(RETENTION_PERIOD),
3222                         /* expectUids= */ Arrays.asList(10010001, 10110004, 10110005));
3223 
3224         assertWithMessage("First pulled uid I/O usage summary atoms")
3225                 .that(mPulledUidIoUsageSummaries).containsExactlyElementsIn(expectedSummaries);
3226         mPulledUidIoUsageSummaries.clear();
3227 
3228         mTimeSource.updateNow(/* numDaysAgo= */ 6);
3229 
3230         assertWithMessage("Status of stats pull atom callback within the same week")
3231                 .that(mStatsPullAtomCallback.onPullAtom(CAR_WATCHDOG_UID_IO_USAGE_SUMMARY,
3232                         events)).isEqualTo(PULL_SUCCESS);
3233 
3234         assertWithMessage("Pulled uid I/O usage summary atoms within the same week")
3235                 .that(mPulledUidIoUsageSummaries).isEmpty();
3236 
3237         mTimeSource.updateNow(/* numDaysAgo= */ 0);
3238 
3239         assertWithMessage("Status of stats pull atom callback after a week")
3240                 .that(mStatsPullAtomCallback.onPullAtom(CAR_WATCHDOG_UID_IO_USAGE_SUMMARY,
3241                         events)).isEqualTo(PULL_SUCCESS);
3242 
3243         expectedSummaries = verifyAndGetUidIoUsageSummaries(
3244                 mTimeSource.getCurrentDate().minus(1, ChronoUnit.WEEKS),
3245                 /* expectUids= */ Arrays.asList(10010001, 10110004, 10110005));
3246 
3247         assertWithMessage("Pulled uid I/O usage summary atoms after a week")
3248                 .that(mPulledUidIoUsageSummaries).containsExactlyElementsIn(expectedSummaries);
3249 
3250         verifyNoMoreInteractions(mMockWatchdogStorage);
3251     }
3252 
3253     @Test
testPullInvalidAtoms()3254     public void testPullInvalidAtoms() throws Exception {
3255         List<StatsEvent> actualEvents = new ArrayList<>();
3256         assertWithMessage("Stats pull atom callback status").that(mStatsPullAtomCallback.onPullAtom(
3257                 0, actualEvents)).isEqualTo(PULL_SKIP);
3258         assertWithMessage("Pulled stats events").that(actualEvents).isEmpty();
3259     }
3260 
3261     @Test
testGetPackageInfosForUids()3262     public void testGetPackageInfosForUids() throws Exception {
3263         injectPackageInfos(Arrays.asList(
3264                 constructPackageManagerPackageInfo(
3265                         "system_package.A", 6001, null, ApplicationInfo.FLAG_SYSTEM, 0),
3266                 constructPackageManagerPackageInfo(
3267                         "vendor_package.B", 5100, null, 0, ApplicationInfo.PRIVATE_FLAG_OEM),
3268                 constructPackageManagerPackageInfo(
3269                         "vendor_package.C", 1345678, null, 0, ApplicationInfo.PRIVATE_FLAG_ODM),
3270                 constructPackageManagerPackageInfo("third_party_package.D", 120056, null)));
3271 
3272         int[] uids = new int[]{6001, 5100, 120056, 1345678};
3273         List<PackageInfo> actualPackageInfos = mWatchdogServiceForSystemImpl.getPackageInfosForUids(
3274                 uids, new ArrayList<>());
3275 
3276         List<PackageInfo> expectedPackageInfos = Arrays.asList(
3277                 constructPackageInfo("system_package.A", 6001, new ArrayList<>(),
3278                         UidType.NATIVE, ComponentType.SYSTEM, ApplicationCategoryType.OTHERS),
3279                 constructPackageInfo("vendor_package.B", 5100, new ArrayList<>(),
3280                         UidType.NATIVE, ComponentType.VENDOR, ApplicationCategoryType.OTHERS),
3281                 constructPackageInfo("third_party_package.D", 120056, new ArrayList<>(),
3282                         UidType.APPLICATION, ComponentType.THIRD_PARTY,
3283                         ApplicationCategoryType.OTHERS),
3284                 constructPackageInfo("vendor_package.C", 1345678, new ArrayList<>(),
3285                         UidType.APPLICATION, ComponentType.VENDOR,
3286                         ApplicationCategoryType.OTHERS));
3287 
3288         assertPackageInfoEquals(actualPackageInfos, expectedPackageInfos);
3289     }
3290 
3291     @Test
testGetPackageInfosWithSharedUids()3292     public void testGetPackageInfosWithSharedUids() throws Exception {
3293         injectPackageInfos(Arrays.asList(
3294                 constructPackageManagerPackageInfo("system_package.A", 6050,
3295                         "system_shared_package", ApplicationInfo.FLAG_UPDATED_SYSTEM_APP, 0),
3296                 constructPackageManagerPackageInfo("system_package.B", 110035,
3297                         "vendor_shared_package", 0, ApplicationInfo.PRIVATE_FLAG_PRODUCT),
3298                 constructPackageManagerPackageInfo("vendor_package.C", 110035,
3299                         "vendor_shared_package", 0, ApplicationInfo.PRIVATE_FLAG_VENDOR),
3300                 constructPackageManagerPackageInfo(
3301                         "third_party_package.D", 6050, "system_shared_package"),
3302                 constructPackageManagerPackageInfo(
3303                         "third_party_package.E", 110035, "vendor_shared_package"),
3304                 constructPackageManagerPackageInfo(
3305                         "third_party_package.F", 120078, "third_party_shared_package")));
3306 
3307         int[] uids = new int[]{6050, 110035, 120056, 120078};
3308         List<PackageInfo> actualPackageInfos = mWatchdogServiceForSystemImpl.getPackageInfosForUids(
3309                 uids, new ArrayList<>());
3310 
3311         List<PackageInfo> expectedPackageInfos = Arrays.asList(
3312                 constructPackageInfo("shared:system_shared_package", 6050,
3313                         Arrays.asList("system_package.A", "third_party_package.D"),
3314                         UidType.NATIVE, ComponentType.SYSTEM, ApplicationCategoryType.OTHERS),
3315                 constructPackageInfo("shared:vendor_shared_package", 110035,
3316                         Arrays.asList("vendor_package.C", "system_package.B",
3317                                 "third_party_package.E"), UidType.APPLICATION,
3318                         ComponentType.VENDOR, ApplicationCategoryType.OTHERS),
3319                 constructPackageInfo("shared:third_party_shared_package", 120078,
3320                         Collections.singletonList("third_party_package.F"),
3321                         UidType.APPLICATION,  ComponentType.THIRD_PARTY,
3322                         ApplicationCategoryType.OTHERS));
3323 
3324         assertPackageInfoEquals(actualPackageInfos, expectedPackageInfos);
3325     }
3326 
3327     @Test
testGetPackageInfosForUidsWithVendorPackagePrefixes()3328     public void testGetPackageInfosForUidsWithVendorPackagePrefixes() throws Exception {
3329         injectPackageInfos(Arrays.asList(
3330                 constructPackageManagerPackageInfo(
3331                         "vendor_package.A", 110034, null, 0, ApplicationInfo.PRIVATE_FLAG_PRODUCT),
3332                 constructPackageManagerPackageInfo("vendor_pkg.B", 110035,
3333                         "vendor_shared_package", ApplicationInfo.FLAG_SYSTEM, 0),
3334                 constructPackageManagerPackageInfo(
3335                         "third_party_package.C", 110035, "vendor_shared_package"),
3336                 constructPackageManagerPackageInfo(
3337                         "third_party_package.D", 110035, "vendor_shared_package"),
3338                 constructPackageManagerPackageInfo(
3339                         "third_party_package.F", 120078, "third_party_shared_package"),
3340                 constructPackageManagerPackageInfo("vndr_pkg.G", 126345, "vendor_package.shared",
3341                         ApplicationInfo.FLAG_SYSTEM, 0),
3342                 /*
3343                  * A 3p package pretending to be a vendor package because 3p packages won't have the
3344                  * required flags.
3345                  */
3346                 constructPackageManagerPackageInfo("vendor_package.imposter", 123456, null, 0, 0)));
3347 
3348         int[] uids = new int[]{110034, 110035, 120078, 126345, 123456};
3349         List<PackageInfo> actualPackageInfos = mWatchdogServiceForSystemImpl.getPackageInfosForUids(
3350                 uids, Arrays.asList("vendor_package.", "vendor_pkg.", "shared:vendor_package."));
3351 
3352         List<PackageInfo> expectedPackageInfos = Arrays.asList(
3353                 constructPackageInfo("vendor_package.A", 110034, new ArrayList<>(),
3354                         UidType.APPLICATION, ComponentType.VENDOR, ApplicationCategoryType.OTHERS),
3355                 constructPackageInfo("shared:vendor_shared_package", 110035,
3356                         Arrays.asList("vendor_pkg.B", "third_party_package.C",
3357                                 "third_party_package.D"), UidType.APPLICATION,
3358                         ComponentType.VENDOR, ApplicationCategoryType.OTHERS),
3359                 constructPackageInfo("shared:third_party_shared_package", 120078,
3360                         Collections.singletonList("third_party_package.F"), UidType.APPLICATION,
3361                         ComponentType.THIRD_PARTY, ApplicationCategoryType.OTHERS),
3362                 constructPackageInfo("shared:vendor_package.shared", 126345,
3363                         Collections.singletonList("vndr_pkg.G"), UidType.APPLICATION,
3364                         ComponentType.VENDOR, ApplicationCategoryType.OTHERS),
3365                 constructPackageInfo("vendor_package.imposter", 123456,
3366                         new ArrayList<>(), UidType.APPLICATION, ComponentType.THIRD_PARTY,
3367                         ApplicationCategoryType.OTHERS));
3368 
3369         assertPackageInfoEquals(actualPackageInfos, expectedPackageInfos);
3370     }
3371 
3372     @Test
testGetPackageInfosForUidsWithMissingApplicationInfos()3373     public void testGetPackageInfosForUidsWithMissingApplicationInfos() throws Exception {
3374         injectPackageInfos(Arrays.asList(
3375                 constructPackageManagerPackageInfo(
3376                         "vendor_package.A", 110034, null, 0, ApplicationInfo.PRIVATE_FLAG_OEM),
3377                 constructPackageManagerPackageInfo("vendor_package.B", 110035,
3378                         "vendor_shared_package", 0, ApplicationInfo.PRIVATE_FLAG_VENDOR),
3379                 constructPackageManagerPackageInfo(
3380                         "third_party_package.C", 110035, "vendor_shared_package")));
3381 
3382         BiConsumer<Integer, String> addPackageToSharedUid = (uid, packageName) -> {
3383             List<String> packages = mPackagesBySharedUid.get(uid);
3384             if (packages == null) {
3385                 packages = new ArrayList<>();
3386             }
3387             packages.add(packageName);
3388             mPackagesBySharedUid.put(uid, packages);
3389         };
3390 
3391         addPackageToSharedUid.accept(110035, "third_party.package.G");
3392         mGenericPackageNameByUid.put(120056, "third_party.package.H");
3393         mGenericPackageNameByUid.put(120078, "shared:third_party_shared_package");
3394         addPackageToSharedUid.accept(120078, "third_party_package.I");
3395 
3396 
3397         int[] uids = new int[]{110034, 110035, 120056, 120078};
3398 
3399         List<PackageInfo> actualPackageInfos = mWatchdogServiceForSystemImpl.getPackageInfosForUids(
3400                 uids, new ArrayList<>());
3401 
3402         List<PackageInfo> expectedPackageInfos = Arrays.asList(
3403                 constructPackageInfo("vendor_package.A", 110034, new ArrayList<>(),
3404                         UidType.APPLICATION, ComponentType.VENDOR, ApplicationCategoryType.OTHERS),
3405                 constructPackageInfo("shared:vendor_shared_package", 110035,
3406                         Arrays.asList("vendor_package.B", "third_party_package.C",
3407                                 "third_party.package.G"),
3408                         UidType.APPLICATION, ComponentType.VENDOR, ApplicationCategoryType.OTHERS),
3409                 constructPackageInfo("third_party.package.H", 120056, new ArrayList<>(),
3410                         UidType.APPLICATION, ComponentType.UNKNOWN,
3411                         ApplicationCategoryType.OTHERS),
3412                 constructPackageInfo("shared:third_party_shared_package", 120078,
3413                         Collections.singletonList("third_party_package.I"),
3414                         UidType.APPLICATION, ComponentType.UNKNOWN,
3415                         ApplicationCategoryType.OTHERS));
3416 
3417         assertPackageInfoEquals(actualPackageInfos, expectedPackageInfos);
3418     }
3419 
3420     @Test
testSetProcessHealthCheckEnabled()3421     public void testSetProcessHealthCheckEnabled() throws Exception {
3422         mCarWatchdogService.controlProcessHealthCheck(true);
3423 
3424         verify(mMockCarWatchdogDaemon).controlProcessHealthCheck(eq(true));
3425     }
3426 
3427     @Test
testSetProcessHealthCheckEnabledWithDisconnectedDaemon()3428     public void testSetProcessHealthCheckEnabledWithDisconnectedDaemon() throws Exception {
3429         crashWatchdogDaemon();
3430 
3431         assertThrows(IllegalStateException.class,
3432                 () -> mCarWatchdogService.controlProcessHealthCheck(false));
3433 
3434         verify(mMockCarWatchdogDaemon, never()).controlProcessHealthCheck(anyBoolean());
3435     }
3436 
3437     @Test
testOveruseConfigurationCacheGetVendorPackagePrefixes()3438     public void testOveruseConfigurationCacheGetVendorPackagePrefixes() throws Exception {
3439         OveruseConfigurationCache cache = new OveruseConfigurationCache();
3440 
3441         cache.set(sampleInternalResourceOveruseConfigurations());
3442 
3443         assertWithMessage("Vendor package prefixes").that(cache.getVendorPackagePrefixes())
3444                 .containsExactly("vendor_package", "some_pkg_as_vendor_pkg");
3445     }
3446 
3447     @Test
testOveruseConfigurationCacheFetchThreshold()3448     public void testOveruseConfigurationCacheFetchThreshold() throws Exception {
3449         OveruseConfigurationCache cache = new OveruseConfigurationCache();
3450 
3451         cache.set(sampleInternalResourceOveruseConfigurations());
3452 
3453         InternalPerStateBytesSubject.assertWithMessage(
3454                 cache.fetchThreshold("system_package.non_critical.A", ComponentType.SYSTEM),
3455                 "System package with generic threshold")
3456                 .isEqualTo(constructPerStateBytes(10, 20, 30));
3457 
3458         InternalPerStateBytesSubject.assertWithMessage(
3459                 cache.fetchThreshold("system_package.A", ComponentType.SYSTEM),
3460                 "System package with package specific threshold")
3461                 .isEqualTo(constructPerStateBytes(40, 50, 60));
3462 
3463         InternalPerStateBytesSubject.assertWithMessage(
3464                 cache.fetchThreshold("system_package.MEDIA", ComponentType.SYSTEM),
3465                 "System package with media category threshold")
3466                 .isEqualTo(constructPerStateBytes(200, 400, 600));
3467 
3468         InternalPerStateBytesSubject.assertWithMessage(
3469                 cache.fetchThreshold("vendor_package.non_critical.A", ComponentType.VENDOR),
3470                 "Vendor package with generic threshold")
3471                 .isEqualTo(constructPerStateBytes(20, 40, 60));
3472 
3473         InternalPerStateBytesSubject.assertWithMessage(
3474                 cache.fetchThreshold("vendor_package.A", ComponentType.VENDOR),
3475                 "Vendor package with package specific threshold")
3476                 .isEqualTo(constructPerStateBytes(80, 100, 120));
3477 
3478         InternalPerStateBytesSubject.assertWithMessage(
3479                 cache.fetchThreshold("vendor_package.MEDIA", ComponentType.VENDOR),
3480                 "Vendor package with media category threshold")
3481                 .isEqualTo(constructPerStateBytes(200, 400, 600));
3482 
3483         InternalPerStateBytesSubject.assertWithMessage(
3484                 cache.fetchThreshold("third_party_package.A",
3485                         ComponentType.THIRD_PARTY),
3486                 "3p package with generic threshold").isEqualTo(constructPerStateBytes(30, 60, 90));
3487 
3488         InternalPerStateBytesSubject.assertWithMessage(
3489                 cache.fetchThreshold("third_party_package.MAPS", ComponentType.VENDOR),
3490                 "3p package with maps category threshold")
3491                 .isEqualTo(constructPerStateBytes(2200, 4400, 6600));
3492     }
3493 
3494     @Test
testOveruseConfigurationCacheIsSafeToKill()3495     public void testOveruseConfigurationCacheIsSafeToKill() throws Exception {
3496         OveruseConfigurationCache cache = new OveruseConfigurationCache();
3497 
3498         cache.set(sampleInternalResourceOveruseConfigurations());
3499 
3500         assertWithMessage("isSafeToKill non-critical system package").that(cache.isSafeToKill(
3501                 "system_package.non_critical.A", ComponentType.SYSTEM, null)).isTrue();
3502 
3503         assertWithMessage("isSafeToKill shared non-critical system package")
3504                 .that(cache.isSafeToKill("system_package.A", ComponentType.SYSTEM,
3505                         Collections.singletonList("system_package.non_critical.A"))).isTrue();
3506 
3507         assertWithMessage("isSafeToKill non-critical vendor package").that(cache.isSafeToKill(
3508                 "vendor_package.non_critical.A", ComponentType.VENDOR, null)).isTrue();
3509 
3510         assertWithMessage("isSafeToKill shared non-critical vendor package")
3511                 .that(cache.isSafeToKill("vendor_package.A", ComponentType.VENDOR,
3512                         Collections.singletonList("vendor_package.non_critical.A"))).isTrue();
3513 
3514         assertWithMessage("isSafeToKill 3p package").that(cache.isSafeToKill(
3515                 "third_party_package.A", ComponentType.THIRD_PARTY, null)).isTrue();
3516 
3517         assertWithMessage("isSafeToKill critical system package").that(cache.isSafeToKill(
3518                 "system_package.A", ComponentType.SYSTEM, null)).isFalse();
3519 
3520         assertWithMessage("isSafeToKill critical vendor package").that(cache.isSafeToKill(
3521                 "vendor_package.A", ComponentType.VENDOR, null)).isFalse();
3522     }
3523 
3524     @Test
testOverwriteOveruseConfigurationCache()3525     public void testOverwriteOveruseConfigurationCache() throws Exception {
3526         OveruseConfigurationCache cache = new OveruseConfigurationCache();
3527 
3528         cache.set(sampleInternalResourceOveruseConfigurations());
3529 
3530         cache.set(new ArrayList<>());
3531 
3532         assertWithMessage("Vendor package prefixes").that(cache.getVendorPackagePrefixes())
3533                 .isEmpty();
3534 
3535         InternalPerStateBytesSubject.assertWithMessage(
3536                 cache.fetchThreshold("system_package.A", ComponentType.SYSTEM),
3537                 "System package with default threshold")
3538                 .isEqualTo(OveruseConfigurationCache.DEFAULT_THRESHOLD);
3539 
3540         InternalPerStateBytesSubject.assertWithMessage(
3541                 cache.fetchThreshold("vendor_package.A", ComponentType.VENDOR),
3542                 "Vendor package with default threshold")
3543                 .isEqualTo(OveruseConfigurationCache.DEFAULT_THRESHOLD);
3544 
3545         InternalPerStateBytesSubject.assertWithMessage(
3546                 cache.fetchThreshold("third_party_package.A", ComponentType.THIRD_PARTY),
3547                 "3p package with default threshold")
3548                 .isEqualTo(OveruseConfigurationCache.DEFAULT_THRESHOLD);
3549 
3550         assertWithMessage("isSafeToKill any system package").that(cache.isSafeToKill(
3551                 "system_package.non_critical.A", ComponentType.SYSTEM, null)).isFalse();
3552 
3553         assertWithMessage("isSafeToKill any vendor package").that(cache.isSafeToKill(
3554                 "vendor_package.non_critical.A", ComponentType.VENDOR, null)).isFalse();
3555     }
3556 
constructPerStateBytes( long fgBytes, long bgBytes, long gmBytes)3557     public static android.automotive.watchdog.PerStateBytes constructPerStateBytes(
3558             long fgBytes, long bgBytes, long gmBytes) {
3559         android.automotive.watchdog.PerStateBytes perStateBytes =
3560                 new android.automotive.watchdog.PerStateBytes();
3561         perStateBytes.foregroundBytes = fgBytes;
3562         perStateBytes.backgroundBytes = bgBytes;
3563         perStateBytes.garageModeBytes = gmBytes;
3564         return perStateBytes;
3565     }
3566 
mockWatchdogDaemon()3567     private void mockWatchdogDaemon() throws Exception {
3568         when(mMockBinder.queryLocalInterface(anyString())).thenReturn(mMockCarWatchdogDaemon);
3569         when(mMockCarWatchdogDaemon.asBinder()).thenReturn(mMockBinder);
3570         doReturn(mMockBinder).when(() -> ServiceManager.getService(CAR_WATCHDOG_DAEMON_INTERFACE));
3571         when(mMockCarWatchdogDaemon.getResourceOveruseConfigurations()).thenReturn(
3572                 sampleInternalResourceOveruseConfigurations());
3573         mIsDaemonCrashed = false;
3574     }
3575 
mockWatchdogStorage()3576     private void mockWatchdogStorage() {
3577         when(mMockWatchdogStorage.saveUserPackageSettings(any())).thenAnswer((args) -> {
3578             mUserPackageSettingsEntries.addAll(args.getArgument(0));
3579             return true;
3580         });
3581         when(mMockWatchdogStorage.saveIoUsageStats(any())).thenAnswer((args) -> {
3582             List<WatchdogStorage.IoUsageStatsEntry> ioUsageStatsEntries = args.getArgument(0);
3583             for (WatchdogStorage.IoUsageStatsEntry entry : ioUsageStatsEntries) {
3584                 mIoUsageStatsEntries.add(
3585                         new WatchdogStorage.IoUsageStatsEntry(entry.userId, entry.packageName,
3586                                 new WatchdogPerfHandler.PackageIoUsage(
3587                                         entry.ioUsage.getInternalIoOveruseStats(),
3588                                         entry.ioUsage.getForgivenWriteBytes(),
3589                                         entry.ioUsage.getForgivenOveruses(),
3590                                         entry.ioUsage.getTotalTimesKilled())));
3591             }
3592             return true;
3593         });
3594         when(mMockWatchdogStorage.getUserPackageSettings()).thenReturn(mUserPackageSettingsEntries);
3595         when(mMockWatchdogStorage.getTodayIoUsageStats()).thenReturn(mIoUsageStatsEntries);
3596         when(mMockWatchdogStorage.getDailySystemIoUsageSummaries(anyLong(), anyLong())).thenAnswer(
3597                 args -> sampleDailyIoUsageSummariesForAWeek(args.getArgument(0),
3598                         SYSTEM_DAILY_IO_USAGE_SUMMARY_MULTIPLIER));
3599         when(mMockWatchdogStorage.getTopUsersDailyIoUsageSummaries(
3600                 anyInt(), anyLong(), anyLong(), anyLong())).thenAnswer(args -> {
3601                     ArrayList<WatchdogStorage.UserPackageDailySummaries> summaries =
3602                             new ArrayList<>();
3603                     for (int i = 0; i < mGenericPackageNameByUid.size(); ++i) {
3604                         int uid = mGenericPackageNameByUid.keyAt(i);
3605                         summaries.add(new WatchdogStorage.UserPackageDailySummaries(
3606                                 UserHandle.getUserId(uid), mGenericPackageNameByUid.valueAt(i),
3607                                 sampleDailyIoUsageSummariesForAWeek(args.getArgument(2),
3608                                         /* sysOrUidMultiplier= */ uid)));
3609                     }
3610                     summaries.sort(Comparator.comparingLong(WatchdogStorage
3611                             .UserPackageDailySummaries::getTotalWrittenBytes).reversed());
3612                     return summaries;
3613                 });
3614     }
3615 
setupUsers()3616     private void setupUsers() {
3617         when(mMockContext.getSystemService(Context.USER_SERVICE)).thenReturn(mMockUserManager);
3618         mockUmGetAllUsers(mMockUserManager, new UserInfo[0]);
3619     }
3620 
initService(int wantedInvocations)3621     private void initService(int wantedInvocations) throws Exception {
3622         mTimeSource.updateNow(/* numDaysAgo= */ 0);
3623         mCarWatchdogService.setOveruseHandlingDelay(OVERUSE_HANDLING_DELAY_MILLS);
3624         mCarWatchdogService.setUidIoUsageSummaryTopCount(
3625                 UID_IO_USAGE_SUMMARY_TOP_COUNT);
3626         mCarWatchdogService.init();
3627         captureCarPowerListeners(wantedInvocations);
3628         captureBroadcastReceiver(wantedInvocations);
3629         captureCarUxRestrictionsChangeListener(wantedInvocations);
3630         captureAndVerifyRegistrationWithDaemon(/* waitOnMain= */ true);
3631         verifyDatabaseInit(wantedInvocations);
3632         captureStatsPullAtomCallback(wantedInvocations);
3633     }
3634 
restartService(int totalRestarts)3635     private void restartService(int totalRestarts) throws Exception {
3636         setCarPowerState(CarPowerStateListener.SHUTDOWN_PREPARE);
3637         setCarPowerState(CarPowerStateListener.SHUTDOWN_ENTER);
3638         mCarWatchdogService.release();
3639         verify(mMockWatchdogStorage, times(totalRestarts)).saveIoUsageStats(any());
3640         verify(mMockWatchdogStorage, times(totalRestarts)).saveUserPackageSettings(any());
3641         verify(mMockWatchdogStorage, times(totalRestarts)).release();
3642         mCarWatchdogService = new CarWatchdogService(mMockContext, mMockWatchdogStorage,
3643                 mMockUserNotificationHelper, mTimeSource);
3644         initService(/* wantedInvocations= */ totalRestarts + 1);
3645     }
3646 
captureCarPowerListeners(int wantedInvocations)3647     private void captureCarPowerListeners(int wantedInvocations) {
3648         verify(mMockCarPowerManagementService, times(wantedInvocations)).registerListener(
3649                 mICarPowerStateListenerCaptor.capture());
3650         mCarPowerStateListener = mICarPowerStateListenerCaptor.getValue();
3651         assertWithMessage("Car power state listener").that(mCarPowerStateListener).isNotNull();
3652 
3653         verify(mMockCarPowerManagementService, times(wantedInvocations)).addPowerPolicyListener(
3654                 any(), mICarPowerPolicyListenerCaptor.capture());
3655         mCarPowerPolicyListener = mICarPowerPolicyListenerCaptor.getValue();
3656         assertWithMessage("Car power policy listener").that(mCarPowerPolicyListener).isNotNull();
3657     }
3658 
captureBroadcastReceiver(int wantedInvocations)3659     private void captureBroadcastReceiver(int wantedInvocations) {
3660         verify(mMockContext, times(wantedInvocations))
3661                 .registerReceiverForAllUsers(mBroadcastReceiverCaptor.capture(), any(), any(),
3662                         any());
3663         mBroadcastReceiver = mBroadcastReceiverCaptor.getValue();
3664         assertWithMessage("Broadcast receiver").that(mBroadcastReceiver).isNotNull();
3665     }
3666 
captureCarUxRestrictionsChangeListener(int wantedInvocations)3667     private void captureCarUxRestrictionsChangeListener(int wantedInvocations) {
3668         verify(mMockCarUxRestrictionsManagerService, times(wantedInvocations))
3669                 .getCurrentUxRestrictions();
3670         verify(mMockCarUxRestrictionsManagerService, times(wantedInvocations))
3671                 .registerUxRestrictionsChangeListener(mICarUxRestrictionsChangeListener.capture(),
3672                         eq(Display.DEFAULT_DISPLAY));
3673         mCarUxRestrictionsChangeListener = mICarUxRestrictionsChangeListener.getValue();
3674         assertWithMessage("UX restrictions change listener").that(mCarUxRestrictionsChangeListener)
3675                 .isNotNull();
3676     }
3677 
captureAndVerifyRegistrationWithDaemon(boolean waitOnMain)3678     private void captureAndVerifyRegistrationWithDaemon(boolean waitOnMain) throws Exception {
3679         if (waitOnMain) {
3680             // Registering to daemon is done on the main thread. To ensure the registration
3681             // completes before verification, execute an empty block on the main thread.
3682             CarServiceUtils.runOnMainSync(() -> {});
3683         }
3684 
3685         verify(mMockCarWatchdogDaemon, atLeastOnce()).asBinder();
3686 
3687         verify(mMockBinder, atLeastOnce()).linkToDeath(mDeathRecipientCaptor.capture(), anyInt());
3688         mCarWatchdogDaemonBinderDeathRecipient = mDeathRecipientCaptor.getValue();
3689         assertWithMessage("Watchdog daemon binder death recipient")
3690                 .that(mCarWatchdogDaemonBinderDeathRecipient).isNotNull();
3691 
3692         verify(mMockCarWatchdogDaemon, atLeastOnce()).registerCarWatchdogService(
3693                 mICarWatchdogServiceForSystemCaptor.capture());
3694         mWatchdogServiceForSystemImpl = mICarWatchdogServiceForSystemCaptor.getValue();
3695         assertWithMessage("Car watchdog service for system")
3696                 .that(mWatchdogServiceForSystemImpl).isNotNull();
3697 
3698         verify(mMockCarWatchdogDaemon, atLeastOnce()).notifySystemStateChange(
3699                 StateType.GARAGE_MODE, GarageMode.GARAGE_MODE_OFF, MISSING_ARG_VALUE);
3700 
3701         // Once registration with daemon completes, the service post a new message on the main
3702         // thread to fetch and sync resource overuse configs.
3703         CarServiceUtils.runOnMainSync(() -> {});
3704 
3705         verify(mMockCarWatchdogDaemon, atLeastOnce()).getResourceOveruseConfigurations();
3706     }
3707 
verifyDatabaseInit(int wantedInvocations)3708     private void verifyDatabaseInit(int wantedInvocations) throws Exception {
3709         /*
3710          * Database read is posted on a separate handler thread. Wait until the handler thread has
3711          * processed the database read request before verifying.
3712          */
3713         CarServiceUtils.getHandlerThread(CarWatchdogService.class.getSimpleName())
3714                 .getThreadHandler().post(() -> {});
3715         verify(mMockWatchdogStorage, times(wantedInvocations)).syncUsers(any());
3716         verify(mMockWatchdogStorage, times(wantedInvocations)).getUserPackageSettings();
3717         verify(mMockWatchdogStorage, times(wantedInvocations)).getTodayIoUsageStats();
3718         verify(mMockWatchdogStorage, times(wantedInvocations)).getNotForgivenHistoricalIoOveruses(
3719                 RECURRING_OVERUSE_PERIOD_IN_DAYS);
3720     }
3721 
captureStatsPullAtomCallback(int wantedInvocations)3722     private void captureStatsPullAtomCallback(int wantedInvocations) {
3723         verify(mMockStatsManager, times(wantedInvocations)).setPullAtomCallback(
3724                 eq(CAR_WATCHDOG_SYSTEM_IO_USAGE_SUMMARY), any(PullAtomMetadata.class),
3725                 any(Executor.class), mStatsPullAtomCallbackCaptor.capture());
3726         verify(mMockStatsManager, times(wantedInvocations)).setPullAtomCallback(
3727                 eq(CAR_WATCHDOG_UID_IO_USAGE_SUMMARY), any(PullAtomMetadata.class),
3728                 any(Executor.class), mStatsPullAtomCallbackCaptor.capture());
3729 
3730         // The same callback is set in the above calls, so fetch the latest captured callback.
3731         mStatsPullAtomCallback = mStatsPullAtomCallbackCaptor.getValue();
3732         assertWithMessage("Stats pull atom callback").that(mStatsPullAtomCallback).isNotNull();
3733     }
3734 
mockBuildStatsEventCalls()3735     private void mockBuildStatsEventCalls() {
3736         when(CarStatsLog.buildStatsEvent(eq(CAR_WATCHDOG_SYSTEM_IO_USAGE_SUMMARY),
3737                 any(byte[].class))).thenAnswer(args -> {
3738                     mPulledSystemIoUsageSummaries.add(AtomsProto.CarWatchdogSystemIoUsageSummary
3739                             .newBuilder()
3740                             .setIoUsageSummary(AtomsProto.CarWatchdogIoUsageSummary.parseFrom(
3741                                     (byte[]) args.getArgument(1)))
3742                             .build());
3743                     // Returned event is not used in tests, so return an empty event.
3744                     return StatsEvent.newBuilder().build();
3745                 });
3746 
3747         when(CarStatsLog.buildStatsEvent(eq(CAR_WATCHDOG_UID_IO_USAGE_SUMMARY), anyInt(),
3748                 any(byte[].class))).thenAnswer(args -> {
3749                     mPulledUidIoUsageSummaries.add(AtomsProto.CarWatchdogUidIoUsageSummary
3750                             .newBuilder()
3751                             .setUid(args.getArgument(1))
3752                             .setIoUsageSummary(AtomsProto.CarWatchdogIoUsageSummary.parseFrom(
3753                                     (byte[]) args.getArgument(2)))
3754                             .build());
3755                     // Returned event is not used in tests, so return an empty event.
3756                     return StatsEvent.newBuilder().build();
3757                 });
3758     }
3759 
mockPackageManager()3760     private void mockPackageManager() throws Exception {
3761         when(mMockPackageManager.getNamesForUids(any())).thenAnswer(args -> {
3762             int[] uids = args.getArgument(0);
3763             String[] names = new String[uids.length];
3764             for (int i = 0; i < uids.length; ++i) {
3765                 names[i] = mGenericPackageNameByUid.get(uids[i], null);
3766             }
3767             return names;
3768         });
3769         when(mMockPackageManager.getPackagesForUid(anyInt())).thenAnswer(args -> {
3770             int uid = args.getArgument(0);
3771             List<String> packages = mPackagesBySharedUid.get(uid);
3772             return packages.toArray(new String[0]);
3773         });
3774         when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(),
3775                 any(UserHandle.class))).thenAnswer(args -> {
3776                     int userId = ((UserHandle) args.getArgument(2)).getIdentifier();
3777                     String userPackageId = userId + ":" + args.getArgument(0);
3778                     android.content.pm.PackageInfo packageInfo =
3779                             mPmPackageInfoByUserPackage.get(userPackageId);
3780                     if (packageInfo == null) {
3781                         throw new PackageManager.NameNotFoundException(
3782                                 "User package id '" + userPackageId + "' not found");
3783                     }
3784                     return packageInfo.applicationInfo;
3785                 });
3786         when(mMockPackageManager.getPackageInfoAsUser(anyString(), anyInt(), anyInt()))
3787                 .thenAnswer(args -> {
3788                     String userPackageId = args.getArgument(2) + ":" + args.getArgument(0);
3789                     android.content.pm.PackageInfo packageInfo =
3790                             mPmPackageInfoByUserPackage.get(userPackageId);
3791                     if (packageInfo == null) {
3792                         throw new PackageManager.NameNotFoundException(
3793                                 "User package id '" + userPackageId + "' not found");
3794                     }
3795                     return packageInfo;
3796                 });
3797         when(mMockPackageManager.getInstalledPackagesAsUser(anyInt(), anyInt()))
3798                 .thenAnswer(args -> {
3799                     int userId = args.getArgument(1);
3800                     List<android.content.pm.PackageInfo> packageInfos = new ArrayList<>();
3801                     for (android.content.pm.PackageInfo packageInfo :
3802                             mPmPackageInfoByUserPackage.values()) {
3803                         if (UserHandle.getUserId(packageInfo.applicationInfo.uid) == userId) {
3804                             packageInfos.add(packageInfo);
3805                         }
3806                     }
3807                     return packageInfos;
3808                 });
3809         when(mMockPackageManager.getPackageUidAsUser(anyString(), anyInt()))
3810                 .thenAnswer(args -> {
3811                     String userPackageId = args.getArgument(1) + ":" + args.getArgument(0);
3812                     android.content.pm.PackageInfo packageInfo =
3813                             mPmPackageInfoByUserPackage.get(userPackageId);
3814                     if (packageInfo == null) {
3815                         throw new PackageManager.NameNotFoundException(
3816                                 "User package id '" + userPackageId + "' not found");
3817                     }
3818                     return packageInfo.applicationInfo.uid;
3819                 });
3820 
3821         doAnswer((args) -> {
3822             String value = args.getArgument(3) + ":" + args.getArgument(0);
3823             mDisabledUserPackages.add(value);
3824             return null;
3825         }).when(mSpiedPackageManager).setApplicationEnabledSetting(
3826                 anyString(), eq(COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED), anyInt(),
3827                 anyInt(), anyString());
3828         doReturn(COMPONENT_ENABLED_STATE_ENABLED).when(mSpiedPackageManager)
3829                 .getApplicationEnabledSetting(anyString(), anyInt());
3830     }
3831 
setCarPowerState(int powerState)3832     private void setCarPowerState(int powerState) throws Exception {
3833         when(mMockCarPowerManagementService.getPowerState()).thenReturn(powerState);
3834         mCarPowerStateListener.onStateChanged(powerState);
3835     }
3836 
setDisplayStateEnabled(boolean isEnabled)3837     private void setDisplayStateEnabled(boolean isEnabled) throws Exception {
3838         int[] enabledComponents = new int[]{};
3839         int[] disabledComponents = new int[]{};
3840         if (isEnabled) {
3841             enabledComponents = new int[]{PowerComponent.DISPLAY};
3842         } else {
3843             disabledComponents = new int[]{PowerComponent.DISPLAY};
3844         }
3845         mCarPowerPolicyListener.onPolicyChanged(
3846                 new CarPowerPolicy(/* policyId= */ "", enabledComponents, disabledComponents),
3847                 /* accumulatedPolicy= */ null);
3848     }
3849 
setRequiresDistractionOptimization(boolean isRequires)3850     private void setRequiresDistractionOptimization(boolean isRequires) throws Exception {
3851         CarUxRestrictions.Builder builder = new CarUxRestrictions.Builder(
3852                 isRequires, UX_RESTRICTIONS_BASELINE, /* time= */ 0);
3853         mCarUxRestrictionsChangeListener.onUxRestrictionsChanged(builder.build());
3854     }
3855 
crashWatchdogDaemon()3856     private void crashWatchdogDaemon() {
3857         doReturn(null).when(() -> ServiceManager.getService(CAR_WATCHDOG_DAEMON_INTERFACE));
3858         mCarWatchdogDaemonBinderDeathRecipient.binderDied();
3859         mIsDaemonCrashed = true;
3860     }
3861 
restartWatchdogDaemonAndAwait()3862     private void restartWatchdogDaemonAndAwait() throws Exception {
3863         CountDownLatch latch = new CountDownLatch(1);
3864         doAnswer(args -> {
3865             latch.countDown();
3866             return null;
3867         }).when(mMockBinder).linkToDeath(any(), anyInt());
3868         mockWatchdogDaemon();
3869         latch.await(MAX_WAIT_TIME_MS, TimeUnit.MILLISECONDS);
3870         captureAndVerifyRegistrationWithDaemon(/* waitOnMain= */ false);
3871     }
3872 
testClientHealthCheck(TestClient client, int badClientCount)3873     private void testClientHealthCheck(TestClient client, int badClientCount) throws Exception {
3874         mCarWatchdogService.registerClient(client, TIMEOUT_CRITICAL);
3875         mWatchdogServiceForSystemImpl.checkIfAlive(123456, TIMEOUT_CRITICAL);
3876         verify(mMockCarWatchdogDaemon, timeout(MAX_WAIT_TIME_MS)).tellCarWatchdogServiceAlive(
3877                 eq(mWatchdogServiceForSystemImpl), mIntArrayCaptor.capture(), eq(123456));
3878         assertThat(mIntArrayCaptor.getValue()).isEmpty();
3879         mWatchdogServiceForSystemImpl.checkIfAlive(987654, TIMEOUT_CRITICAL);
3880         verify(mMockCarWatchdogDaemon, timeout(MAX_WAIT_TIME_MS)).tellCarWatchdogServiceAlive(
3881                 eq(mWatchdogServiceForSystemImpl), mIntArrayCaptor.capture(), eq(987654));
3882         assertThat(mIntArrayCaptor.getValue().length).isEqualTo(badClientCount);
3883     }
3884 
3885     private List<android.automotive.watchdog.internal.ResourceOveruseConfiguration>
captureOnSetResourceOveruseConfigurations()3886             captureOnSetResourceOveruseConfigurations() throws Exception {
3887         verify(mMockCarWatchdogDaemon, timeout(MAX_WAIT_TIME_MS))
3888                 .updateResourceOveruseConfigurations(
3889                         mResourceOveruseConfigurationsCaptor.capture());
3890         return mResourceOveruseConfigurationsCaptor.getValue();
3891     }
3892 
injectIoOveruseStatsForPackages( SparseArray<String> genericPackageNameByUid, Set<String> killablePackages, Set<String> shouldNotifyPackages)3893     private SparseArray<PackageIoOveruseStats> injectIoOveruseStatsForPackages(
3894             SparseArray<String> genericPackageNameByUid, Set<String> killablePackages,
3895             Set<String> shouldNotifyPackages) throws Exception {
3896         SparseArray<PackageIoOveruseStats> packageIoOveruseStatsByUid = new SparseArray<>();
3897         List<PackageIoOveruseStats> packageIoOveruseStats = new ArrayList<>();
3898         for (int i = 0; i < genericPackageNameByUid.size(); ++i) {
3899             String name = genericPackageNameByUid.valueAt(i);
3900             int uid = genericPackageNameByUid.keyAt(i);
3901             PackageIoOveruseStats stats = constructPackageIoOveruseStats(uid,
3902                     shouldNotifyPackages.contains(name),
3903                     constructPerStateBytes(80, 147, 213),
3904                     constructInternalIoOveruseStats(killablePackages.contains(name),
3905                             /* remainingWriteBytes= */ constructPerStateBytes(20, 20, 20),
3906                             /* writtenBytes= */ constructPerStateBytes(100, 200, 300),
3907                             /* totalOveruses= */ 3));
3908             packageIoOveruseStatsByUid.put(uid, stats);
3909             packageIoOveruseStats.add(stats);
3910         }
3911         pushLatestIoOveruseStatsAndWait(packageIoOveruseStats);
3912         return packageIoOveruseStatsByUid;
3913     }
3914 
injectPackageInfos(List<android.content.pm.PackageInfo> packageInfos)3915     private void injectPackageInfos(List<android.content.pm.PackageInfo> packageInfos) {
3916         for (android.content.pm.PackageInfo packageInfo : packageInfos) {
3917             String genericPackageName = packageInfo.packageName;
3918             int uid = packageInfo.applicationInfo.uid;
3919             int userId = UserHandle.getUserId(uid);
3920             if (packageInfo.sharedUserId != null) {
3921                 genericPackageName =
3922                         PackageInfoHandler.SHARED_PACKAGE_PREFIX + packageInfo.sharedUserId;
3923                 List<String> packages = mPackagesBySharedUid.get(uid);
3924                 if (packages == null) {
3925                     packages = new ArrayList<>();
3926                 }
3927                 packages.add(packageInfo.packageName);
3928                 mPackagesBySharedUid.put(uid, packages);
3929             }
3930             String userPackageId = userId + ":" + packageInfo.packageName;
3931             assertWithMessage("Duplicate package infos provided for user package id: %s",
3932                     userPackageId).that(mPmPackageInfoByUserPackage.containsKey(userPackageId))
3933                     .isFalse();
3934             assertWithMessage("Mismatch generic package names for the same uid '%s'",
3935                     uid).that(mGenericPackageNameByUid.get(uid, genericPackageName))
3936                     .isEqualTo(genericPackageName);
3937             mPmPackageInfoByUserPackage.put(userPackageId, packageInfo);
3938             mGenericPackageNameByUid.put(uid, genericPackageName);
3939         }
3940     }
3941 
pushLatestIoOveruseStatsAndWait(List<PackageIoOveruseStats> packageIoOveruseStats)3942     private void pushLatestIoOveruseStatsAndWait(List<PackageIoOveruseStats> packageIoOveruseStats)
3943             throws Exception {
3944         mWatchdogServiceForSystemImpl.latestIoOveruseStats(packageIoOveruseStats);
3945 
3946         // Resource overuse handling is done on the main thread by posting a new message with
3947         // OVERUSE_HANDLING_DELAY_MILLS delay. Wait until the below message is processed before
3948         // returning, so the resource overuse handling is completed.
3949         delayedRunOnMainSync(() -> {}, OVERUSE_HANDLING_DELAY_MILLS * 2);
3950     }
3951 
setUpSampleUserAndPackages()3952     private void setUpSampleUserAndPackages() {
3953         mockUmGetUserHandles(mMockUserManager, /* excludeDying= */ true, 100, 101);
3954         int[] users = new int[]{100, 101};
3955         List<android.content.pm.PackageInfo> packageInfos = new ArrayList<>();
3956         for (int i = 0; i < users.length; ++i) {
3957             packageInfos.add(constructPackageManagerPackageInfo(
3958                     "system_package.critical", UserHandle.getUid(users[i], 10001), null));
3959             packageInfos.add(constructPackageManagerPackageInfo(
3960                     "system_package.non_critical", UserHandle.getUid(users[i], 10002), null));
3961             packageInfos.add(constructPackageManagerPackageInfo(
3962                     "vendor_package.critical", UserHandle.getUid(users[i], 10003), null));
3963             packageInfos.add(constructPackageManagerPackageInfo(
3964                     "vendor_package.non_critical", UserHandle.getUid(users[i], 10004), null));
3965             packageInfos.add(constructPackageManagerPackageInfo(
3966                     "third_party_package.A", UserHandle.getUid(users[i], 10005),
3967                     "third_party_shared_package"));
3968             packageInfos.add(constructPackageManagerPackageInfo(
3969                     "third_party_package.B", UserHandle.getUid(users[i], 10005),
3970                     "third_party_shared_package"));
3971         }
3972         injectPackageInfos(packageInfos);
3973     }
3974 
sampleIoOveruseStats(boolean requireRecurrentOveruseStats)3975     private List<PackageIoOveruseStats> sampleIoOveruseStats(boolean requireRecurrentOveruseStats)
3976             throws Exception {
3977         int[] users = new int[]{100, 101};
3978         int totalOveruses = requireRecurrentOveruseStats ? RECURRING_OVERUSE_TIMES + 1 : 1;
3979         List<PackageIoOveruseStats> packageIoOveruseStats = new ArrayList<>();
3980         android.automotive.watchdog.PerStateBytes zeroRemainingBytes =
3981                 constructPerStateBytes(0, 0, 0);
3982         android.automotive.watchdog.PerStateBytes nonZeroRemainingBytes =
3983                 constructPerStateBytes(20, 30, 40);
3984         android.automotive.watchdog.PerStateBytes writtenBytes =
3985                 constructPerStateBytes(100, 200, 300);
3986         for (int i = 0; i < users.length; ++i) {
3987             // Overuse occurred but cannot be killed/disabled.
3988             packageIoOveruseStats.add(constructPackageIoOveruseStats(
3989                     UserHandle.getUid(users[i], 10001), /* shouldNotify= */ true,
3990                     /* forgivenWriteBytes= */ writtenBytes,
3991                     constructInternalIoOveruseStats(
3992                             /* killableOnOveruse= */ false, zeroRemainingBytes, writtenBytes,
3993                             totalOveruses)));
3994             // No overuse occurred but the package should be notified.
3995             packageIoOveruseStats.add(constructPackageIoOveruseStats(
3996                     UserHandle.getUid(users[i], 10002), /* shouldNotify= */ true,
3997                     /* forgivenWriteBytes= */ constructPerStateBytes(0, 0, 0),
3998                     constructInternalIoOveruseStats(
3999                             /* killableOnOveruse= */ true, nonZeroRemainingBytes, writtenBytes,
4000                             totalOveruses)));
4001             // Neither overuse occurred nor be notified.
4002             packageIoOveruseStats.add(constructPackageIoOveruseStats(
4003                     UserHandle.getUid(users[i], 10003), /* shouldNotify= */ false,
4004                     /* forgivenWriteBytes= */ constructPerStateBytes(0, 0, 0),
4005                     constructInternalIoOveruseStats(
4006                             /* killableOnOveruse= */ false, nonZeroRemainingBytes, writtenBytes,
4007                             totalOveruses)));
4008             // Overuse occurred and can be killed/disabled.
4009             packageIoOveruseStats.add(constructPackageIoOveruseStats(
4010                     UserHandle.getUid(users[i], 10004), /* shouldNotify= */ false,
4011                     /* forgivenWriteBytes= */ writtenBytes,
4012                     constructInternalIoOveruseStats(
4013                             /* killableOnOveruse= */ true, zeroRemainingBytes, writtenBytes,
4014                             totalOveruses)));
4015             // Overuse occurred and can be killed/disabled.
4016             packageIoOveruseStats.add(constructPackageIoOveruseStats(
4017                     UserHandle.getUid(users[i], 10005), /* shouldNotify= */ true,
4018                     /* forgivenWriteBytes= */ writtenBytes,
4019                     constructInternalIoOveruseStats(
4020                             /* killableOnOveruse= */ true, zeroRemainingBytes, writtenBytes,
4021                             totalOveruses)));
4022         }
4023         return packageIoOveruseStats;
4024     }
4025 
captureAndVerifyUserNotifications( List<UserNotificationCall> expectedUserNotificationCalls)4026     private void captureAndVerifyUserNotifications(
4027             List<UserNotificationCall> expectedUserNotificationCalls) {
4028         // Recurring overuse notification handling task is posted on the service thread and this
4029         // task sends the user notifications. Wait for this task to complete.
4030         CarServiceUtils.runOnLooperSync(
4031                 CarServiceUtils.getHandlerThread(CarWatchdogService.class.getSimpleName())
4032                         .getLooper(), () -> {});
4033 
4034         verify(mMockUserNotificationHelper, times(expectedUserNotificationCalls.size()))
4035                 .showResourceOveruseNotificationsAsUser(mPackageNotificationInfosCaptor.capture(),
4036                         mUserHandleCaptor.capture());
4037 
4038         List<List<UserNotificationHelper.PackageNotificationInfo>> allPackageNotificationInfos =
4039                 mPackageNotificationInfosCaptor.getAllValues();
4040         List<UserHandle> allUserHandles = mUserHandleCaptor.getAllValues();
4041 
4042         for (int i = 0; i < expectedUserNotificationCalls.size(); ++i) {
4043             UserNotificationCall expectedUserNotificationCall =
4044                     expectedUserNotificationCalls.get(i);
4045             expectedUserNotificationCall.verifyCall(allPackageNotificationInfos.get(i),
4046                     allUserHandles.get(i));
4047         }
4048     }
4049 
sampleReportedOveruseStats()4050     private static List<AtomsProto.CarWatchdogIoOveruseStatsReported> sampleReportedOveruseStats() {
4051         // The below thresholds are from {@link sampleInternalResourceOveruseConfiguration} and
4052         // UID/stat are from {@link sampleIoOveruseStats}.
4053         AtomsProto.CarWatchdogPerStateBytes systemThreshold =
4054                 WatchdogPerfHandler.constructCarWatchdogPerStateBytes(10, 20, 30);
4055         AtomsProto.CarWatchdogPerStateBytes vendorThreshold =
4056                 WatchdogPerfHandler.constructCarWatchdogPerStateBytes(20, 40, 60);
4057         AtomsProto.CarWatchdogPerStateBytes thirdPartyThreshold =
4058                 WatchdogPerfHandler.constructCarWatchdogPerStateBytes(30, 60, 90);
4059         AtomsProto.CarWatchdogPerStateBytes writtenBytes =
4060                 WatchdogPerfHandler.constructCarWatchdogPerStateBytes(100, 200, 300);
4061         List<AtomsProto.CarWatchdogIoOveruseStatsReported> reportedOveruseStats = new ArrayList<>();
4062         reportedOveruseStats.add(constructIoOveruseStatsReported(
4063                 10010001, systemThreshold, writtenBytes));
4064         reportedOveruseStats.add(constructIoOveruseStatsReported(
4065                 10110001, systemThreshold, writtenBytes));
4066         reportedOveruseStats.add(constructIoOveruseStatsReported(
4067                 10010004, vendorThreshold, writtenBytes));
4068         reportedOveruseStats.add(constructIoOveruseStatsReported(
4069                 10110004, vendorThreshold, writtenBytes));
4070         reportedOveruseStats.add(constructIoOveruseStatsReported(
4071                 10010005, thirdPartyThreshold, writtenBytes));
4072         reportedOveruseStats.add(constructIoOveruseStatsReported(
4073                 10110005, thirdPartyThreshold, writtenBytes));
4074         return reportedOveruseStats;
4075     }
4076 
sampleReportedKillStats( int systemState, int[] killedUids)4077     private static List<AtomsProto.CarWatchdogKillStatsReported> sampleReportedKillStats(
4078             int systemState, int[] killedUids) {
4079         // The below thresholds are from {@link sampleInternalResourceOveruseConfiguration} and
4080         // UID/stat are from {@link sampleIoOveruseStats}.
4081         AtomsProto.CarWatchdogPerStateBytes vendorThreshold =
4082                 WatchdogPerfHandler.constructCarWatchdogPerStateBytes(20, 40, 60);
4083         AtomsProto.CarWatchdogPerStateBytes thirdPartyThreshold =
4084                 WatchdogPerfHandler.constructCarWatchdogPerStateBytes(30, 60, 90);
4085         AtomsProto.CarWatchdogPerStateBytes writtenBytes =
4086                 WatchdogPerfHandler.constructCarWatchdogPerStateBytes(100, 200, 300);
4087         List<AtomsProto.CarWatchdogKillStatsReported> reportedKillStats = new ArrayList<>();
4088         for (int uid : killedUids) {
4089             AtomsProto.CarWatchdogPerStateBytes threshold =
4090                     UserHandle.getAppId(uid) == 10004 ? vendorThreshold : thirdPartyThreshold;
4091             reportedKillStats.add(constructIoOveruseKillStatsReported(
4092                     uid, systemState, threshold, writtenBytes));
4093         }
4094         return reportedKillStats;
4095     }
4096 
verifyOnOveruseCalled(List<ResourceOveruseStats> expectedStats, IResourceOveruseListener mockListener)4097     private static void verifyOnOveruseCalled(List<ResourceOveruseStats> expectedStats,
4098             IResourceOveruseListener mockListener) throws Exception {
4099         ArgumentCaptor<ResourceOveruseStats> resourceOveruseStatsCaptor =
4100                 ArgumentCaptor.forClass(ResourceOveruseStats.class);
4101 
4102         verify(mockListener, times(expectedStats.size()))
4103                 .onOveruse(resourceOveruseStatsCaptor.capture());
4104 
4105         ResourceOveruseStatsSubject.assertThat(resourceOveruseStatsCaptor.getAllValues())
4106                 .containsExactlyElementsIn(expectedStats);
4107     }
4108 
sampleResourceOveruseConfigurations()4109     private static List<ResourceOveruseConfiguration> sampleResourceOveruseConfigurations() {
4110         return Arrays.asList(
4111                 sampleResourceOveruseConfigurationBuilder(ComponentType.SYSTEM,
4112                         sampleIoOveruseConfigurationBuilder(ComponentType.SYSTEM).build()).build(),
4113                 sampleResourceOveruseConfigurationBuilder(ComponentType.VENDOR,
4114                         sampleIoOveruseConfigurationBuilder(ComponentType.VENDOR).build()).build(),
4115                 sampleResourceOveruseConfigurationBuilder(ComponentType.THIRD_PARTY,
4116                         sampleIoOveruseConfigurationBuilder(ComponentType.THIRD_PARTY).build())
4117                         .build());
4118     }
4119 
4120     private static List<android.automotive.watchdog.internal.ResourceOveruseConfiguration>
sampleInternalResourceOveruseConfigurations()4121             sampleInternalResourceOveruseConfigurations() {
4122         return Arrays.asList(
4123                 sampleInternalResourceOveruseConfiguration(ComponentType.SYSTEM,
4124                         sampleInternalIoOveruseConfiguration(ComponentType.SYSTEM)),
4125                 sampleInternalResourceOveruseConfiguration(ComponentType.VENDOR,
4126                         sampleInternalIoOveruseConfiguration(ComponentType.VENDOR)),
4127                 sampleInternalResourceOveruseConfiguration(ComponentType.THIRD_PARTY,
4128                         sampleInternalIoOveruseConfiguration(ComponentType.THIRD_PARTY)));
4129     }
4130 
sampleResourceOveruseConfigurationBuilder( @omponentType int componentType, IoOveruseConfiguration ioOveruseConfig)4131     private static ResourceOveruseConfiguration.Builder sampleResourceOveruseConfigurationBuilder(
4132             @ComponentType int componentType, IoOveruseConfiguration ioOveruseConfig) {
4133         String prefix = WatchdogPerfHandler.toComponentTypeStr(componentType).toLowerCase();
4134         List<String> safeToKill = Arrays.asList(prefix + "_package.non_critical.A",
4135                 prefix + "_pkg.non_critical.B",
4136                 "shared:" + prefix + "_shared_package.non_critical.B",
4137                 "some_pkg_as_" + prefix + "_pkg");
4138         List<String> vendorPrefixes = Arrays.asList(
4139                 prefix + "_package", "some_pkg_as_" + prefix + "_pkg");
4140         Map<String, String> pkgToAppCategory = new ArrayMap<>();
4141         pkgToAppCategory.put("system_package.MEDIA", "android.car.watchdog.app.category.MEDIA");
4142         pkgToAppCategory.put("system_package.A", "android.car.watchdog.app.category.MAPS");
4143         pkgToAppCategory.put("vendor_package.MEDIA", "android.car.watchdog.app.category.MEDIA");
4144         pkgToAppCategory.put("vendor_package.A", "android.car.watchdog.app.category.MAPS");
4145         pkgToAppCategory.put("third_party_package.MAPS", "android.car.watchdog.app.category.MAPS");
4146         ResourceOveruseConfiguration.Builder configBuilder =
4147                 new ResourceOveruseConfiguration.Builder(componentType, safeToKill,
4148                         vendorPrefixes, pkgToAppCategory);
4149         configBuilder.setIoOveruseConfiguration(ioOveruseConfig);
4150         return configBuilder;
4151     }
4152 
sampleIoOveruseConfigurationBuilder( @omponentType int componentType)4153     private static IoOveruseConfiguration.Builder sampleIoOveruseConfigurationBuilder(
4154             @ComponentType int componentType) {
4155         String prefix = WatchdogPerfHandler.toComponentTypeStr(componentType).toLowerCase();
4156         PerStateBytes componentLevelThresholds = new PerStateBytes(
4157                 /* foregroundModeBytes= */ componentType * 10L,
4158                 /* backgroundModeBytes= */ componentType * 20L,
4159                 /* garageModeBytes= */ componentType * 30L);
4160         Map<String, PerStateBytes> packageSpecificThresholds = new ArrayMap<>();
4161         packageSpecificThresholds.put(prefix + "_package.A", new PerStateBytes(
4162                 /* foregroundModeBytes= */ componentType * 40L,
4163                 /* backgroundModeBytes= */ componentType * 50L,
4164                 /* garageModeBytes= */ componentType * 60L));
4165 
4166         Map<String, PerStateBytes> appCategorySpecificThresholds = new ArrayMap<>();
4167         appCategorySpecificThresholds.put(
4168                 ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MEDIA,
4169                 new PerStateBytes(/* foregroundModeBytes= */ componentType * 100L,
4170                         /* backgroundModeBytes= */ componentType * 200L,
4171                         /* garageModeBytes= */ componentType * 300L));
4172         appCategorySpecificThresholds.put(
4173                 ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MAPS,
4174                 new PerStateBytes(/* foregroundModeBytes= */ componentType * 1100L,
4175                         /* backgroundModeBytes= */ componentType * 2200L,
4176                         /* garageModeBytes= */ componentType * 3300L));
4177 
4178         List<IoOveruseAlertThreshold> systemWideThresholds = Collections.singletonList(
4179                 new IoOveruseAlertThreshold(/* durationInSeconds= */ componentType * 10L,
4180                         /* writtenBytesPerSecond= */ componentType * 200L));
4181 
4182         return new IoOveruseConfiguration.Builder(componentLevelThresholds,
4183                 packageSpecificThresholds, appCategorySpecificThresholds, systemWideThresholds);
4184     }
4185 
4186     private static android.automotive.watchdog.internal.ResourceOveruseConfiguration
sampleInternalResourceOveruseConfiguration(@omponentType int componentType, android.automotive.watchdog.internal.IoOveruseConfiguration ioOveruseConfig)4187             sampleInternalResourceOveruseConfiguration(@ComponentType int componentType,
4188             android.automotive.watchdog.internal.IoOveruseConfiguration ioOveruseConfig) {
4189         String prefix = WatchdogPerfHandler.toComponentTypeStr(componentType).toLowerCase();
4190         android.automotive.watchdog.internal.ResourceOveruseConfiguration config =
4191                 new android.automotive.watchdog.internal.ResourceOveruseConfiguration();
4192         config.componentType = componentType;
4193         config.safeToKillPackages = Arrays.asList(prefix + "_package.non_critical.A",
4194                 prefix + "_pkg.non_critical.B",
4195                 "shared:" + prefix + "_shared_package.non_critical.B",
4196                 "some_pkg_as_" + prefix + "_pkg");
4197         config.vendorPackagePrefixes = Arrays.asList(
4198                 prefix + "_package", "some_pkg_as_" + prefix + "_pkg");
4199         config.packageMetadata = Arrays.asList(
4200                 constructPackageMetadata("system_package.MEDIA", ApplicationCategoryType.MEDIA),
4201                 constructPackageMetadata("system_package.A", ApplicationCategoryType.MAPS),
4202                 constructPackageMetadata("vendor_package.MEDIA", ApplicationCategoryType.MEDIA),
4203                 constructPackageMetadata("vendor_package.A", ApplicationCategoryType.MAPS),
4204                 constructPackageMetadata("third_party_package.MAPS", ApplicationCategoryType.MAPS));
4205 
4206         ResourceSpecificConfiguration resourceSpecificConfig = new ResourceSpecificConfiguration();
4207         resourceSpecificConfig.setIoOveruseConfiguration(ioOveruseConfig);
4208         config.resourceSpecificConfigurations = Collections.singletonList(resourceSpecificConfig);
4209 
4210         return config;
4211     }
4212 
4213     private static android.automotive.watchdog.internal.IoOveruseConfiguration
sampleInternalIoOveruseConfiguration(@omponentType int componentType)4214             sampleInternalIoOveruseConfiguration(@ComponentType int componentType) {
4215         String prefix = WatchdogPerfHandler.toComponentTypeStr(componentType).toLowerCase();
4216         android.automotive.watchdog.internal.IoOveruseConfiguration config =
4217                 new android.automotive.watchdog.internal.IoOveruseConfiguration();
4218         config.componentLevelThresholds = constructPerStateIoOveruseThreshold(
4219                 WatchdogPerfHandler.toComponentTypeStr(componentType),
4220                 /* fgBytes= */ componentType * 10L, /* bgBytes= */ componentType *  20L,
4221                 /*gmBytes= */ componentType * 30L);
4222         config.packageSpecificThresholds = Collections.singletonList(
4223                 constructPerStateIoOveruseThreshold(prefix + "_package.A",
4224                         /* fgBytes= */ componentType * 40L, /* bgBytes= */ componentType * 50L,
4225                         /* gmBytes= */ componentType * 60L));
4226         config.categorySpecificThresholds = Arrays.asList(
4227                 constructPerStateIoOveruseThreshold(
4228                         WatchdogPerfHandler.INTERNAL_APPLICATION_CATEGORY_TYPE_MEDIA,
4229                         /* fgBytes= */ componentType * 100L, /* bgBytes= */ componentType * 200L,
4230                         /* gmBytes= */ componentType * 300L),
4231                 constructPerStateIoOveruseThreshold(
4232                         WatchdogPerfHandler.INTERNAL_APPLICATION_CATEGORY_TYPE_MAPS,
4233                         /* fgBytes= */ componentType * 1100L, /* bgBytes= */ componentType * 2200L,
4234                         /* gmBytes= */ componentType * 3300L));
4235         config.systemWideThresholds = Collections.singletonList(
4236                 constructInternalIoOveruseAlertThreshold(
4237                         /* duration= */ componentType * 10L, /* writeBPS= */ componentType * 200L));
4238         return config;
4239     }
4240 
constructPackageMetadata( String packageName, @ApplicationCategoryType int appCategoryType)4241     private static PackageMetadata constructPackageMetadata(
4242             String packageName, @ApplicationCategoryType int appCategoryType) {
4243         PackageMetadata metadata = new PackageMetadata();
4244         metadata.packageName = packageName;
4245         metadata.appCategoryType = appCategoryType;
4246         return metadata;
4247     }
4248 
constructPerStateIoOveruseThreshold(String name, long fgBytes, long bgBytes, long gmBytes)4249     private static PerStateIoOveruseThreshold constructPerStateIoOveruseThreshold(String name,
4250             long fgBytes, long bgBytes, long gmBytes) {
4251         PerStateIoOveruseThreshold threshold = new PerStateIoOveruseThreshold();
4252         threshold.name = name;
4253         threshold.perStateWriteBytes = new android.automotive.watchdog.PerStateBytes();
4254         threshold.perStateWriteBytes.foregroundBytes = fgBytes;
4255         threshold.perStateWriteBytes.backgroundBytes = bgBytes;
4256         threshold.perStateWriteBytes.garageModeBytes = gmBytes;
4257         return threshold;
4258     }
4259 
4260     private static android.automotive.watchdog.internal.IoOveruseAlertThreshold
constructInternalIoOveruseAlertThreshold(long duration, long writeBPS)4261             constructInternalIoOveruseAlertThreshold(long duration, long writeBPS) {
4262         android.automotive.watchdog.internal.IoOveruseAlertThreshold threshold =
4263                 new android.automotive.watchdog.internal.IoOveruseAlertThreshold();
4264         threshold.durationInSeconds = duration;
4265         threshold.writtenBytesPerSecond = writeBPS;
4266         return threshold;
4267     }
4268 
constructPackageIoOveruseStats(int uid, boolean shouldNotify, android.automotive.watchdog.PerStateBytes forgivenWriteBytes, android.automotive.watchdog.IoOveruseStats ioOveruseStats)4269     private static PackageIoOveruseStats constructPackageIoOveruseStats(int uid,
4270             boolean shouldNotify, android.automotive.watchdog.PerStateBytes forgivenWriteBytes,
4271             android.automotive.watchdog.IoOveruseStats ioOveruseStats) {
4272         PackageIoOveruseStats stats = new PackageIoOveruseStats();
4273         stats.uid = uid;
4274         stats.shouldNotify = shouldNotify;
4275         stats.forgivenWriteBytes = forgivenWriteBytes;
4276         stats.ioOveruseStats = ioOveruseStats;
4277         return stats;
4278     }
4279 
constructResourceOveruseStats(int uid, String packageName, android.automotive.watchdog.IoOveruseStats internalIoOveruseStats)4280     private static ResourceOveruseStats constructResourceOveruseStats(int uid, String packageName,
4281             android.automotive.watchdog.IoOveruseStats internalIoOveruseStats) {
4282         IoOveruseStats ioOveruseStats = WatchdogPerfHandler.toIoOveruseStatsBuilder(
4283                 internalIoOveruseStats, /* totalTimesKilled= */ 0,
4284                 internalIoOveruseStats.killableOnOveruse).build();
4285 
4286         return new ResourceOveruseStats.Builder(packageName, UserHandle.getUserHandleForUid(uid))
4287                 .setIoOveruseStats(ioOveruseStats).build();
4288     }
4289 
constructUserPackageIoUsageStats( int userId, String packageName, android.automotive.watchdog.PerStateBytes writtenBytes, android.automotive.watchdog.PerStateBytes forgivenWriteBytes, int totalOveruses)4290     private static UserPackageIoUsageStats constructUserPackageIoUsageStats(
4291             int userId, String packageName, android.automotive.watchdog.PerStateBytes writtenBytes,
4292             android.automotive.watchdog.PerStateBytes forgivenWriteBytes, int totalOveruses) {
4293         UserPackageIoUsageStats stats = new UserPackageIoUsageStats();
4294         stats.userId = userId;
4295         stats.packageName = packageName;
4296         stats.ioUsageStats = new IoUsageStats();
4297         stats.ioUsageStats.writtenBytes = writtenBytes;
4298         stats.ioUsageStats.forgivenWriteBytes = forgivenWriteBytes;
4299         stats.ioUsageStats.totalOveruses = totalOveruses;
4300         return stats;
4301     }
4302 
isUserPackageIoUsageStatsEquals(UserPackageIoUsageStats actual, UserPackageIoUsageStats expected)4303     public static boolean isUserPackageIoUsageStatsEquals(UserPackageIoUsageStats actual,
4304             UserPackageIoUsageStats expected) {
4305         return actual.userId == expected.userId && actual.packageName.equals(expected.packageName)
4306                 && isInternalPerStateBytesEquals(
4307                         actual.ioUsageStats.writtenBytes, expected.ioUsageStats.writtenBytes)
4308                 && isInternalPerStateBytesEquals(actual.ioUsageStats.forgivenWriteBytes,
4309                         expected.ioUsageStats.forgivenWriteBytes)
4310                 && actual.ioUsageStats.totalOveruses == expected.ioUsageStats.totalOveruses;
4311     }
4312 
isInternalPerStateBytesEquals( android.automotive.watchdog.PerStateBytes actual, android.automotive.watchdog.PerStateBytes expected)4313     public static boolean isInternalPerStateBytesEquals(
4314             android.automotive.watchdog.PerStateBytes actual,
4315             android.automotive.watchdog.PerStateBytes expected) {
4316         return actual.foregroundBytes == expected.foregroundBytes
4317                 && actual.backgroundBytes == expected.backgroundBytes
4318                 && actual.garageModeBytes == expected.garageModeBytes;
4319     }
4320 
constructInternalIoOveruseStats( boolean killableOnOveruse, android.automotive.watchdog.PerStateBytes remainingWriteBytes, android.automotive.watchdog.PerStateBytes writtenBytes, int totalOveruses)4321     private android.automotive.watchdog.IoOveruseStats constructInternalIoOveruseStats(
4322             boolean killableOnOveruse,
4323             android.automotive.watchdog.PerStateBytes remainingWriteBytes,
4324             android.automotive.watchdog.PerStateBytes writtenBytes, int totalOveruses) {
4325         return constructInternalIoOveruseStats(killableOnOveruse, STATS_DURATION_SECONDS,
4326                 remainingWriteBytes, writtenBytes, totalOveruses);
4327     }
4328 
constructInternalIoOveruseStats( boolean killableOnOveruse, long durationInSecs, android.automotive.watchdog.PerStateBytes remainingWriteBytes, android.automotive.watchdog.PerStateBytes writtenBytes, int totalOveruses)4329     private android.automotive.watchdog.IoOveruseStats constructInternalIoOveruseStats(
4330             boolean killableOnOveruse, long durationInSecs,
4331             android.automotive.watchdog.PerStateBytes remainingWriteBytes,
4332             android.automotive.watchdog.PerStateBytes writtenBytes, int totalOveruses) {
4333         android.automotive.watchdog.IoOveruseStats stats =
4334                 new android.automotive.watchdog.IoOveruseStats();
4335         stats.startTime = mTimeSource.now().getEpochSecond();
4336         stats.durationInSeconds = durationInSecs;
4337         stats.killableOnOveruse = killableOnOveruse;
4338         stats.remainingWriteBytes = remainingWriteBytes;
4339         stats.writtenBytes = writtenBytes;
4340         stats.totalOveruses = totalOveruses;
4341         return stats;
4342     }
4343 
delayedRunOnMainSync(Runnable action, long delayMillis)4344     private static void delayedRunOnMainSync(Runnable action, long delayMillis)
4345             throws InterruptedException {
4346         AtomicBoolean isComplete = new AtomicBoolean();
4347         Handler handler = new Handler(Looper.getMainLooper());
4348         handler.postDelayed(() -> {
4349             action.run();
4350             synchronized (action) {
4351                 isComplete.set(true);
4352                 action.notifyAll();
4353             }
4354         }, delayMillis);
4355         synchronized (action) {
4356             while (!isComplete.get()) {
4357                 action.wait();
4358             }
4359         }
4360     }
4361 
4362     private static AtomsProto.CarWatchdogIoOveruseStatsReported
constructIoOveruseStatsReported(int uid, AtomsProto.CarWatchdogPerStateBytes threshold, AtomsProto.CarWatchdogPerStateBytes writtenBytes)4363             constructIoOveruseStatsReported(int uid, AtomsProto.CarWatchdogPerStateBytes threshold,
4364             AtomsProto.CarWatchdogPerStateBytes writtenBytes) {
4365         return constructCarWatchdogIoOveruseStatsReported(
4366                 uid, WatchdogPerfHandler.constructCarWatchdogIoOveruseStats(
4367                         AtomsProto.CarWatchdogIoOveruseStats.Period.DAILY, threshold, writtenBytes)
4368         );
4369     }
4370 
4371     private static AtomsProto.CarWatchdogIoOveruseStatsReported
constructCarWatchdogIoOveruseStatsReported( int uid, AtomsProto.CarWatchdogIoOveruseStats ioOveruseStats)4372             constructCarWatchdogIoOveruseStatsReported(
4373                     int uid, AtomsProto.CarWatchdogIoOveruseStats ioOveruseStats) {
4374         return AtomsProto.CarWatchdogIoOveruseStatsReported.newBuilder()
4375                 .setUid(uid)
4376                 .setIoOveruseStats(ioOveruseStats)
4377                 .build();
4378     }
4379 
constructIoOveruseKillStatsReported( int uid, int systemState, AtomsProto.CarWatchdogPerStateBytes threshold, AtomsProto.CarWatchdogPerStateBytes writtenBytes)4380     private static AtomsProto.CarWatchdogKillStatsReported constructIoOveruseKillStatsReported(
4381             int uid, int systemState, AtomsProto.CarWatchdogPerStateBytes threshold,
4382             AtomsProto.CarWatchdogPerStateBytes writtenBytes) {
4383         return constructCarWatchdogKillStatsReported(uid,
4384                 CAR_WATCHDOG_KILL_STATS_REPORTED__UID_STATE__UNKNOWN_UID_STATE, systemState,
4385                 CAR_WATCHDOG_KILL_STATS_REPORTED__KILL_REASON__KILLED_ON_IO_OVERUSE,
4386                 WatchdogPerfHandler.constructCarWatchdogIoOveruseStats(
4387                         AtomsProto.CarWatchdogIoOveruseStats.Period.DAILY, threshold, writtenBytes)
4388         );
4389     }
4390 
constructCarWatchdogKillStatsReported( int uid, int uidState, int systemState, int killReason, AtomsProto.CarWatchdogIoOveruseStats ioOveruseStats)4391     private static AtomsProto.CarWatchdogKillStatsReported constructCarWatchdogKillStatsReported(
4392             int uid, int uidState, int systemState, int killReason,
4393             AtomsProto.CarWatchdogIoOveruseStats ioOveruseStats) {
4394         return AtomsProto.CarWatchdogKillStatsReported.newBuilder()
4395                 .setUid(uid)
4396                 .setUidState(AtomsProto.CarWatchdogKillStatsReported.UidState.forNumber(uidState))
4397                 .setSystemState(AtomsProto.CarWatchdogKillStatsReported.SystemState.forNumber(
4398                         systemState))
4399                 .setKillReason(AtomsProto.CarWatchdogKillStatsReported.KillReason.forNumber(
4400                         killReason))
4401                 .setIoOveruseStats(ioOveruseStats)
4402                 .build();
4403     }
4404 
captureAndVerifyIoOveruseStatsReported( List<AtomsProto.CarWatchdogIoOveruseStatsReported> expected)4405     private void captureAndVerifyIoOveruseStatsReported(
4406             List<AtomsProto.CarWatchdogIoOveruseStatsReported> expected) throws Exception {
4407         verify(() -> CarStatsLog.write(eq(CarStatsLog.CAR_WATCHDOG_IO_OVERUSE_STATS_REPORTED),
4408                 mOverusingUidCaptor.capture(), mOveruseStatsCaptor.capture()),
4409                 times(expected.size()));
4410 
4411         List<Integer> allUidValues = mOverusingUidCaptor.getAllValues();
4412         List<byte[]> allOveruseStatsValues = mOveruseStatsCaptor.getAllValues();
4413         List<AtomsProto.CarWatchdogIoOveruseStatsReported> actual = new ArrayList<>();
4414         for (int i = 0; i < expected.size(); ++i) {
4415             actual.add(constructCarWatchdogIoOveruseStatsReported(allUidValues.get(i),
4416                     AtomsProto.CarWatchdogIoOveruseStats.parseFrom(allOveruseStatsValues.get(i))));
4417         }
4418         assertWithMessage("I/O overuse stats reported to statsd").that(actual)
4419                 .containsExactlyElementsIn(expected);
4420     }
4421 
captureAndVerifyKillStatsReported( List<AtomsProto.CarWatchdogKillStatsReported> expected)4422     private void captureAndVerifyKillStatsReported(
4423             List<AtomsProto.CarWatchdogKillStatsReported> expected) throws Exception {
4424         // Overuse handling task is posted on the main thread and this task performs disabling and
4425         // uploading metrics. Wait for this task to complete.
4426         CarServiceUtils.runOnMainSync(() -> {});
4427 
4428         verify(() -> CarStatsLog.write(eq(CarStatsLog.CAR_WATCHDOG_KILL_STATS_REPORTED),
4429                 mKilledUidCaptor.capture(), mUidStateCaptor.capture(),
4430                 mSystemStateCaptor.capture(), mKillReasonCaptor.capture(), eq(null),
4431                 mKilledStatsCaptor.capture()), times(expected.size()));
4432 
4433         List<Integer> allUidValues = mKilledUidCaptor.getAllValues();
4434         List<Integer> allUidStateValues = mUidStateCaptor.getAllValues();
4435         List<Integer> allSystemStateValues = mSystemStateCaptor.getAllValues();
4436         List<Integer> allKillReasonValues = mKillReasonCaptor.getAllValues();
4437         List<byte[]> allIoOveruseStatsValues = mKilledStatsCaptor.getAllValues();
4438         List<AtomsProto.CarWatchdogKillStatsReported> actual = new ArrayList<>();
4439         for (int i = 0; i < expected.size(); ++i) {
4440             actual.add(constructCarWatchdogKillStatsReported(allUidValues.get(i),
4441                     allUidStateValues.get(i), allSystemStateValues.get(i),
4442                     allKillReasonValues.get(i),
4443                     AtomsProto.CarWatchdogIoOveruseStats.parseFrom(
4444                             allIoOveruseStatsValues.get(i))));
4445         }
4446         assertWithMessage("I/O overuse kill stats reported to statsd").that(actual)
4447                 .containsExactlyElementsIn(expected);
4448     }
4449 
verifyAndGetSystemIoUsageSummaries( ZonedDateTime beginReportDate)4450     private List<AtomsProto.CarWatchdogSystemIoUsageSummary> verifyAndGetSystemIoUsageSummaries(
4451             ZonedDateTime beginReportDate) {
4452         ZonedDateTime beginWeekStartDate = beginReportDate.with(ChronoField.DAY_OF_WEEK, 1);
4453         ZonedDateTime endWeekStartDate = mTimeSource.getCurrentDate()
4454                 .with(ChronoField.DAY_OF_WEEK, 1);
4455         List<AtomsProto.CarWatchdogSystemIoUsageSummary> expectedSummaries = new ArrayList<>();
4456         while (!beginWeekStartDate.equals(endWeekStartDate)) {
4457             long startEpochSecond = beginWeekStartDate.toEpochSecond();
4458             verify(mMockWatchdogStorage).getDailySystemIoUsageSummaries(startEpochSecond,
4459                     beginWeekStartDate.plusWeeks(1).toEpochSecond());
4460             expectedSummaries.add(AtomsProto.CarWatchdogSystemIoUsageSummary.newBuilder()
4461                     .setIoUsageSummary(constructCarWatchdogIoUsageSummary(startEpochSecond,
4462                             sampleDailyIoUsageSummariesForAWeek(startEpochSecond,
4463                                     SYSTEM_DAILY_IO_USAGE_SUMMARY_MULTIPLIER)))
4464                     .build());
4465             beginWeekStartDate = beginWeekStartDate.plusWeeks(1);
4466         }
4467         return expectedSummaries;
4468     }
4469 
verifyAndGetUidIoUsageSummaries( ZonedDateTime beginReportDate, List<Integer> expectUids)4470     private List<AtomsProto.CarWatchdogUidIoUsageSummary> verifyAndGetUidIoUsageSummaries(
4471             ZonedDateTime beginReportDate, List<Integer> expectUids) {
4472         ZonedDateTime beginWeekStartDate = beginReportDate.with(ChronoField.DAY_OF_WEEK, 1);
4473         ZonedDateTime endWeekStartDate = mTimeSource.getCurrentDate()
4474                 .with(ChronoField.DAY_OF_WEEK, 1);
4475         List<AtomsProto.CarWatchdogUidIoUsageSummary> expectedSummaries = new ArrayList<>();
4476         while (!beginWeekStartDate.equals(endWeekStartDate)) {
4477             long startEpochSecond = beginWeekStartDate.toEpochSecond();
4478             verify(mMockWatchdogStorage).getTopUsersDailyIoUsageSummaries(
4479                     UID_IO_USAGE_SUMMARY_TOP_COUNT * 2,
4480                     UID_IO_USAGE_SUMMARY_MIN_SYSTEM_TOTAL_WEEKLY_WRITTEN_BYTES, startEpochSecond,
4481                     beginWeekStartDate.plusWeeks(1).toEpochSecond());
4482             for (Integer uid : expectUids) {
4483                 expectedSummaries.add(AtomsProto.CarWatchdogUidIoUsageSummary.newBuilder()
4484                         .setUid(uid)
4485                         .setIoUsageSummary(constructCarWatchdogIoUsageSummary(startEpochSecond,
4486                                 sampleDailyIoUsageSummariesForAWeek(startEpochSecond,
4487                                         uid)))
4488                         .build());
4489             }
4490             beginWeekStartDate = beginWeekStartDate.plusWeeks(1);
4491         }
4492         return expectedSummaries;
4493     }
4494 
constructCarWatchdogIoUsageSummary( long startTimeMillis, List<AtomsProto.CarWatchdogDailyIoUsageSummary> dailySummaries)4495     private static AtomsProto.CarWatchdogIoUsageSummary constructCarWatchdogIoUsageSummary(
4496             long startTimeMillis, List<AtomsProto.CarWatchdogDailyIoUsageSummary> dailySummaries) {
4497         return AtomsProto.CarWatchdogIoUsageSummary.newBuilder()
4498                 .setEventTimePeriod(AtomsProto.CarWatchdogEventTimePeriod.newBuilder()
4499                         .setPeriod(AtomsProto.CarWatchdogEventTimePeriod.Period.WEEKLY)
4500                         .setStartTimeMillis(startTimeMillis).build())
4501                 .addAllDailyIoUsageSummary(dailySummaries)
4502                 .build();
4503     }
4504 
sampleDailyIoUsageSummariesForAWeek( long startEpochSeconds, long sysOrUidMultiplier)4505     private List<AtomsProto.CarWatchdogDailyIoUsageSummary> sampleDailyIoUsageSummariesForAWeek(
4506             long startEpochSeconds, long sysOrUidMultiplier) {
4507         List<AtomsProto.CarWatchdogDailyIoUsageSummary> summaries = new ArrayList<>();
4508         long weekMultiplier = ChronoUnit.WEEKS.between(
4509                 ZonedDateTime.ofInstant(Instant.ofEpochSecond(startEpochSeconds), ZONE_OFFSET),
4510                 mTimeSource.getCurrentDate());
4511         for (int i = 1; i < 8; ++i) {
4512             summaries.add(constructCarWatchdogDailyIoUsageSummary(
4513                     /* fgWrBytes= */ 100 * i * weekMultiplier * sysOrUidMultiplier,
4514                     /* bgWrBytes= */ 200 * i * weekMultiplier * sysOrUidMultiplier,
4515                     /* gmWrBytes= */ 300 * i * weekMultiplier * sysOrUidMultiplier,
4516                     /* overuseCount= */ 2 * i));
4517         }
4518         return summaries;
4519     }
4520 
constructCarWatchdogDailyIoUsageSummary( long fgWrBytes, long bgWrBytes, long gmWrBytes, int overuseCount)4521     static AtomsProto.CarWatchdogDailyIoUsageSummary constructCarWatchdogDailyIoUsageSummary(
4522             long fgWrBytes, long bgWrBytes, long gmWrBytes, int overuseCount) {
4523         return AtomsProto.CarWatchdogDailyIoUsageSummary.newBuilder()
4524                 .setWrittenBytes(WatchdogPerfHandler
4525                         .constructCarWatchdogPerStateBytes(fgWrBytes, bgWrBytes, gmWrBytes))
4526                 .setOveruseCount(overuseCount)
4527                 .build();
4528     }
4529 
4530     private class TestClient extends ICarWatchdogServiceCallback.Stub {
4531         protected int mLastSessionId = INVALID_SESSION_ID;
4532 
4533         @Override
onCheckHealthStatus(int sessionId, int timeout)4534         public void onCheckHealthStatus(int sessionId, int timeout) {
4535             mLastSessionId = sessionId;
4536             mCarWatchdogService.tellClientAlive(this, sessionId);
4537         }
4538 
4539         @Override
onPrepareProcessTermination()4540         public void onPrepareProcessTermination() {
4541         }
4542 
getLastSessionId()4543         public int getLastSessionId() {
4544             return mLastSessionId;
4545         }
4546     }
4547 
4548     private final class BadTestClient extends TestClient {
4549         @Override
onCheckHealthStatus(int sessionId, int timeout)4550         public void onCheckHealthStatus(int sessionId, int timeout) {
4551             mLastSessionId = sessionId;
4552             // This client doesn't respond to CarWatchdogService.
4553         }
4554     }
4555 
createMockResourceOveruseListener()4556     private static IResourceOveruseListener createMockResourceOveruseListener() {
4557         IResourceOveruseListener listener = mock(IResourceOveruseListener.Stub.class);
4558         when(listener.asBinder()).thenCallRealMethod();
4559         return listener;
4560     }
4561 
constructPackageInfo(String packageName, int uid, List<String> sharedUidPackages, int uidType, int componentType, int appCategoryType)4562     private static PackageInfo constructPackageInfo(String packageName, int uid,
4563             List<String> sharedUidPackages, int uidType, int componentType, int appCategoryType) {
4564         PackageInfo packageInfo = new PackageInfo();
4565         packageInfo.packageIdentifier = new PackageIdentifier();
4566         packageInfo.packageIdentifier.name = packageName;
4567         packageInfo.packageIdentifier.uid = uid;
4568         packageInfo.uidType = uidType;
4569         packageInfo.sharedUidPackages = sharedUidPackages;
4570         packageInfo.componentType = componentType;
4571         packageInfo.appCategoryType = appCategoryType;
4572 
4573         return packageInfo;
4574     }
4575 
toPackageInfosString(List<PackageInfo> packageInfos)4576     private static String toPackageInfosString(List<PackageInfo> packageInfos) {
4577         StringBuilder builder = new StringBuilder();
4578         for (PackageInfo packageInfo : packageInfos) {
4579             builder = packageInfoStringBuilder(builder, packageInfo).append('\n');
4580         }
4581         return builder.toString();
4582     }
4583 
packageInfoStringBuilder( StringBuilder builder, PackageInfo packageInfo)4584     private static StringBuilder packageInfoStringBuilder(
4585             StringBuilder builder, PackageInfo packageInfo) {
4586         if (packageInfo == null) {
4587             return builder.append("Null package info\n");
4588         }
4589         builder.append("Package name: '").append(packageInfo.packageIdentifier.name)
4590                 .append("', UID: ").append(packageInfo.packageIdentifier.uid).append('\n')
4591                 .append("Owned packages: ");
4592         if (packageInfo.sharedUidPackages != null) {
4593             for (int i = 0; i < packageInfo.sharedUidPackages.size(); ++i) {
4594                 builder.append('\'').append(packageInfo.sharedUidPackages.get(i)).append('\'');
4595                 if (i < packageInfo.sharedUidPackages.size() - 1) {
4596                     builder.append(", ");
4597                 }
4598             }
4599             builder.append('\n');
4600         } else {
4601             builder.append("Null");
4602         }
4603         builder.append("Component type: ").append(packageInfo.componentType).append('\n')
4604                 .append("Application category type: ").append(packageInfo.appCategoryType).append(
4605                 '\n');
4606 
4607         return builder;
4608     }
4609 
assertPackageInfoEquals(List<PackageInfo> actual, List<PackageInfo> expected)4610     private static void assertPackageInfoEquals(List<PackageInfo> actual,
4611             List<PackageInfo> expected) throws Exception {
4612         assertWithMessage("Package infos for UIDs:\nExpected: %s\nActual: %s",
4613                 CarWatchdogServiceUnitTest.toPackageInfosString(expected),
4614                 CarWatchdogServiceUnitTest.toPackageInfosString(actual))
4615                 .that(actual)
4616                 .comparingElementsUsing(
4617                         Correspondence.from(CarWatchdogServiceUnitTest::isPackageInfoEquals,
4618                                 "is package info equal to")).containsExactlyElementsIn(expected);
4619     }
4620 
isPackageInfoEquals(PackageInfo lhs, PackageInfo rhs)4621     private static boolean isPackageInfoEquals(PackageInfo lhs, PackageInfo rhs) {
4622         return isEquals(lhs.packageIdentifier, rhs.packageIdentifier)
4623                 && lhs.sharedUidPackages.containsAll(rhs.sharedUidPackages)
4624                 && lhs.componentType == rhs.componentType
4625                 && lhs.appCategoryType == rhs.appCategoryType;
4626     }
4627 
isEquals(PackageIdentifier lhs, PackageIdentifier rhs)4628     private static boolean isEquals(PackageIdentifier lhs, PackageIdentifier rhs) {
4629         return lhs.name.equals(rhs.name) && lhs.uid == rhs.uid;
4630     }
4631 
constructPackageManagerPackageInfo( String packageName, int uid, String sharedUserId)4632     private static android.content.pm.PackageInfo constructPackageManagerPackageInfo(
4633             String packageName, int uid, String sharedUserId) {
4634         if (packageName.startsWith("system")) {
4635             return constructPackageManagerPackageInfo(
4636                     packageName, uid, sharedUserId, ApplicationInfo.FLAG_SYSTEM, 0);
4637         }
4638         if (packageName.startsWith("vendor")) {
4639             return constructPackageManagerPackageInfo(
4640                     packageName, uid, sharedUserId, ApplicationInfo.FLAG_SYSTEM,
4641                     ApplicationInfo.PRIVATE_FLAG_OEM);
4642         }
4643         return constructPackageManagerPackageInfo(packageName, uid, sharedUserId, 0, 0);
4644     }
4645 
constructPackageManagerPackageInfo( String packageName, int uid, String sharedUserId, int flags, int privateFlags)4646     private static android.content.pm.PackageInfo constructPackageManagerPackageInfo(
4647             String packageName, int uid, String sharedUserId, int flags, int privateFlags) {
4648         android.content.pm.PackageInfo packageInfo = new android.content.pm.PackageInfo();
4649         packageInfo.packageName = packageName;
4650         packageInfo.sharedUserId = sharedUserId;
4651         packageInfo.applicationInfo = new ApplicationInfo();
4652         packageInfo.applicationInfo.packageName = packageName;
4653         packageInfo.applicationInfo.uid = uid;
4654         packageInfo.applicationInfo.flags = flags;
4655         packageInfo.applicationInfo.privateFlags = privateFlags;
4656         return packageInfo;
4657     }
4658 
4659     private static final class TestTimeSource extends TimeSource {
4660         private static final Instant TEST_DATE_TIME = Instant.parse("2021-11-12T13:14:15.16Z");
4661         private Instant mNow;
TestTimeSource()4662         TestTimeSource() {
4663             mNow = TEST_DATE_TIME;
4664         }
4665 
4666         @Override
now()4667         public Instant now() {
4668             /* Return the same time, so the tests are deterministic. */
4669             return mNow;
4670         }
4671 
4672         @Override
toString()4673         public String toString() {
4674             return "Mocked date to " + now();
4675         }
4676 
updateNow(int numDaysAgo)4677         void updateNow(int numDaysAgo) {
4678             mNow = TEST_DATE_TIME.minus(numDaysAgo, ChronoUnit.DAYS);
4679         }
4680     }
4681 
4682     private static final class UserNotificationCall {
4683         public final UserHandle userHandle;
4684         public final List<String> packages;
4685         public final boolean hasHeadsUpNotification;
4686         public final List<Integer> notificationIds;
4687 
UserNotificationCall(UserHandle userHandle, List<String> packages, boolean hasHeadsUpNotification, List<Integer> notificationIds)4688         UserNotificationCall(UserHandle userHandle, List<String> packages,
4689                 boolean hasHeadsUpNotification, List<Integer> notificationIds) {
4690             this.userHandle = userHandle;
4691             this.packages = packages;
4692             this.hasHeadsUpNotification = hasHeadsUpNotification;
4693             this.notificationIds = notificationIds;
4694         }
4695 
verifyCall( List<UserNotificationHelper.PackageNotificationInfo> actualPackageNotificationInfos, UserHandle actualUserHandle)4696         void verifyCall(
4697                 List<UserNotificationHelper.PackageNotificationInfo> actualPackageNotificationInfos,
4698                 UserHandle actualUserHandle) {
4699             assertWithMessage("User handle").that(actualUserHandle).isEqualTo(userHandle);
4700             List<String> actualPackages = new ArrayList<>();
4701             List<Integer> actualNotificationIds = new ArrayList<>();
4702             int numHeadsUpNotification = 0;
4703             for (UserNotificationHelper.PackageNotificationInfo info
4704                     : actualPackageNotificationInfos) {
4705                 actualPackages.add(info.packageName);
4706                 numHeadsUpNotification += info.importance == NotificationManager.IMPORTANCE_HIGH ? 1
4707                         : 0;
4708                 actualNotificationIds.add(info.notificationId);
4709             }
4710             assertWithMessage("Packages").that(actualPackages).isEqualTo(packages);
4711             assertWithMessage("Notification ids").that(actualNotificationIds)
4712                     .containsExactlyElementsIn(notificationIds);
4713             assertWithMessage("Number of heads up notifications").that(numHeadsUpNotification)
4714                     .isEqualTo(hasHeadsUpNotification ? 1 : 0);
4715         }
4716     }
4717 }
4718