1 /* 2 * Copyright (C) 2022 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 android.app.cts; 18 19 import static android.Manifest.permission.MANAGE_WEAK_ESCROW_TOKEN; 20 import static android.os.Process.myUserHandle; 21 22 import static com.android.compatibility.common.util.SystemUtil.runShellCommand; 23 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; 24 25 import static com.google.common.truth.Truth.assertThat; 26 27 import static org.junit.Assume.assumeFalse; 28 import static org.junit.Assume.assumeTrue; 29 import static org.mockito.ArgumentMatchers.eq; 30 import static org.mockito.Mockito.mock; 31 import static org.mockito.Mockito.never; 32 import static org.mockito.Mockito.verify; 33 34 import android.app.KeyguardManager; 35 import android.app.KeyguardManager.WeakEscrowTokenActivatedListener; 36 import android.app.KeyguardManager.WeakEscrowTokenRemovedListener; 37 import android.content.Context; 38 import android.content.pm.PackageManager; 39 import android.os.UserHandle; 40 41 import androidx.test.ext.junit.runners.AndroidJUnit4; 42 import androidx.test.platform.app.InstrumentationRegistry; 43 44 import org.junit.After; 45 import org.junit.Before; 46 import org.junit.Test; 47 import org.junit.runner.RunWith; 48 49 import java.io.IOException; 50 import java.nio.charset.StandardCharsets; 51 import java.util.concurrent.Executor; 52 53 @RunWith(AndroidJUnit4.class) 54 public class KeyguardWeakEscrowTokenTest { 55 private static final String TEST_PIN1 = "1234"; 56 private static final String TEST_PIN2 = "4321"; 57 58 private final byte[] mTestToken1 = "test_token1".getBytes(StandardCharsets.UTF_8); 59 private final byte[] mTestToken2 = "test_token2".getBytes(StandardCharsets.UTF_8); 60 private final Executor mTestExecutor = Runnable::run; 61 62 private Context mContext; 63 private UserHandle mTestUser; 64 private KeyguardManager mKeyguardManager; 65 private WeakEscrowTokenActivatedListener mMockTokenActivatedListener; 66 private WeakEscrowTokenRemovedListener mMockTokenRemovedListener; 67 68 @Before setUp()69 public void setUp() { 70 mContext = InstrumentationRegistry.getInstrumentation().getContext(); 71 mKeyguardManager = mContext.getSystemService(KeyguardManager.class); 72 mTestUser = myUserHandle(); 73 mMockTokenActivatedListener = mock(WeakEscrowTokenActivatedListener.class); 74 mMockTokenRemovedListener = mock(WeakEscrowTokenRemovedListener.class); 75 } 76 77 @After cleanUp()78 public void cleanUp() throws IOException { 79 if (!isAutomotiveDevice() || mKeyguardManager == null) return; 80 runWithShellPermissionIdentity(() -> { 81 try { 82 mKeyguardManager 83 .unregisterWeakEscrowTokenRemovedListener(mMockTokenRemovedListener); 84 } catch (IllegalArgumentException e) { 85 // Mock listener was not registered before. 86 } 87 }, MANAGE_WEAK_ESCROW_TOKEN); 88 removeLockCredential(TEST_PIN1); 89 removeLockCredential(TEST_PIN2); 90 } 91 92 @Test testAddWeakEscrowToken_noCredentialSetUp_tokenActivatedImmediately()93 public void testAddWeakEscrowToken_noCredentialSetUp_tokenActivatedImmediately() { 94 assumeIsAutomotiveDevice(); 95 assumeKeyguardManagerAvailable(); 96 97 runWithShellPermissionIdentity(() -> { 98 long handle = mKeyguardManager.addWeakEscrowToken(mTestToken1, mTestUser, mTestExecutor, 99 mMockTokenActivatedListener); 100 boolean isActive = mKeyguardManager.isWeakEscrowTokenActive(handle, mTestUser); 101 boolean isValid = mKeyguardManager.isWeakEscrowTokenValid(handle, mTestToken1, 102 mTestUser); 103 104 assertThat(isActive).isTrue(); 105 assertThat(isValid).isTrue(); 106 verify(mMockTokenActivatedListener).onWeakEscrowTokenActivated(eq(handle), 107 eq(mTestUser)); 108 109 // Clean up 110 mKeyguardManager.removeWeakEscrowToken(handle, mTestUser); 111 }, MANAGE_WEAK_ESCROW_TOKEN); 112 } 113 114 @Test testAddWeakEscrowToken_hasCredentialSetUp_tokenActivatedAfterVerification()115 public void testAddWeakEscrowToken_hasCredentialSetUp_tokenActivatedAfterVerification() { 116 assumeIsAutomotiveDevice(); 117 assumeKeyguardManagerAvailable(); 118 119 runWithShellPermissionIdentity(() -> { 120 setLockCredential(TEST_PIN1); 121 long handle = mKeyguardManager.addWeakEscrowToken(mTestToken1, mTestUser, mTestExecutor, 122 mMockTokenActivatedListener); 123 boolean isActiveBeforeVerification = mKeyguardManager.isWeakEscrowTokenActive(handle, 124 mTestUser); 125 verifyCredential(TEST_PIN1); 126 boolean isActiveAfterVerification = mKeyguardManager.isWeakEscrowTokenActive(handle, 127 mTestUser); 128 129 assertThat(isActiveBeforeVerification).isFalse(); 130 assertThat(isActiveAfterVerification).isTrue(); 131 132 // Clean up 133 mKeyguardManager.removeWeakEscrowToken(handle, mTestUser); 134 }, MANAGE_WEAK_ESCROW_TOKEN); 135 } 136 137 @Test testRemoveWeakEscrowToken_tokenRemoved()138 public void testRemoveWeakEscrowToken_tokenRemoved() { 139 assumeIsAutomotiveDevice(); 140 assumeKeyguardManagerAvailable(); 141 142 runWithShellPermissionIdentity(() -> { 143 long handle = mKeyguardManager.addWeakEscrowToken(mTestToken1, mTestUser, mTestExecutor, 144 mMockTokenActivatedListener); 145 boolean isActiveBeforeRemove = mKeyguardManager.isWeakEscrowTokenActive(handle, 146 mTestUser); 147 mKeyguardManager.removeWeakEscrowToken(handle, mTestUser); 148 boolean isActiveAfterRemove = mKeyguardManager.isWeakEscrowTokenActive(handle, 149 mTestUser); 150 151 assertThat(isActiveBeforeRemove).isTrue(); 152 assertThat(isActiveAfterRemove).isFalse(); 153 }, MANAGE_WEAK_ESCROW_TOKEN); 154 } 155 156 @Test testRegisterWeakEscrowTokenRemovedListener_listenerRegistered()157 public void testRegisterWeakEscrowTokenRemovedListener_listenerRegistered() { 158 assumeIsAutomotiveDevice(); 159 assumeKeyguardManagerAvailable(); 160 161 runWithShellPermissionIdentity(() -> { 162 mKeyguardManager.registerWeakEscrowTokenRemovedListener(mTestExecutor, 163 mMockTokenRemovedListener); 164 long handle = mKeyguardManager.addWeakEscrowToken(mTestToken1, mTestUser, 165 mTestExecutor, mMockTokenActivatedListener); 166 mKeyguardManager.removeWeakEscrowToken(handle, mTestUser); 167 168 verify(mMockTokenRemovedListener).onWeakEscrowTokenRemoved(eq(handle), eq(mTestUser)); 169 }, MANAGE_WEAK_ESCROW_TOKEN); 170 } 171 172 @Test testUnregisterWeakEscrowTokenRemovedListener_listenerUnregistered()173 public void testUnregisterWeakEscrowTokenRemovedListener_listenerUnregistered() { 174 assumeIsAutomotiveDevice(); 175 assumeKeyguardManagerAvailable(); 176 177 runWithShellPermissionIdentity(() -> { 178 mKeyguardManager.registerWeakEscrowTokenRemovedListener(mTestExecutor, 179 mMockTokenRemovedListener); 180 long handle0 = mKeyguardManager.addWeakEscrowToken(mTestToken1, mTestUser, 181 mTestExecutor, mMockTokenActivatedListener); 182 long handle1 = mKeyguardManager.addWeakEscrowToken(mTestToken2, mTestUser, 183 mTestExecutor, mMockTokenActivatedListener); 184 mKeyguardManager.removeWeakEscrowToken(handle0, mTestUser); 185 mKeyguardManager.unregisterWeakEscrowTokenRemovedListener(mMockTokenRemovedListener); 186 mKeyguardManager.removeWeakEscrowToken(handle1, mTestUser); 187 188 verify(mMockTokenRemovedListener).onWeakEscrowTokenRemoved(eq(handle0), eq(mTestUser)); 189 verify(mMockTokenRemovedListener, never()).onWeakEscrowTokenRemoved(eq(handle1), 190 eq(mTestUser)); 191 }, MANAGE_WEAK_ESCROW_TOKEN); 192 } 193 194 @Test testWeakEscrowTokenRemovedWhenCredentialChanged()195 public void testWeakEscrowTokenRemovedWhenCredentialChanged() { 196 assumeIsAutomotiveDevice(); 197 assumeKeyguardManagerAvailable(); 198 199 runWithShellPermissionIdentity(() -> { 200 long handle = mKeyguardManager.addWeakEscrowToken(mTestToken1, mTestUser, mTestExecutor, 201 mMockTokenActivatedListener); 202 setLockCredential(TEST_PIN1); 203 boolean isActiveBeforeCredentialChange = mKeyguardManager 204 .isWeakEscrowTokenActive(handle, mTestUser); 205 updateLockCredential(TEST_PIN1, TEST_PIN2); 206 boolean isActiveAfterCredentialChange = mKeyguardManager.isWeakEscrowTokenActive(handle, 207 mTestUser); 208 209 assertThat(isActiveBeforeCredentialChange).isTrue(); 210 assertThat(isActiveAfterCredentialChange).isFalse(); 211 }, MANAGE_WEAK_ESCROW_TOKEN); 212 } 213 214 @Test testAutoEscrowTokenRemovedWhenCredentialRemoved()215 public void testAutoEscrowTokenRemovedWhenCredentialRemoved() { 216 assumeIsAutomotiveDevice(); 217 assumeKeyguardManagerAvailable(); 218 219 runWithShellPermissionIdentity(() -> { 220 long handle = mKeyguardManager.addWeakEscrowToken(mTestToken1, mTestUser, mTestExecutor, 221 mMockTokenActivatedListener); 222 setLockCredential(TEST_PIN1); 223 boolean isActiveBeforeCredentialRemove = mKeyguardManager 224 .isWeakEscrowTokenActive(handle, mTestUser); 225 removeLockCredential(TEST_PIN1); 226 boolean isActiveAfterCredentialRemove = mKeyguardManager.isWeakEscrowTokenActive(handle, 227 mTestUser); 228 229 assertThat(isActiveBeforeCredentialRemove).isTrue(); 230 assertThat(isActiveAfterCredentialRemove).isFalse(); 231 }, MANAGE_WEAK_ESCROW_TOKEN); 232 } 233 assumeIsAutomotiveDevice()234 private void assumeIsAutomotiveDevice() { 235 assumeTrue("Test skipped because it's not running on automotive device.", 236 isAutomotiveDevice()); 237 } 238 isAutomotiveDevice()239 private boolean isAutomotiveDevice() { 240 return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); 241 } 242 assumeKeyguardManagerAvailable()243 private void assumeKeyguardManagerAvailable() { 244 assumeFalse("Test skipped because KeyguardManager is not available.", 245 mKeyguardManager == null); 246 } 247 removeLockCredential(String oldCredential)248 private static void removeLockCredential(String oldCredential) throws IOException { 249 runShellCommand(InstrumentationRegistry.getInstrumentation(), "locksettings clear --old " 250 + oldCredential); 251 } 252 updateLockCredential(String oldCredential, String credential)253 private static void updateLockCredential(String oldCredential, String credential) 254 throws IOException { 255 runShellCommand(InstrumentationRegistry.getInstrumentation(), 256 String.format("locksettings set-pin --old %s %s", oldCredential, credential)); 257 } 258 setLockCredential(String credential)259 private static void setLockCredential(String credential) throws IOException { 260 runShellCommand(InstrumentationRegistry.getInstrumentation(), "locksettings set-pin " 261 + credential); 262 } 263 verifyCredential(String credential)264 private static void verifyCredential(String credential) throws IOException { 265 runShellCommand(InstrumentationRegistry.getInstrumentation(), "locksettings verify --old " 266 + credential); 267 } 268 } 269