blob: c68fbdc0a2ac836af0b50e0d5a8088f5af89a4ce [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
17package com.android.server;
18
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;
Adrian Roose5424992014-11-07 21:47:17 +010024import android.content.Context;
25import android.content.ContextWrapper;
26import android.content.pm.UserInfo;
27import android.database.sqlite.SQLiteDatabase;
28import android.os.FileUtils;
29import android.os.UserManager;
30import android.test.AndroidTestCase;
31
Rubin Xu1de89b32016-11-30 20:03:13 +000032import com.android.internal.widget.LockPatternUtils;
33import com.android.server.LockSettingsStorage.CredentialHash;
Adrian Roose5424992014-11-07 21:47:17 +010034import java.io.File;
35import java.util.ArrayList;
36import java.util.Arrays;
37import java.util.List;
38import java.util.concurrent.CountDownLatch;
39
Rubin Xu1de89b32016-11-30 20:03:13 +000040/**
41 * runtest frameworks-services -c com.android.server.LockSettingsStorageTests
42 */
Adrian Roose5424992014-11-07 21:47:17 +010043public class LockSettingsStorageTests extends AndroidTestCase {
Rubin Xu1de89b32016-11-30 20:03:13 +000044 private final byte[] PASSWORD_0 = "thepassword0".getBytes();
45 private final byte[] PASSWORD_1 = "password1".getBytes();
46 private final byte[] PATTERN_0 = "123654".getBytes();
47 private final byte[] PATTERN_1 = "147852369".getBytes();
48
Adrian Roose5424992014-11-07 21:47:17 +010049 LockSettingsStorage mStorage;
50 File mStorageDir;
51
52 private File mDb;
53
54 @Override
55 protected void setUp() throws Exception {
56 super.setUp();
57 mStorageDir = new File(getContext().getFilesDir(), "locksettings");
58 mDb = getContext().getDatabasePath("locksettings.db");
59
60 assertTrue(mStorageDir.exists() || mStorageDir.mkdirs());
61 assertTrue(FileUtils.deleteContents(mStorageDir));
62 assertTrue(!mDb.exists() || mDb.delete());
63
Rubin Xu1de89b32016-11-30 20:03:13 +000064 final UserManager mockUserManager = mock(UserManager.class);
65 // User 2 is a profile of user 1.
66 when(mockUserManager.getProfileParent(eq(2))).thenReturn(new UserInfo(1, "name", 0));
67 // User 3 is a profile of user 0.
68 when(mockUserManager.getProfileParent(eq(3))).thenReturn(new UserInfo(0, "name", 0));
Adrian Roose5424992014-11-07 21:47:17 +010069
Rubin Xu0cbc19e2016-12-09 14:00:21 +000070 MockLockSettingsContext context = new MockLockSettingsContext(getContext(), mockUserManager,
71 mock(NotificationManager.class));
72 mStorage = new LockSettingsStorageTestable(context,
73 new File(getContext().getFilesDir(), "locksettings"));
74 mStorage.setDatabaseOnCreateCallback(new LockSettingsStorage.Callback() {
75 @Override
76 public void initialize(SQLiteDatabase db) {
77 mStorage.writeKeyValue(db, "initializedKey", "initialValue", 0);
78 }
79 });
Adrian Roose5424992014-11-07 21:47:17 +010080 }
81
82 @Override
83 protected void tearDown() throws Exception {
84 super.tearDown();
85 mStorage.closeDatabase();
86 }
87
88 public void testKeyValue_InitializeWorked() {
89 assertEquals("initialValue", mStorage.readKeyValue("initializedKey", "default", 0));
90 mStorage.clearCache();
91 assertEquals("initialValue", mStorage.readKeyValue("initializedKey", "default", 0));
92 }
93
94 public void testKeyValue_WriteThenRead() {
95 mStorage.writeKeyValue("key", "value", 0);
96 assertEquals("value", mStorage.readKeyValue("key", "default", 0));
97 mStorage.clearCache();
98 assertEquals("value", mStorage.readKeyValue("key", "default", 0));
99 }
100
101 public void testKeyValue_DefaultValue() {
102 assertEquals("default", mStorage.readKeyValue("unititialized key", "default", 0));
103 assertEquals("default2", mStorage.readKeyValue("unititialized key", "default2", 0));
104 }
105
106 public void testKeyValue_Concurrency() {
107 final Object monitor = new Object();
108 List<Thread> threads = new ArrayList<>();
109 for (int i = 0; i < 100; i++) {
110 final int threadId = i;
111 threads.add(new Thread() {
112 @Override
113 public void run() {
114 synchronized (monitor) {
115 try {
116 monitor.wait();
117 } catch (InterruptedException e) {
118 return;
119 }
120 mStorage.writeKeyValue("key", "1 from thread " + threadId, 0);
121 mStorage.readKeyValue("key", "default", 0);
122 mStorage.writeKeyValue("key", "2 from thread " + threadId, 0);
123 mStorage.readKeyValue("key", "default", 0);
124 mStorage.writeKeyValue("key", "3 from thread " + threadId, 0);
125 mStorage.readKeyValue("key", "default", 0);
126 mStorage.writeKeyValue("key", "4 from thread " + threadId, 0);
127 mStorage.readKeyValue("key", "default", 0);
128 mStorage.writeKeyValue("key", "5 from thread " + threadId, 0);
129 mStorage.readKeyValue("key", "default", 0);
130 }
131 }
132 });
133 threads.get(i).start();
134 }
135 mStorage.writeKeyValue("key", "initalValue", 0);
136 synchronized (monitor) {
137 monitor.notifyAll();
138 }
139 for (int i = 0; i < threads.size(); i++) {
140 try {
141 threads.get(i).join();
142 } catch (InterruptedException e) {
143 }
144 }
145 assertEquals('5', mStorage.readKeyValue("key", "default", 0).charAt(0));
146 mStorage.clearCache();
147 assertEquals('5', mStorage.readKeyValue("key", "default", 0).charAt(0));
148 }
149
150 public void testKeyValue_CacheStarvedWriter() {
151 final CountDownLatch latch = new CountDownLatch(1);
152 List<Thread> threads = new ArrayList<>();
153 for (int i = 0; i < 100; i++) {
154 final int threadId = i;
155 threads.add(new Thread() {
156 @Override
157 public void run() {
158 try {
159 latch.await();
160 } catch (InterruptedException e) {
161 return;
162 }
163 if (threadId == 50) {
164 mStorage.writeKeyValue("starvedWriterKey", "value", 0);
165 } else {
166 mStorage.readKeyValue("starvedWriterKey", "default", 0);
167 }
168 }
169 });
170 threads.get(i).start();
171 }
172 latch.countDown();
173 for (int i = 0; i < threads.size(); i++) {
174 try {
175 threads.get(i).join();
176 } catch (InterruptedException e) {
177 }
178 }
179 String cached = mStorage.readKeyValue("key", "default", 0);
180 mStorage.clearCache();
181 String storage = mStorage.readKeyValue("key", "default", 0);
182 assertEquals("Cached value didn't match stored value", storage, cached);
183 }
184
185 public void testRemoveUser() {
186 mStorage.writeKeyValue("key", "value", 0);
Rubin Xu1de89b32016-11-30 20:03:13 +0000187 writePasswordBytes(PASSWORD_0, 0);
188 writePatternBytes(PATTERN_0, 0);
Adrian Roose5424992014-11-07 21:47:17 +0100189
190 mStorage.writeKeyValue("key", "value", 1);
Rubin Xu1de89b32016-11-30 20:03:13 +0000191 writePasswordBytes(PASSWORD_1, 1);
192 writePatternBytes(PATTERN_1, 1);
Adrian Roose5424992014-11-07 21:47:17 +0100193
194 mStorage.removeUser(0);
195
196 assertEquals("value", mStorage.readKeyValue("key", "default", 1));
197 assertEquals("default", mStorage.readKeyValue("key", "default", 0));
Rubin Xu1de89b32016-11-30 20:03:13 +0000198 assertEquals(LockPatternUtils.CREDENTIAL_TYPE_NONE, mStorage.readCredentialHash(0).type);
199 assertPatternBytes(PATTERN_1, 1);
Adrian Roose5424992014-11-07 21:47:17 +0100200 }
201
Rubin Xu1de89b32016-11-30 20:03:13 +0000202 public void testCredential_Default() {
203 assertEquals(mStorage.readCredentialHash(0).type, LockPatternUtils.CREDENTIAL_TYPE_NONE);
Adrian Roose5424992014-11-07 21:47:17 +0100204 }
205
206 public void testPassword_Write() {
Rubin Xu1de89b32016-11-30 20:03:13 +0000207 writePasswordBytes(PASSWORD_0, 0);
Adrian Roose5424992014-11-07 21:47:17 +0100208
Rubin Xu1de89b32016-11-30 20:03:13 +0000209 assertPasswordBytes(PASSWORD_0, 0);
Adrian Roose5424992014-11-07 21:47:17 +0100210 mStorage.clearCache();
Rubin Xu1de89b32016-11-30 20:03:13 +0000211 assertPasswordBytes(PASSWORD_0, 0);
Adrian Roose5424992014-11-07 21:47:17 +0100212 }
213
214 public void testPassword_WriteProfileWritesParent() {
Rubin Xu1de89b32016-11-30 20:03:13 +0000215 writePasswordBytes(PASSWORD_0, 1);
216 writePasswordBytes(PASSWORD_1, 2);
Adrian Roose5424992014-11-07 21:47:17 +0100217
Rubin Xu1de89b32016-11-30 20:03:13 +0000218 assertPasswordBytes(PASSWORD_0, 1);
219 assertPasswordBytes(PASSWORD_1, 2);
Adrian Roose5424992014-11-07 21:47:17 +0100220 mStorage.clearCache();
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 }
224
Ricky Waia46b40f2016-03-31 16:48:29 +0100225 public void testLockType_WriteProfileWritesParent() {
Rubin Xu1de89b32016-11-30 20:03:13 +0000226 writePasswordBytes(PASSWORD_0, 10);
227 writePatternBytes(PATTERN_0, 20);
Ricky Waia46b40f2016-03-31 16:48:29 +0100228
Rubin Xu1de89b32016-11-30 20:03:13 +0000229 assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
230 mStorage.readCredentialHash(10).type);
231 assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
232 mStorage.readCredentialHash(20).type);
Ricky Waia46b40f2016-03-31 16:48:29 +0100233 mStorage.clearCache();
Rubin Xu1de89b32016-11-30 20:03:13 +0000234 assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
235 mStorage.readCredentialHash(10).type);
236 assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
237 mStorage.readCredentialHash(20).type);
238 }
239
240 public void testPassword_WriteParentWritesProfile() {
241 writePasswordBytes(PASSWORD_0, 2);
242 writePasswordBytes(PASSWORD_1, 1);
243
244 assertPasswordBytes(PASSWORD_1, 1);
245 assertPasswordBytes(PASSWORD_0, 2);
246 mStorage.clearCache();
247 assertPasswordBytes(PASSWORD_1, 1);
248 assertPasswordBytes(PASSWORD_0, 2);
Ricky Waia46b40f2016-03-31 16:48:29 +0100249 }
250
251 public void testProfileLock_ReadWriteChildProfileLock() {
252 assertFalse(mStorage.hasChildProfileLock(20));
Rubin Xu1de89b32016-11-30 20:03:13 +0000253 mStorage.writeChildProfileLock(20, PASSWORD_0);
254 assertArrayEquals(PASSWORD_0, mStorage.readChildProfileLock(20));
Ricky Waia46b40f2016-03-31 16:48:29 +0100255 assertTrue(mStorage.hasChildProfileLock(20));
256 mStorage.clearCache();
Rubin Xu1de89b32016-11-30 20:03:13 +0000257 assertArrayEquals(PASSWORD_0, mStorage.readChildProfileLock(20));
Ricky Waia46b40f2016-03-31 16:48:29 +0100258 assertTrue(mStorage.hasChildProfileLock(20));
259 }
260
Adrian Roose5424992014-11-07 21:47:17 +0100261 public void testPattern_Write() {
Rubin Xu1de89b32016-11-30 20:03:13 +0000262 writePatternBytes(PATTERN_0, 0);
Adrian Roose5424992014-11-07 21:47:17 +0100263
Rubin Xu1de89b32016-11-30 20:03:13 +0000264 assertPatternBytes(PATTERN_0, 0);
Adrian Roose5424992014-11-07 21:47:17 +0100265 mStorage.clearCache();
Rubin Xu1de89b32016-11-30 20:03:13 +0000266 assertPatternBytes(PATTERN_0, 0);
Adrian Roose5424992014-11-07 21:47:17 +0100267 }
268
269 public void testPattern_WriteProfileWritesParent() {
Rubin Xu1de89b32016-11-30 20:03:13 +0000270 writePatternBytes(PATTERN_0, 1);
271 writePatternBytes(PATTERN_1, 2);
Adrian Roose5424992014-11-07 21:47:17 +0100272
Rubin Xu1de89b32016-11-30 20:03:13 +0000273 assertPatternBytes(PATTERN_0, 1);
274 assertPatternBytes(PATTERN_1, 2);
Adrian Roose5424992014-11-07 21:47:17 +0100275 mStorage.clearCache();
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 }
279
280 public void testPattern_WriteParentWritesProfile() {
Rubin Xu1de89b32016-11-30 20:03:13 +0000281 writePatternBytes(PATTERN_1, 2);
282 writePatternBytes(PATTERN_0, 1);
Adrian Roose5424992014-11-07 21:47:17 +0100283
Rubin Xu1de89b32016-11-30 20:03:13 +0000284 assertPatternBytes(PATTERN_0, 1);
285 assertPatternBytes(PATTERN_1, 2);
Adrian Roose5424992014-11-07 21:47:17 +0100286 mStorage.clearCache();
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 }
290
291 public void testPrefetch() {
292 mStorage.writeKeyValue("key", "toBeFetched", 0);
Rubin Xu1de89b32016-11-30 20:03:13 +0000293 writePatternBytes(PATTERN_0, 0);
Adrian Roose5424992014-11-07 21:47:17 +0100294
295 mStorage.clearCache();
296 mStorage.prefetchUser(0);
297
298 assertEquals("toBeFetched", mStorage.readKeyValue("key", "default", 0));
Rubin Xu1de89b32016-11-30 20:03:13 +0000299 assertPatternBytes(PATTERN_0, 0);
Adrian Roose5424992014-11-07 21:47:17 +0100300 }
301
302 public void testFileLocation_Owner() {
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000303 LockSettingsStorage storage = new LockSettingsStorage(getContext());
Adrian Roose5424992014-11-07 21:47:17 +0100304
Rubin Xu1de89b32016-11-30 20:03:13 +0000305 assertEquals("/data/system/gesture.key", storage.getLegacyLockPatternFilename(0));
306 assertEquals("/data/system/password.key", storage.getLegacyLockPasswordFilename(0));
307 assertEquals("/data/system/gatekeeper.pattern.key", storage.getLockPatternFilename(0));
308 assertEquals("/data/system/gatekeeper.password.key", storage.getLockPasswordFilename(0));
Adrian Roose5424992014-11-07 21:47:17 +0100309 }
310
311 public void testFileLocation_SecondaryUser() {
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000312 LockSettingsStorage storage = new LockSettingsStorage(getContext());
Adrian Roose5424992014-11-07 21:47:17 +0100313
Rubin Xu1de89b32016-11-30 20:03:13 +0000314 assertEquals("/data/system/users/1/gatekeeper.pattern.key", storage.getLockPatternFilename(1));
315 assertEquals("/data/system/users/1/gatekeeper.password.key", storage.getLockPasswordFilename(1));
Adrian Roose5424992014-11-07 21:47:17 +0100316 }
317
318 public void testFileLocation_ProfileToSecondary() {
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000319 LockSettingsStorage storage = new LockSettingsStorage(getContext());
Adrian Roose5424992014-11-07 21:47:17 +0100320
Rubin Xu1de89b32016-11-30 20:03:13 +0000321 assertEquals("/data/system/users/2/gatekeeper.pattern.key", storage.getLockPatternFilename(2));
322 assertEquals("/data/system/users/2/gatekeeper.password.key", storage.getLockPasswordFilename(2));
Adrian Roose5424992014-11-07 21:47:17 +0100323 }
324
325 public void testFileLocation_ProfileToOwner() {
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000326 LockSettingsStorage storage = new LockSettingsStorage(getContext());
Adrian Roose5424992014-11-07 21:47:17 +0100327
Rubin Xu1de89b32016-11-30 20:03:13 +0000328 assertEquals("/data/system/users/3/gatekeeper.pattern.key", storage.getLockPatternFilename(3));
329 assertEquals("/data/system/users/3/gatekeeper.password.key", storage.getLockPasswordFilename(3));
Adrian Roose5424992014-11-07 21:47:17 +0100330 }
331
Rubin Xu3bf722a2016-12-15 16:07:38 +0000332 public void testSyntheticPasswordState() {
333 final byte[] data = {1,2,3,4};
334 mStorage.writeSyntheticPasswordState(10, 1234L, "state", data);
335 assertArrayEquals(data, mStorage.readSyntheticPasswordState(10, 1234L, "state"));
336 assertEquals(null, mStorage.readSyntheticPasswordState(0, 1234L, "state"));
337
338 mStorage.deleteSyntheticPasswordState(10, 1234L, "state", true);
339 assertEquals(null, mStorage.readSyntheticPasswordState(10, 1234L, "state"));
340 }
341
Adrian Roose5424992014-11-07 21:47:17 +0100342 private static void assertArrayEquals(byte[] expected, byte[] actual) {
343 if (!Arrays.equals(expected, actual)) {
344 fail("expected:<" + Arrays.toString(expected) +
345 "> but was:<" + Arrays.toString(actual) + ">");
346 }
347 }
Rubin Xu1de89b32016-11-30 20:03:13 +0000348
349 private void writePasswordBytes(byte[] password, int userId) {
350 mStorage.writeCredentialHash(CredentialHash.create(
351 password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD), userId);
352 }
353
354 private void writePatternBytes(byte[] pattern, int userId) {
355 mStorage.writeCredentialHash(CredentialHash.create(
356 pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN), userId);
357 }
358
359 private void assertPasswordBytes(byte[] password, int userId) {
360 CredentialHash cred = mStorage.readCredentialHash(userId);
361 assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, cred.type);
362 assertArrayEquals(password, cred.hash);
363 }
364
365 private void assertPatternBytes(byte[] pattern, int userId) {
366 CredentialHash cred = mStorage.readCredentialHash(userId);
367 assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PATTERN, cred.type);
368 assertArrayEquals(pattern, cred.hash);
369 }
Adrian Roose5424992014-11-07 21:47:17 +0100370}