blob: 46779048e9dbb7be187fd0dea4ca1c44cf27d386 [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;
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;
31import android.test.AndroidTestCase;
32
Rubin Xu1de89b32016-11-30 20:03:13 +000033import com.android.internal.widget.LockPatternUtils;
34import com.android.server.LockSettingsStorage.CredentialHash;
Adrian Roose5424992014-11-07 21:47:17 +010035import java.io.File;
36import java.util.ArrayList;
37import java.util.Arrays;
38import java.util.List;
39import java.util.concurrent.CountDownLatch;
40
Rubin Xu1de89b32016-11-30 20:03:13 +000041/**
42 * runtest frameworks-services -c com.android.server.LockSettingsStorageTests
43 */
Adrian Roose5424992014-11-07 21:47:17 +010044public class LockSettingsStorageTests extends AndroidTestCase {
Rubin Xu1de89b32016-11-30 20:03:13 +000045 private final byte[] PASSWORD_0 = "thepassword0".getBytes();
46 private final byte[] PASSWORD_1 = "password1".getBytes();
47 private final byte[] PATTERN_0 = "123654".getBytes();
48 private final byte[] PATTERN_1 = "147852369".getBytes();
49
Adrian Roose5424992014-11-07 21:47:17 +010050 LockSettingsStorage mStorage;
51 File mStorageDir;
52
53 private File mDb;
54
55 @Override
56 protected void setUp() throws Exception {
57 super.setUp();
58 mStorageDir = new File(getContext().getFilesDir(), "locksettings");
59 mDb = getContext().getDatabasePath("locksettings.db");
60
61 assertTrue(mStorageDir.exists() || mStorageDir.mkdirs());
62 assertTrue(FileUtils.deleteContents(mStorageDir));
63 assertTrue(!mDb.exists() || mDb.delete());
64
Rubin Xu1de89b32016-11-30 20:03:13 +000065 final UserManager mockUserManager = mock(UserManager.class);
66 // User 2 is a profile of user 1.
67 when(mockUserManager.getProfileParent(eq(2))).thenReturn(new UserInfo(1, "name", 0));
68 // User 3 is a profile of user 0.
69 when(mockUserManager.getProfileParent(eq(3))).thenReturn(new UserInfo(0, "name", 0));
Adrian Roose5424992014-11-07 21:47:17 +010070
Rubin Xu0cbc19e2016-12-09 14:00:21 +000071 MockLockSettingsContext context = new MockLockSettingsContext(getContext(), mockUserManager,
Rubin Xu8b30ec32017-03-05 00:47:09 +000072 mock(NotificationManager.class), mock(DevicePolicyManager.class));
Rubin Xu0cbc19e2016-12-09 14:00:21 +000073 mStorage = new LockSettingsStorageTestable(context,
74 new File(getContext().getFilesDir(), "locksettings"));
75 mStorage.setDatabaseOnCreateCallback(new LockSettingsStorage.Callback() {
76 @Override
77 public void initialize(SQLiteDatabase db) {
78 mStorage.writeKeyValue(db, "initializedKey", "initialValue", 0);
79 }
80 });
Adrian Roose5424992014-11-07 21:47:17 +010081 }
82
83 @Override
84 protected void tearDown() throws Exception {
85 super.tearDown();
86 mStorage.closeDatabase();
87 }
88
89 public void testKeyValue_InitializeWorked() {
90 assertEquals("initialValue", mStorage.readKeyValue("initializedKey", "default", 0));
91 mStorage.clearCache();
92 assertEquals("initialValue", mStorage.readKeyValue("initializedKey", "default", 0));
93 }
94
95 public void testKeyValue_WriteThenRead() {
96 mStorage.writeKeyValue("key", "value", 0);
97 assertEquals("value", mStorage.readKeyValue("key", "default", 0));
98 mStorage.clearCache();
99 assertEquals("value", mStorage.readKeyValue("key", "default", 0));
100 }
101
102 public void testKeyValue_DefaultValue() {
103 assertEquals("default", mStorage.readKeyValue("unititialized key", "default", 0));
104 assertEquals("default2", mStorage.readKeyValue("unititialized key", "default2", 0));
105 }
106
107 public void testKeyValue_Concurrency() {
108 final Object monitor = new Object();
109 List<Thread> threads = new ArrayList<>();
110 for (int i = 0; i < 100; i++) {
111 final int threadId = i;
112 threads.add(new Thread() {
113 @Override
114 public void run() {
115 synchronized (monitor) {
116 try {
117 monitor.wait();
118 } catch (InterruptedException e) {
119 return;
120 }
121 mStorage.writeKeyValue("key", "1 from thread " + threadId, 0);
122 mStorage.readKeyValue("key", "default", 0);
123 mStorage.writeKeyValue("key", "2 from thread " + threadId, 0);
124 mStorage.readKeyValue("key", "default", 0);
125 mStorage.writeKeyValue("key", "3 from thread " + threadId, 0);
126 mStorage.readKeyValue("key", "default", 0);
127 mStorage.writeKeyValue("key", "4 from thread " + threadId, 0);
128 mStorage.readKeyValue("key", "default", 0);
129 mStorage.writeKeyValue("key", "5 from thread " + threadId, 0);
130 mStorage.readKeyValue("key", "default", 0);
131 }
132 }
133 });
134 threads.get(i).start();
135 }
136 mStorage.writeKeyValue("key", "initalValue", 0);
137 synchronized (monitor) {
138 monitor.notifyAll();
139 }
140 for (int i = 0; i < threads.size(); i++) {
141 try {
142 threads.get(i).join();
143 } catch (InterruptedException e) {
144 }
145 }
146 assertEquals('5', mStorage.readKeyValue("key", "default", 0).charAt(0));
147 mStorage.clearCache();
148 assertEquals('5', mStorage.readKeyValue("key", "default", 0).charAt(0));
149 }
150
151 public void testKeyValue_CacheStarvedWriter() {
152 final CountDownLatch latch = new CountDownLatch(1);
153 List<Thread> threads = new ArrayList<>();
154 for (int i = 0; i < 100; i++) {
155 final int threadId = i;
156 threads.add(new Thread() {
157 @Override
158 public void run() {
159 try {
160 latch.await();
161 } catch (InterruptedException e) {
162 return;
163 }
164 if (threadId == 50) {
165 mStorage.writeKeyValue("starvedWriterKey", "value", 0);
166 } else {
167 mStorage.readKeyValue("starvedWriterKey", "default", 0);
168 }
169 }
170 });
171 threads.get(i).start();
172 }
173 latch.countDown();
174 for (int i = 0; i < threads.size(); i++) {
175 try {
176 threads.get(i).join();
177 } catch (InterruptedException e) {
178 }
179 }
180 String cached = mStorage.readKeyValue("key", "default", 0);
181 mStorage.clearCache();
182 String storage = mStorage.readKeyValue("key", "default", 0);
183 assertEquals("Cached value didn't match stored value", storage, cached);
184 }
185
186 public void testRemoveUser() {
187 mStorage.writeKeyValue("key", "value", 0);
Rubin Xu1de89b32016-11-30 20:03:13 +0000188 writePasswordBytes(PASSWORD_0, 0);
189 writePatternBytes(PATTERN_0, 0);
Adrian Roose5424992014-11-07 21:47:17 +0100190
191 mStorage.writeKeyValue("key", "value", 1);
Rubin Xu1de89b32016-11-30 20:03:13 +0000192 writePasswordBytes(PASSWORD_1, 1);
193 writePatternBytes(PATTERN_1, 1);
Adrian Roose5424992014-11-07 21:47:17 +0100194
195 mStorage.removeUser(0);
196
197 assertEquals("value", mStorage.readKeyValue("key", "default", 1));
198 assertEquals("default", mStorage.readKeyValue("key", "default", 0));
Rubin Xu1de89b32016-11-30 20:03:13 +0000199 assertEquals(LockPatternUtils.CREDENTIAL_TYPE_NONE, mStorage.readCredentialHash(0).type);
200 assertPatternBytes(PATTERN_1, 1);
Adrian Roose5424992014-11-07 21:47:17 +0100201 }
202
Rubin Xu1de89b32016-11-30 20:03:13 +0000203 public void testCredential_Default() {
204 assertEquals(mStorage.readCredentialHash(0).type, LockPatternUtils.CREDENTIAL_TYPE_NONE);
Adrian Roose5424992014-11-07 21:47:17 +0100205 }
206
207 public void testPassword_Write() {
Rubin Xu1de89b32016-11-30 20:03:13 +0000208 writePasswordBytes(PASSWORD_0, 0);
Adrian Roose5424992014-11-07 21:47:17 +0100209
Rubin Xu1de89b32016-11-30 20:03:13 +0000210 assertPasswordBytes(PASSWORD_0, 0);
Adrian Roose5424992014-11-07 21:47:17 +0100211 mStorage.clearCache();
Rubin Xu1de89b32016-11-30 20:03:13 +0000212 assertPasswordBytes(PASSWORD_0, 0);
Adrian Roose5424992014-11-07 21:47:17 +0100213 }
214
215 public void testPassword_WriteProfileWritesParent() {
Rubin Xu1de89b32016-11-30 20:03:13 +0000216 writePasswordBytes(PASSWORD_0, 1);
217 writePasswordBytes(PASSWORD_1, 2);
Adrian Roose5424992014-11-07 21:47:17 +0100218
Rubin Xu1de89b32016-11-30 20:03:13 +0000219 assertPasswordBytes(PASSWORD_0, 1);
220 assertPasswordBytes(PASSWORD_1, 2);
Adrian Roose5424992014-11-07 21:47:17 +0100221 mStorage.clearCache();
Rubin Xu1de89b32016-11-30 20:03:13 +0000222 assertPasswordBytes(PASSWORD_0, 1);
223 assertPasswordBytes(PASSWORD_1, 2);
Adrian Roose5424992014-11-07 21:47:17 +0100224 }
225
Ricky Waia46b40f2016-03-31 16:48:29 +0100226 public void testLockType_WriteProfileWritesParent() {
Rubin Xu1de89b32016-11-30 20:03:13 +0000227 writePasswordBytes(PASSWORD_0, 10);
228 writePatternBytes(PATTERN_0, 20);
Ricky Waia46b40f2016-03-31 16:48:29 +0100229
Rubin Xu1de89b32016-11-30 20:03:13 +0000230 assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
231 mStorage.readCredentialHash(10).type);
232 assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
233 mStorage.readCredentialHash(20).type);
Ricky Waia46b40f2016-03-31 16:48:29 +0100234 mStorage.clearCache();
Rubin Xu1de89b32016-11-30 20:03:13 +0000235 assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
236 mStorage.readCredentialHash(10).type);
237 assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
238 mStorage.readCredentialHash(20).type);
239 }
240
241 public void testPassword_WriteParentWritesProfile() {
242 writePasswordBytes(PASSWORD_0, 2);
243 writePasswordBytes(PASSWORD_1, 1);
244
245 assertPasswordBytes(PASSWORD_1, 1);
246 assertPasswordBytes(PASSWORD_0, 2);
247 mStorage.clearCache();
248 assertPasswordBytes(PASSWORD_1, 1);
249 assertPasswordBytes(PASSWORD_0, 2);
Ricky Waia46b40f2016-03-31 16:48:29 +0100250 }
251
252 public void testProfileLock_ReadWriteChildProfileLock() {
253 assertFalse(mStorage.hasChildProfileLock(20));
Rubin Xu1de89b32016-11-30 20:03:13 +0000254 mStorage.writeChildProfileLock(20, PASSWORD_0);
255 assertArrayEquals(PASSWORD_0, mStorage.readChildProfileLock(20));
Ricky Waia46b40f2016-03-31 16:48:29 +0100256 assertTrue(mStorage.hasChildProfileLock(20));
257 mStorage.clearCache();
Rubin Xu1de89b32016-11-30 20:03:13 +0000258 assertArrayEquals(PASSWORD_0, mStorage.readChildProfileLock(20));
Ricky Waia46b40f2016-03-31 16:48:29 +0100259 assertTrue(mStorage.hasChildProfileLock(20));
260 }
261
Adrian Roose5424992014-11-07 21:47:17 +0100262 public void testPattern_Write() {
Rubin Xu1de89b32016-11-30 20:03:13 +0000263 writePatternBytes(PATTERN_0, 0);
Adrian Roose5424992014-11-07 21:47:17 +0100264
Rubin Xu1de89b32016-11-30 20:03:13 +0000265 assertPatternBytes(PATTERN_0, 0);
Adrian Roose5424992014-11-07 21:47:17 +0100266 mStorage.clearCache();
Rubin Xu1de89b32016-11-30 20:03:13 +0000267 assertPatternBytes(PATTERN_0, 0);
Adrian Roose5424992014-11-07 21:47:17 +0100268 }
269
270 public void testPattern_WriteProfileWritesParent() {
Rubin Xu1de89b32016-11-30 20:03:13 +0000271 writePatternBytes(PATTERN_0, 1);
272 writePatternBytes(PATTERN_1, 2);
Adrian Roose5424992014-11-07 21:47:17 +0100273
Rubin Xu1de89b32016-11-30 20:03:13 +0000274 assertPatternBytes(PATTERN_0, 1);
275 assertPatternBytes(PATTERN_1, 2);
Adrian Roose5424992014-11-07 21:47:17 +0100276 mStorage.clearCache();
Rubin Xu1de89b32016-11-30 20:03:13 +0000277 assertPatternBytes(PATTERN_0, 1);
278 assertPatternBytes(PATTERN_1, 2);
Adrian Roose5424992014-11-07 21:47:17 +0100279 }
280
281 public void testPattern_WriteParentWritesProfile() {
Rubin Xu1de89b32016-11-30 20:03:13 +0000282 writePatternBytes(PATTERN_1, 2);
283 writePatternBytes(PATTERN_0, 1);
Adrian Roose5424992014-11-07 21:47:17 +0100284
Rubin Xu1de89b32016-11-30 20:03:13 +0000285 assertPatternBytes(PATTERN_0, 1);
286 assertPatternBytes(PATTERN_1, 2);
Adrian Roose5424992014-11-07 21:47:17 +0100287 mStorage.clearCache();
Rubin Xu1de89b32016-11-30 20:03:13 +0000288 assertPatternBytes(PATTERN_0, 1);
289 assertPatternBytes(PATTERN_1, 2);
Adrian Roose5424992014-11-07 21:47:17 +0100290 }
291
292 public void testPrefetch() {
293 mStorage.writeKeyValue("key", "toBeFetched", 0);
Rubin Xu1de89b32016-11-30 20:03:13 +0000294 writePatternBytes(PATTERN_0, 0);
Adrian Roose5424992014-11-07 21:47:17 +0100295
296 mStorage.clearCache();
297 mStorage.prefetchUser(0);
298
299 assertEquals("toBeFetched", mStorage.readKeyValue("key", "default", 0));
Rubin Xu1de89b32016-11-30 20:03:13 +0000300 assertPatternBytes(PATTERN_0, 0);
Adrian Roose5424992014-11-07 21:47:17 +0100301 }
302
303 public void testFileLocation_Owner() {
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000304 LockSettingsStorage storage = new LockSettingsStorage(getContext());
Adrian Roose5424992014-11-07 21:47:17 +0100305
Rubin Xu1de89b32016-11-30 20:03:13 +0000306 assertEquals("/data/system/gesture.key", storage.getLegacyLockPatternFilename(0));
307 assertEquals("/data/system/password.key", storage.getLegacyLockPasswordFilename(0));
308 assertEquals("/data/system/gatekeeper.pattern.key", storage.getLockPatternFilename(0));
309 assertEquals("/data/system/gatekeeper.password.key", storage.getLockPasswordFilename(0));
Adrian Roose5424992014-11-07 21:47:17 +0100310 }
311
312 public void testFileLocation_SecondaryUser() {
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000313 LockSettingsStorage storage = new LockSettingsStorage(getContext());
Adrian Roose5424992014-11-07 21:47:17 +0100314
Rubin Xu1de89b32016-11-30 20:03:13 +0000315 assertEquals("/data/system/users/1/gatekeeper.pattern.key", storage.getLockPatternFilename(1));
316 assertEquals("/data/system/users/1/gatekeeper.password.key", storage.getLockPasswordFilename(1));
Adrian Roose5424992014-11-07 21:47:17 +0100317 }
318
319 public void testFileLocation_ProfileToSecondary() {
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000320 LockSettingsStorage storage = new LockSettingsStorage(getContext());
Adrian Roose5424992014-11-07 21:47:17 +0100321
Rubin Xu1de89b32016-11-30 20:03:13 +0000322 assertEquals("/data/system/users/2/gatekeeper.pattern.key", storage.getLockPatternFilename(2));
323 assertEquals("/data/system/users/2/gatekeeper.password.key", storage.getLockPasswordFilename(2));
Adrian Roose5424992014-11-07 21:47:17 +0100324 }
325
326 public void testFileLocation_ProfileToOwner() {
Rubin Xu0cbc19e2016-12-09 14:00:21 +0000327 LockSettingsStorage storage = new LockSettingsStorage(getContext());
Adrian Roose5424992014-11-07 21:47:17 +0100328
Rubin Xu1de89b32016-11-30 20:03:13 +0000329 assertEquals("/data/system/users/3/gatekeeper.pattern.key", storage.getLockPatternFilename(3));
330 assertEquals("/data/system/users/3/gatekeeper.password.key", storage.getLockPasswordFilename(3));
Adrian Roose5424992014-11-07 21:47:17 +0100331 }
332
Rubin Xu3bf722a2016-12-15 16:07:38 +0000333 public void testSyntheticPasswordState() {
334 final byte[] data = {1,2,3,4};
335 mStorage.writeSyntheticPasswordState(10, 1234L, "state", data);
336 assertArrayEquals(data, mStorage.readSyntheticPasswordState(10, 1234L, "state"));
337 assertEquals(null, mStorage.readSyntheticPasswordState(0, 1234L, "state"));
338
339 mStorage.deleteSyntheticPasswordState(10, 1234L, "state", true);
340 assertEquals(null, mStorage.readSyntheticPasswordState(10, 1234L, "state"));
341 }
342
Adrian Roose5424992014-11-07 21:47:17 +0100343 private static void assertArrayEquals(byte[] expected, byte[] actual) {
344 if (!Arrays.equals(expected, actual)) {
345 fail("expected:<" + Arrays.toString(expected) +
346 "> but was:<" + Arrays.toString(actual) + ">");
347 }
348 }
Rubin Xu1de89b32016-11-30 20:03:13 +0000349
350 private void writePasswordBytes(byte[] password, int userId) {
351 mStorage.writeCredentialHash(CredentialHash.create(
352 password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD), userId);
353 }
354
355 private void writePatternBytes(byte[] pattern, int userId) {
356 mStorage.writeCredentialHash(CredentialHash.create(
357 pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN), userId);
358 }
359
360 private void assertPasswordBytes(byte[] password, int userId) {
361 CredentialHash cred = mStorage.readCredentialHash(userId);
362 assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, cred.type);
363 assertArrayEquals(password, cred.hash);
364 }
365
366 private void assertPatternBytes(byte[] pattern, int userId) {
367 CredentialHash cred = mStorage.readCredentialHash(userId);
368 assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PATTERN, cred.type);
369 assertArrayEquals(pattern, cred.hash);
370 }
Adrian Roose5424992014-11-07 21:47:17 +0100371}