blob: 449a54c082dcdf771bcef7e1e21478badb2b67bb [file] [log] [blame]
Adrian Roose5424992014-11-07 21:47:17 +01001/*
2 * Copyright (C) 2014 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
Andrew Scull507d11c2017-05-03 17:19:01 +010017package com.android.server.locksettings;
Adrian Roose5424992014-11-07 21:47:17 +010018
Rubin Xu1de89b32016-11-30 20:03:13 +000019import static org.mockito.Matchers.eq;
20import static org.mockito.Mockito.mock;
21import static org.mockito.Mockito.when;
22
Rubin Xu0cbc19e2016-12-09 14:00:21 +000023import android.app.NotificationManager;
Rubin Xu8b30ec32017-03-05 00:47:09 +000024import android.app.admin.DevicePolicyManager;
Adrian Roose5424992014-11-07 21:47:17 +010025import android.content.Context;
26import android.content.ContextWrapper;
27import android.content.pm.UserInfo;
28import android.database.sqlite.SQLiteDatabase;
29import android.os.FileUtils;
30import android.os.UserManager;
Rubin Xuaa32d152017-04-27 17:01:05 +010031import android.os.storage.StorageManager;
Adrian Roose5424992014-11-07 21:47:17 +010032import android.test.AndroidTestCase;
33
Rubin Xu1de89b32016-11-30 20:03:13 +000034import com.android.internal.widget.LockPatternUtils;
Andrew Scull507d11c2017-05-03 17:19:01 +010035import com.android.server.locksettings.LockSettingsStorage.CredentialHash;
Adrian Roose5424992014-11-07 21:47:17 +010036import java.io.File;
37import java.util.ArrayList;
38import java.util.Arrays;
39import java.util.List;
40import java.util.concurrent.CountDownLatch;
41
Rubin Xu1de89b32016-11-30 20:03:13 +000042/**
Andrew Scull507d11c2017-05-03 17:19:01 +010043 * runtest frameworks-services -c com.android.server.locksettings.LockSettingsStorageTests
Rubin Xu1de89b32016-11-30 20:03:13 +000044 */
Adrian Roose5424992014-11-07 21:47:17 +010045public class LockSettingsStorageTests extends AndroidTestCase {
Rubin Xu1de89b32016-11-30 20:03:13 +000046 private final byte[] PASSWORD_0 = "thepassword0".getBytes();
47 private final byte[] PASSWORD_1 = "password1".getBytes();
48 private final byte[] PATTERN_0 = "123654".getBytes();
49 private final byte[] PATTERN_1 = "147852369".getBytes();
50
Adrian Roose5424992014-11-07 21:47:17 +010051 LockSettingsStorage mStorage;
52 File mStorageDir;
53
54 private File mDb;
55
56 @Override
57 protected void setUp() throws Exception {
58 super.setUp();
59 mStorageDir = new File(getContext().getFilesDir(), "locksettings");
60 mDb = getContext().getDatabasePath("locksettings.db");
61
62 assertTrue(mStorageDir.exists() || mStorageDir.mkdirs());
63 assertTrue(FileUtils.deleteContents(mStorageDir));
64 assertTrue(!mDb.exists() || mDb.delete());
65
Rubin Xu1de89b32016-11-30 20:03:13 +000066 final UserManager mockUserManager = mock(UserManager.class);
67 // User 2 is a profile of user 1.
68 when(mockUserManager.getProfileParent(eq(2))).thenReturn(new UserInfo(1, "name", 0));
69 // User 3 is a profile of user 0.
70 when(mockUserManager.getProfileParent(eq(3))).thenReturn(new UserInfo(0, "name", 0));
Adrian Roose5424992014-11-07 21:47:17 +010071
Rubin Xu0cbc19e2016-12-09 14:00:21 +000072 MockLockSettingsContext context = new MockLockSettingsContext(getContext(), mockUserManager,
Rubin Xuaa32d152017-04-27 17:01:05 +010073 mock(NotificationManager.class), mock(DevicePolicyManager.class),
74 mock(StorageManager.class));
Rubin Xu0cbc19e2016-12-09 14:00:21 +000075 mStorage = new LockSettingsStorageTestable(context,
76 new File(getContext().getFilesDir(), "locksettings"));
77 mStorage.setDatabaseOnCreateCallback(new LockSettingsStorage.Callback() {
78 @Override
79 public void initialize(SQLiteDatabase db) {
80 mStorage.writeKeyValue(db, "initializedKey", "initialValue", 0);
81 }
82 });
Adrian Roose5424992014-11-07 21:47:17 +010083 }
84
85 @Override
86 protected void tearDown() throws Exception {
87 super.tearDown();
88 mStorage.closeDatabase();
89 }
90
91 public void testKeyValue_InitializeWorked() {
92 assertEquals("initialValue", mStorage.readKeyValue("initializedKey", "default", 0));
93 mStorage.clearCache();
94 assertEquals("initialValue", mStorage.readKeyValue("initializedKey", "default", 0));
95 }
96
97 public void testKeyValue_WriteThenRead() {
98 mStorage.writeKeyValue("key", "value", 0);
99 assertEquals("value", mStorage.readKeyValue("key", "default", 0));
100 mStorage.clearCache();
101 assertEquals("value", mStorage.readKeyValue("key", "default", 0));
102 }
103
104 public void testKeyValue_DefaultValue() {
105 assertEquals("default", mStorage.readKeyValue("unititialized key", "default", 0));
106 assertEquals("default2", mStorage.readKeyValue("unititialized key", "default2", 0));
107 }
108
109 public void testKeyValue_Concurrency() {
110 final Object monitor = new Object();
111 List<Thread> threads = new ArrayList<>();
112 for (int i = 0; i < 100; i++) {
113 final int threadId = i;
114 threads.add(new Thread() {
115 @Override
116 public void run() {
117 synchronized (monitor) {
118 try {
119 monitor.wait();
120 } catch (InterruptedException e) {
121 return;
122 }
123 mStorage.writeKeyValue("key", "1 from thread " + threadId, 0);
124 mStorage.readKeyValue("key", "default", 0);
125 mStorage.writeKeyValue("key", "2 from thread " + threadId, 0);
126 mStorage.readKeyValue("key", "default", 0);
127 mStorage.writeKeyValue("key", "3 from thread " + threadId, 0);
128 mStorage.readKeyValue("key", "default", 0);
129 mStorage.writeKeyValue("key", "4 from thread " + threadId, 0);
130 mStorage.readKeyValue("key", "default", 0);
131 mStorage.writeKeyValue("key", "5 from thread " + threadId, 0);
132 mStorage.readKeyValue("key", "default", 0);
133 }
134 }
135 });
136 threads.get(i).start();
137 }
138 mStorage.writeKeyValue("key", "initalValue", 0);
139 synchronized (monitor) {
140 monitor.notifyAll();
141 }
142 for (int i = 0; i < threads.size(); i++) {
143 try {
144 threads.get(i).join();
145 } catch (InterruptedException e) {
146 }
147 }
148 assertEquals('5', mStorage.readKeyValue("key", "default", 0).charAt(0));
149 mStorage.clearCache();
150 assertEquals('5', mStorage.readKeyValue("key", "default", 0).charAt(0));
151 }
152
153 public void testKeyValue_CacheStarvedWriter() {
154 final CountDownLatch latch = new CountDownLatch(1);
155 List<Thread> threads = new ArrayList<>();
156 for (int i = 0; i < 100; i++) {
157 final int threadId = i;
158 threads.add(new Thread() {
159 @Override
160 public void run() {
161 try {
162 latch.await();
163 } catch (InterruptedException e) {
164 return;
165 }
166 if (threadId == 50) {
167 mStorage.writeKeyValue("starvedWriterKey", "value", 0);
168 } else {
169 mStorage.readKeyValue("starvedWriterKey", "default", 0);
170 }
171 }
172 });
173 threads.get(i).start();
174 }
175 latch.countDown();
176 for (int i = 0; i < threads.size(); i++) {
177 try {
178 threads.get(i).join();
179 } catch (InterruptedException e) {
180 }
181 }
182 String cached = mStorage.readKeyValue("key", "default", 0);
183 mStorage.clearCache();
184 String storage = mStorage.readKeyValue("key", "default", 0);
185 assertEquals("Cached value didn't match stored value", storage, cached);
186 }
187
188 public void testRemoveUser() {
189 mStorage.writeKeyValue("key", "value", 0);
Rubin Xu1de89b32016-11-30 20:03:13 +0000190 writePasswordBytes(PASSWORD_0, 0);
191 writePatternBytes(PATTERN_0, 0);
Adrian Roose5424992014-11-07 21:47:17 +0100192
193 mStorage.writeKeyValue("key", "value", 1);
Rubin Xu1de89b32016-11-30 20:03:13 +0000194 writePasswordBytes(PASSWORD_1, 1);
195 writePatternBytes(PATTERN_1, 1);
Adrian Roose5424992014-11-07 21:47:17 +0100196
197 mStorage.removeUser(0);
198
199 assertEquals("value", mStorage.readKeyValue("key", "default", 1));
200 assertEquals("default", mStorage.readKeyValue("key", "default", 0));
Rubin Xu1de89b32016-11-30 20:03:13 +0000201 assertEquals(LockPatternUtils.CREDENTIAL_TYPE_NONE, mStorage.readCredentialHash(0).type);
202 assertPatternBytes(PATTERN_1, 1);
Adrian Roose5424992014-11-07 21:47:17 +0100203 }
204
Rubin Xu1de89b32016-11-30 20:03:13 +0000205 public void testCredential_Default() {
206 assertEquals(mStorage.readCredentialHash(0).type, LockPatternUtils.CREDENTIAL_TYPE_NONE);
Adrian Roose5424992014-11-07 21:47:17 +0100207 }
208
209 public void testPassword_Write() {
Rubin Xu1de89b32016-11-30 20:03:13 +0000210 writePasswordBytes(PASSWORD_0, 0);
Adrian Roose5424992014-11-07 21:47:17 +0100211
Rubin Xu1de89b32016-11-30 20:03:13 +0000212 assertPasswordBytes(PASSWORD_0, 0);
Adrian Roose5424992014-11-07 21:47:17 +0100213 mStorage.clearCache();
Rubin Xu1de89b32016-11-30 20:03:13 +0000214 assertPasswordBytes(PASSWORD_0, 0);
Adrian Roose5424992014-11-07 21:47:17 +0100215 }
216
217 public void testPassword_WriteProfileWritesParent() {
Rubin Xu1de89b32016-11-30 20:03:13 +0000218 writePasswordBytes(PASSWORD_0, 1);
219 writePasswordBytes(PASSWORD_1, 2);
Adrian Roose5424992014-11-07 21:47:17 +0100220
Rubin Xu1de89b32016-11-30 20:03:13 +0000221 assertPasswordBytes(PASSWORD_0, 1);
222 assertPasswordBytes(PASSWORD_1, 2);
Adrian Roose5424992014-11-07 21:47:17 +0100223 mStorage.clearCache();
Rubin Xu1de89b32016-11-30 20:03:13 +0000224 assertPasswordBytes(PASSWORD_0, 1);
225 assertPasswordBytes(PASSWORD_1, 2);
Adrian Roose5424992014-11-07 21:47:17 +0100226 }
227
Ricky Waia46b40f2016-03-31 16:48:29 +0100228 public void testLockType_WriteProfileWritesParent() {
Rubin Xu1de89b32016-11-30 20:03:13 +0000229 writePasswordBytes(PASSWORD_0, 10);
230 writePatternBytes(PATTERN_0, 20);
Ricky Waia46b40f2016-03-31 16:48:29 +0100231
Rubin Xu1de89b32016-11-30 20:03:13 +0000232 assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
233 mStorage.readCredentialHash(10).type);
234 assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
235 mStorage.readCredentialHash(20).type);
Ricky Waia46b40f2016-03-31 16:48:29 +0100236 mStorage.clearCache();
Rubin Xu1de89b32016-11-30 20:03:13 +0000237 assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
238 mStorage.readCredentialHash(10).type);
239 assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
240 mStorage.readCredentialHash(20).type);
241 }
242
243 public void testPassword_WriteParentWritesProfile() {
244 writePasswordBytes(PASSWORD_0, 2);
245 writePasswordBytes(PASSWORD_1, 1);
246
247 assertPasswordBytes(PASSWORD_1, 1);
248 assertPasswordBytes(PASSWORD_0, 2);
249 mStorage.clearCache();
250 assertPasswordBytes(PASSWORD_1, 1);
251 assertPasswordBytes(PASSWORD_0, 2);
Ricky Waia46b40f2016-03-31 16:48:29 +0100252 }
253
254 public void testProfileLock_ReadWriteChildProfileLock() {
255 assertFalse(mStorage.hasChildProfileLock(20));
Rubin Xu1de89b32016-11-30 20:03:13 +0000256 mStorage.writeChildProfileLock(20, PASSWORD_0);
257 assertArrayEquals(PASSWORD_0, mStorage.readChildProfileLock(20));
Ricky Waia46b40f2016-03-31 16:48:29 +0100258 assertTrue(mStorage.hasChildProfileLock(20));
259 mStorage.clearCache();
Rubin Xu1de89b32016-11-30 20:03:13 +0000260 assertArrayEquals(PASSWORD_0, mStorage.readChildProfileLock(20));
Ricky Waia46b40f2016-03-31 16:48:29 +0100261 assertTrue(mStorage.hasChildProfileLock(20));
262 }
263
Adrian Roose5424992014-11-07 21:47:17 +0100264 public void testPattern_Write() {
Rubin Xu1de89b32016-11-30 20:03:13 +0000265 writePatternBytes(PATTERN_0, 0);
Adrian Roose5424992014-11-07 21:47:17 +0100266
Rubin Xu1de89b32016-11-30 20:03:13 +0000267 assertPatternBytes(PATTERN_0, 0);
Adrian Roose5424992014-11-07 21:47:17 +0100268 mStorage.clearCache();
Rubin Xu1de89b32016-11-30 20:03:13 +0000269 assertPatternBytes(PATTERN_0, 0);
Adrian Roose5424992014-11-07 21:47:17 +0100270 }
271
272 public void testPattern_WriteProfileWritesParent() {
Rubin Xu1de89b32016-11-30 20:03:13 +0000273 writePatternBytes(PATTERN_0, 1);
274 writePatternBytes(PATTERN_1, 2);
Adrian Roose5424992014-11-07 21:47:17 +0100275
Rubin Xu1de89b32016-11-30 20:03:13 +0000276 assertPatternBytes(PATTERN_0, 1);
277 assertPatternBytes(PATTERN_1, 2);
Adrian Roose5424992014-11-07 21:47:17 +0100278 mStorage.clearCache();
Rubin Xu1de89b32016-11-30 20:03:13 +0000279 assertPatternBytes(PATTERN_0, 1);
280 assertPatternBytes(PATTERN_1, 2);
Adrian Roose5424992014-11-07 21:47:17 +0100281 }
282
283 public void testPattern_WriteParentWritesProfile() {
Rubin Xu1de89b32016-11-30 20:03:13 +0000284 writePatternBytes(PATTERN_1, 2);
285 writePatternBytes(PATTERN_0, 1);
Adrian Roose5424992014-11-07 21:47:17 +0100286
Rubin Xu1de89b32016-11-30 20:03:13 +0000287 assertPatternBytes(PATTERN_0, 1);
288 assertPatternBytes(PATTERN_1, 2);
Adrian Roose5424992014-11-07 21:47:17 +0100289 mStorage.clearCache();
Rubin Xu1de89b32016-11-30 20:03:13 +0000290 assertPatternBytes(PATTERN_0, 1);
291 assertPatternBytes(PATTERN_1, 2);
Adrian Roose5424992014-11-07 21:47:17 +0100292 }
293
294 public void testPrefetch() {
295 mStorage.writeKeyValue("key", "toBeFetched", 0);
Rubin Xu1de89b32016-11-30 20:03:13 +0000296 writePatternBytes(PATTERN_0, 0);
Adrian Roose5424992014-11-07 21:47:17 +0100297
298 mStorage.clearCache();
299 mStorage.prefetchUser(0);
300
301 assertEquals("toBeFetched", mStorage.readKeyValue("key", "default", 0));
Rubin Xu1de89b32016-11-30 20:03:13 +0000302 assertPatternBytes(PATTERN_0, 0);
Adrian Roose5424992014-11-07 21:47:17 +0100303 }
304
305 public void testFileLocation_Owner() {
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000306 LockSettingsStorage storage = new LockSettingsStorage(getContext());
Adrian Roose5424992014-11-07 21:47:17 +0100307
Rubin Xu1de89b32016-11-30 20:03:13 +0000308 assertEquals("/data/system/gesture.key", storage.getLegacyLockPatternFilename(0));
309 assertEquals("/data/system/password.key", storage.getLegacyLockPasswordFilename(0));
310 assertEquals("/data/system/gatekeeper.pattern.key", storage.getLockPatternFilename(0));
311 assertEquals("/data/system/gatekeeper.password.key", storage.getLockPasswordFilename(0));
Adrian Roose5424992014-11-07 21:47:17 +0100312 }
313
314 public void testFileLocation_SecondaryUser() {
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000315 LockSettingsStorage storage = new LockSettingsStorage(getContext());
Adrian Roose5424992014-11-07 21:47:17 +0100316
Rubin Xu1de89b32016-11-30 20:03:13 +0000317 assertEquals("/data/system/users/1/gatekeeper.pattern.key", storage.getLockPatternFilename(1));
318 assertEquals("/data/system/users/1/gatekeeper.password.key", storage.getLockPasswordFilename(1));
Adrian Roose5424992014-11-07 21:47:17 +0100319 }
320
321 public void testFileLocation_ProfileToSecondary() {
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000322 LockSettingsStorage storage = new LockSettingsStorage(getContext());
Adrian Roose5424992014-11-07 21:47:17 +0100323
Rubin Xu1de89b32016-11-30 20:03:13 +0000324 assertEquals("/data/system/users/2/gatekeeper.pattern.key", storage.getLockPatternFilename(2));
325 assertEquals("/data/system/users/2/gatekeeper.password.key", storage.getLockPasswordFilename(2));
Adrian Roose5424992014-11-07 21:47:17 +0100326 }
327
328 public void testFileLocation_ProfileToOwner() {
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000329 LockSettingsStorage storage = new LockSettingsStorage(getContext());
Adrian Roose5424992014-11-07 21:47:17 +0100330
Rubin Xu1de89b32016-11-30 20:03:13 +0000331 assertEquals("/data/system/users/3/gatekeeper.pattern.key", storage.getLockPatternFilename(3));
332 assertEquals("/data/system/users/3/gatekeeper.password.key", storage.getLockPasswordFilename(3));
Adrian Roose5424992014-11-07 21:47:17 +0100333 }
334
Rubin Xu3bf722a2016-12-15 16:07:38 +0000335 public void testSyntheticPasswordState() {
336 final byte[] data = {1,2,3,4};
337 mStorage.writeSyntheticPasswordState(10, 1234L, "state", data);
338 assertArrayEquals(data, mStorage.readSyntheticPasswordState(10, 1234L, "state"));
339 assertEquals(null, mStorage.readSyntheticPasswordState(0, 1234L, "state"));
340
Rubin Xuaa32d152017-04-27 17:01:05 +0100341 mStorage.deleteSyntheticPasswordState(10, 1234L, "state");
Rubin Xu3bf722a2016-12-15 16:07:38 +0000342 assertEquals(null, mStorage.readSyntheticPasswordState(10, 1234L, "state"));
343 }
344
Adrian Roose5424992014-11-07 21:47:17 +0100345 private static void assertArrayEquals(byte[] expected, byte[] actual) {
346 if (!Arrays.equals(expected, actual)) {
347 fail("expected:<" + Arrays.toString(expected) +
348 "> but was:<" + Arrays.toString(actual) + ">");
349 }
350 }
Rubin Xu1de89b32016-11-30 20:03:13 +0000351
352 private void writePasswordBytes(byte[] password, int userId) {
353 mStorage.writeCredentialHash(CredentialHash.create(
354 password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD), userId);
355 }
356
357 private void writePatternBytes(byte[] pattern, int userId) {
358 mStorage.writeCredentialHash(CredentialHash.create(
359 pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN), userId);
360 }
361
362 private void assertPasswordBytes(byte[] password, int userId) {
363 CredentialHash cred = mStorage.readCredentialHash(userId);
364 assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, cred.type);
365 assertArrayEquals(password, cred.hash);
366 }
367
368 private void assertPatternBytes(byte[] pattern, int userId) {
369 CredentialHash cred = mStorage.readCredentialHash(userId);
370 assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PATTERN, cred.type);
371 assertArrayEquals(pattern, cred.hash);
372 }
Adrian Roose5424992014-11-07 21:47:17 +0100373}