LockSettingsStorageTests.java revision ee67b61bb08ab09be413f181f948f6359f4c256d
1/*
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
19import static org.mockito.Matchers.eq;
20import static org.mockito.Mockito.mock;
21import static org.mockito.Mockito.when;
22
23import android.app.NotificationManager;
24import android.app.admin.DevicePolicyManager;
25import 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.os.storage.StorageManager;
32import android.test.AndroidTestCase;
33
34import com.android.internal.widget.LockPatternUtils;
35import com.android.server.LockSettingsStorage.CredentialHash;
36import java.io.File;
37import java.util.ArrayList;
38import java.util.Arrays;
39import java.util.List;
40import java.util.concurrent.CountDownLatch;
41
42/**
43 * runtest frameworks-services -c com.android.server.LockSettingsStorageTests
44 */
45public class LockSettingsStorageTests extends AndroidTestCase {
46    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
51    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
66        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));
71
72        MockLockSettingsContext context = new MockLockSettingsContext(getContext(), mockUserManager,
73                mock(NotificationManager.class), mock(DevicePolicyManager.class),
74                mock(StorageManager.class));
75        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                });
83    }
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);
190        writePasswordBytes(PASSWORD_0, 0);
191        writePatternBytes(PATTERN_0, 0);
192
193        mStorage.writeKeyValue("key", "value", 1);
194        writePasswordBytes(PASSWORD_1, 1);
195        writePatternBytes(PATTERN_1, 1);
196
197        mStorage.removeUser(0);
198
199        assertEquals("value", mStorage.readKeyValue("key", "default", 1));
200        assertEquals("default", mStorage.readKeyValue("key", "default", 0));
201        assertEquals(LockPatternUtils.CREDENTIAL_TYPE_NONE, mStorage.readCredentialHash(0).type);
202        assertPatternBytes(PATTERN_1, 1);
203    }
204
205    public void testCredential_Default() {
206        assertEquals(mStorage.readCredentialHash(0).type, LockPatternUtils.CREDENTIAL_TYPE_NONE);
207    }
208
209    public void testPassword_Write() {
210        writePasswordBytes(PASSWORD_0, 0);
211
212        assertPasswordBytes(PASSWORD_0, 0);
213        mStorage.clearCache();
214        assertPasswordBytes(PASSWORD_0, 0);
215    }
216
217    public void testPassword_WriteProfileWritesParent() {
218        writePasswordBytes(PASSWORD_0, 1);
219        writePasswordBytes(PASSWORD_1, 2);
220
221        assertPasswordBytes(PASSWORD_0, 1);
222        assertPasswordBytes(PASSWORD_1, 2);
223        mStorage.clearCache();
224        assertPasswordBytes(PASSWORD_0, 1);
225        assertPasswordBytes(PASSWORD_1, 2);
226    }
227
228    public void testLockType_WriteProfileWritesParent() {
229        writePasswordBytes(PASSWORD_0, 10);
230        writePatternBytes(PATTERN_0, 20);
231
232        assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
233                mStorage.readCredentialHash(10).type);
234        assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
235                mStorage.readCredentialHash(20).type);
236        mStorage.clearCache();
237        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);
252    }
253
254    public void testProfileLock_ReadWriteChildProfileLock() {
255        assertFalse(mStorage.hasChildProfileLock(20));
256        mStorage.writeChildProfileLock(20, PASSWORD_0);
257        assertArrayEquals(PASSWORD_0, mStorage.readChildProfileLock(20));
258        assertTrue(mStorage.hasChildProfileLock(20));
259        mStorage.clearCache();
260        assertArrayEquals(PASSWORD_0, mStorage.readChildProfileLock(20));
261        assertTrue(mStorage.hasChildProfileLock(20));
262    }
263
264    public void testPattern_Write() {
265        writePatternBytes(PATTERN_0, 0);
266
267        assertPatternBytes(PATTERN_0, 0);
268        mStorage.clearCache();
269        assertPatternBytes(PATTERN_0, 0);
270    }
271
272    public void testPattern_WriteProfileWritesParent() {
273        writePatternBytes(PATTERN_0, 1);
274        writePatternBytes(PATTERN_1, 2);
275
276        assertPatternBytes(PATTERN_0, 1);
277        assertPatternBytes(PATTERN_1, 2);
278        mStorage.clearCache();
279        assertPatternBytes(PATTERN_0, 1);
280        assertPatternBytes(PATTERN_1, 2);
281    }
282
283    public void testPattern_WriteParentWritesProfile() {
284        writePatternBytes(PATTERN_1, 2);
285        writePatternBytes(PATTERN_0, 1);
286
287        assertPatternBytes(PATTERN_0, 1);
288        assertPatternBytes(PATTERN_1, 2);
289        mStorage.clearCache();
290        assertPatternBytes(PATTERN_0, 1);
291        assertPatternBytes(PATTERN_1, 2);
292    }
293
294    public void testPrefetch() {
295        mStorage.writeKeyValue("key", "toBeFetched", 0);
296        writePatternBytes(PATTERN_0, 0);
297
298        mStorage.clearCache();
299        mStorage.prefetchUser(0);
300
301        assertEquals("toBeFetched", mStorage.readKeyValue("key", "default", 0));
302        assertPatternBytes(PATTERN_0, 0);
303    }
304
305    public void testFileLocation_Owner() {
306        LockSettingsStorage storage = new LockSettingsStorage(getContext());
307
308        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));
312    }
313
314    public void testFileLocation_SecondaryUser() {
315        LockSettingsStorage storage = new LockSettingsStorage(getContext());
316
317        assertEquals("/data/system/users/1/gatekeeper.pattern.key", storage.getLockPatternFilename(1));
318        assertEquals("/data/system/users/1/gatekeeper.password.key", storage.getLockPasswordFilename(1));
319    }
320
321    public void testFileLocation_ProfileToSecondary() {
322        LockSettingsStorage storage = new LockSettingsStorage(getContext());
323
324        assertEquals("/data/system/users/2/gatekeeper.pattern.key", storage.getLockPatternFilename(2));
325        assertEquals("/data/system/users/2/gatekeeper.password.key", storage.getLockPasswordFilename(2));
326    }
327
328    public void testFileLocation_ProfileToOwner() {
329        LockSettingsStorage storage = new LockSettingsStorage(getContext());
330
331        assertEquals("/data/system/users/3/gatekeeper.pattern.key", storage.getLockPatternFilename(3));
332        assertEquals("/data/system/users/3/gatekeeper.password.key", storage.getLockPasswordFilename(3));
333    }
334
335    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
341        mStorage.deleteSyntheticPasswordState(10, 1234L, "state");
342        assertEquals(null, mStorage.readSyntheticPasswordState(10, 1234L, "state"));
343    }
344
345    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    }
351
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    }
373}
374