1 /* 2 * Copyright (C) 2023 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.devicelockcontroller; 18 19 import static com.android.devicelockcontroller.common.DeviceLockConstants.EXTRA_KIOSK_PACKAGE; 20 21 import static com.google.common.truth.Truth.assertThat; 22 23 import static org.mockito.ArgumentMatchers.anyBoolean; 24 import static org.mockito.ArgumentMatchers.eq; 25 import static org.mockito.Mockito.verify; 26 import static org.mockito.Mockito.when; 27 28 import android.content.ComponentName; 29 import android.content.Intent; 30 import android.os.Bundle; 31 import android.os.IBinder; 32 import android.os.RemoteCallback; 33 import android.os.RemoteException; 34 35 import androidx.test.core.app.ApplicationProvider; 36 import androidx.test.rule.ServiceTestRule; 37 38 import com.android.devicelockcontroller.policy.DevicePolicyController; 39 import com.android.devicelockcontroller.policy.DeviceStateController; 40 import com.android.devicelockcontroller.policy.FinalizationController; 41 import com.android.devicelockcontroller.stats.StatsLogger; 42 import com.android.devicelockcontroller.stats.StatsLoggerProvider; 43 import com.android.devicelockcontroller.storage.SetupParametersClient; 44 45 import com.google.common.util.concurrent.Futures; 46 47 import org.junit.Before; 48 import org.junit.Rule; 49 import org.junit.Test; 50 import org.junit.runner.RunWith; 51 import org.robolectric.Robolectric; 52 import org.robolectric.RobolectricTestRunner; 53 import org.robolectric.Shadows; 54 import org.robolectric.shadows.ShadowApplication; 55 import org.robolectric.shadows.ShadowPackageManager; 56 57 import java.util.concurrent.ExecutionException; 58 import java.util.concurrent.TimeoutException; 59 60 @RunWith(RobolectricTestRunner.class) 61 public final class DeviceLockControllerServiceTest { 62 63 @Rule 64 public final ServiceTestRule mServiceRule = new ServiceTestRule(); 65 66 private static final int KIOSK_APP_UID = 123; 67 68 private static final String KIOSK_APP_PACKAGE_NAME = "TEST_PACKAGE"; 69 70 private StatsLogger mStatsLogger; 71 private TestDeviceLockControllerApplication mTestApp; 72 73 @Before setUp()74 public void setUp() throws TimeoutException, ExecutionException, InterruptedException { 75 mTestApp = ApplicationProvider.getApplicationContext(); 76 StatsLoggerProvider loggerProvider = 77 (StatsLoggerProvider) mTestApp.getApplicationContext(); 78 mStatsLogger = loggerProvider.getStatsLogger(); 79 80 // Put Kiosk app package name and UID into SetupParameters and shadow PackageManager 81 setupSetupParameters(); 82 ShadowPackageManager packageManager = Shadows.shadowOf(mTestApp.getPackageManager()); 83 packageManager.setPackagesForUid(KIOSK_APP_UID, KIOSK_APP_PACKAGE_NAME); 84 final ShadowApplication shadowApplication = Shadows.shadowOf(mTestApp); 85 86 // Setup the service for DeviceLockControllerService using Robolectric 87 DeviceLockControllerService dlcService = Robolectric.setupService( 88 DeviceLockControllerService.class); 89 shadowApplication.setComponentNameAndServiceForBindService( 90 new ComponentName(mTestApp, DeviceLockControllerService.class), 91 dlcService.onBind(/* intent =*/null)); 92 shadowApplication.setBindServiceCallsOnServiceConnectedDirectly(/* callDirectly =*/true); 93 } 94 95 @Test lockDevice_shouldLogKioskRequest_andLogLockSuccess()96 public void lockDevice_shouldLogKioskRequest_andLogLockSuccess() throws RemoteException, 97 TimeoutException { 98 Intent serviceIntent = new Intent(mTestApp, DeviceLockControllerService.class); 99 IBinder binder = mServiceRule.bindService(serviceIntent); 100 when(mTestApp.getDeviceStateController().lockDevice()).thenReturn( 101 Futures.immediateVoidFuture()); 102 103 assertThat(binder).isNotNull(); 104 105 IDeviceLockControllerService.Stub serviceStub = (IDeviceLockControllerService.Stub) binder; 106 serviceStub.lockDevice(new RemoteCallback((result -> {}))); 107 108 verify(mStatsLogger).logKioskAppRequest(eq(KIOSK_APP_UID)); 109 verify(mStatsLogger).logSuccessfulLockingDevice(); 110 } 111 112 @Test lockDevice_failure_shouldLogToStatsLogger()113 public void lockDevice_failure_shouldLogToStatsLogger() throws TimeoutException, 114 RemoteException { 115 DeviceStateController deviceStateController = mTestApp.getDeviceStateController(); 116 Intent serviceIntent = new Intent(mTestApp, DeviceLockControllerService.class); 117 IBinder binder = mServiceRule.bindService(serviceIntent); 118 when(deviceStateController.lockDevice()).thenReturn( 119 Futures.immediateFailedFuture(new RuntimeException("Test Exception"))); 120 when(deviceStateController.getDeviceState()).thenReturn(Futures.immediateFuture( 121 DeviceStateController.DeviceState.UNLOCKED)); 122 123 assertThat(binder).isNotNull(); 124 125 IDeviceLockControllerService.Stub serviceStub = (IDeviceLockControllerService.Stub) binder; 126 serviceStub.lockDevice(new RemoteCallback((result -> {}))); 127 128 verify(mStatsLogger).logLockDeviceFailure(DeviceStateController.DeviceState.UNLOCKED); 129 } 130 131 @Test unlockDevice_shouldLogKioskRequest_AndLogUnlockSuccess()132 public void unlockDevice_shouldLogKioskRequest_AndLogUnlockSuccess() throws RemoteException, 133 TimeoutException { 134 Intent serviceIntent = new Intent(mTestApp, DeviceLockControllerService.class); 135 IBinder binder = mServiceRule.bindService(serviceIntent); 136 when(mTestApp.getDeviceStateController().unlockDevice()).thenReturn( 137 Futures.immediateVoidFuture()); 138 139 assertThat(binder).isNotNull(); 140 141 IDeviceLockControllerService.Stub serviceStub = (IDeviceLockControllerService.Stub) binder; 142 serviceStub.unlockDevice(new RemoteCallback((result -> {}))); 143 144 verify(mStatsLogger).logKioskAppRequest(eq(KIOSK_APP_UID)); 145 verify(mStatsLogger).logSuccessfulUnlockingDevice(); 146 } 147 148 @Test unlockDevice_failure_shouldLogToStatsLogger()149 public void unlockDevice_failure_shouldLogToStatsLogger() throws TimeoutException, 150 RemoteException { 151 DeviceStateController deviceStateController = mTestApp.getDeviceStateController(); 152 Intent serviceIntent = new Intent(mTestApp, DeviceLockControllerService.class); 153 IBinder binder = mServiceRule.bindService(serviceIntent); 154 when(deviceStateController.unlockDevice()).thenReturn( 155 Futures.immediateFailedFuture(new RuntimeException("Test Exception"))); 156 when(deviceStateController.getDeviceState()).thenReturn(Futures.immediateFuture( 157 DeviceStateController.DeviceState.LOCKED)); 158 159 assertThat(binder).isNotNull(); 160 161 IDeviceLockControllerService.Stub serviceStub = (IDeviceLockControllerService.Stub) binder; 162 serviceStub.unlockDevice(new RemoteCallback((result -> {}))); 163 164 verify(mStatsLogger).logUnlockDeviceFailure(DeviceStateController.DeviceState.LOCKED); 165 } 166 167 @Test isDeviceLocked_shouldLogKioskRequest()168 public void isDeviceLocked_shouldLogKioskRequest() throws RemoteException, TimeoutException { 169 Intent serviceIntent = new Intent(mTestApp, DeviceLockControllerService.class); 170 IBinder binder = mServiceRule.bindService(serviceIntent); 171 when(mTestApp.getDeviceStateController().isLocked()).thenReturn( 172 Futures.immediateFuture(true)); 173 174 assertThat(binder).isNotNull(); 175 176 IDeviceLockControllerService.Stub serviceStub = (IDeviceLockControllerService.Stub) binder; 177 serviceStub.isDeviceLocked(new RemoteCallback((result -> {}))); 178 179 verify(mStatsLogger).logKioskAppRequest(eq(KIOSK_APP_UID)); 180 } 181 182 @Test getDeviceIdentifier_shouldLogKioskRequest()183 public void getDeviceIdentifier_shouldLogKioskRequest() 184 throws RemoteException, TimeoutException { 185 Intent serviceIntent = new Intent(mTestApp, DeviceLockControllerService.class); 186 IBinder binder = mServiceRule.bindService(serviceIntent); 187 188 assertThat(binder).isNotNull(); 189 190 IDeviceLockControllerService.Stub serviceStub = (IDeviceLockControllerService.Stub) binder; 191 serviceStub.getDeviceIdentifier(new RemoteCallback((result -> {}))); 192 193 verify(mStatsLogger).logKioskAppRequest(eq(KIOSK_APP_UID)); 194 } 195 196 @Test clearDeviceRestrictions_shouldLogKioskRequest()197 public void clearDeviceRestrictions_shouldLogKioskRequest() 198 throws RemoteException, TimeoutException { 199 Intent serviceIntent = new Intent(mTestApp, DeviceLockControllerService.class); 200 IBinder binder = mServiceRule.bindService(serviceIntent); 201 DeviceStateController deviceStateController = mTestApp.getDeviceStateController(); 202 when(deviceStateController.clearDevice()).thenReturn(Futures.immediateVoidFuture()); 203 FinalizationController finalizationController = mTestApp.getFinalizationController(); 204 when(finalizationController.notifyRestrictionsCleared()) 205 .thenReturn(Futures.immediateVoidFuture()); 206 207 assertThat(binder).isNotNull(); 208 209 IDeviceLockControllerService.Stub serviceStub = (IDeviceLockControllerService.Stub) binder; 210 serviceStub.clearDeviceRestrictions(new RemoteCallback((result -> {}))); 211 212 verify(mStatsLogger).logKioskAppRequest(eq(KIOSK_APP_UID)); 213 } 214 215 @Test onUserSwitching_enforcePoliciesAndFinalizationState()216 public void onUserSwitching_enforcePoliciesAndFinalizationState() 217 throws RemoteException, TimeoutException { 218 Intent serviceIntent = new Intent(mTestApp, DeviceLockControllerService.class); 219 IBinder binder = mServiceRule.bindService(serviceIntent); 220 DevicePolicyController policyController = mTestApp.getPolicyController(); 221 when(policyController.enforceCurrentPolicies()).thenReturn(Futures.immediateVoidFuture()); 222 FinalizationController finalizationController = mTestApp.getFinalizationController(); 223 when(finalizationController.enforceDiskState(anyBoolean())).thenReturn( 224 Futures.immediateVoidFuture()); 225 226 assertThat(binder).isNotNull(); 227 IDeviceLockControllerService.Stub serviceStub = (IDeviceLockControllerService.Stub) binder; 228 serviceStub.onUserSwitching(new RemoteCallback(result -> {})); 229 230 verify(policyController).enforceCurrentPolicies(); 231 verify(finalizationController).enforceDiskState(true); 232 } 233 setupSetupParameters()234 private static void setupSetupParameters() throws InterruptedException, ExecutionException { 235 Bundle preferences = new Bundle(); 236 preferences.putString(EXTRA_KIOSK_PACKAGE, KIOSK_APP_PACKAGE_NAME); 237 SetupParametersClient.getInstance().createPrefs(preferences).get(); 238 } 239 } 240