• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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