LockSettingsStorageTests.java revision e542499a304f067372d85722e11a74b4e56b0bd7
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 android.content.Context;
20import android.content.ContextWrapper;
21import android.content.pm.UserInfo;
22import android.database.sqlite.SQLiteDatabase;
23import android.os.FileUtils;
24import android.os.UserManager;
25import android.test.AndroidTestCase;
26
27import java.io.File;
28import java.util.ArrayList;
29import java.util.Arrays;
30import java.util.List;
31import java.util.concurrent.CountDownLatch;
32
33public class LockSettingsStorageTests extends AndroidTestCase {
34    LockSettingsStorage mStorage;
35    File mStorageDir;
36
37    private File mDb;
38
39    @Override
40    protected void setUp() throws Exception {
41        super.setUp();
42        mStorageDir = new File(getContext().getFilesDir(), "locksettings");
43        mDb = getContext().getDatabasePath("locksettings.db");
44
45        assertTrue(mStorageDir.exists() || mStorageDir.mkdirs());
46        assertTrue(FileUtils.deleteContents(mStorageDir));
47        assertTrue(!mDb.exists() || mDb.delete());
48
49        final Context ctx = getContext();
50        setContext(new ContextWrapper(ctx) {
51            @Override
52            public Object getSystemService(String name) {
53                if (USER_SERVICE.equals(name)) {
54                    return new UserManager(ctx, null) {
55                        @Override
56                        public UserInfo getProfileParent(int userHandle) {
57                            if (userHandle == 2) {
58                                // User 2 is a profile of user 1.
59                                return new UserInfo(1, "name", 0);
60                            }
61                            if (userHandle == 3) {
62                                // User 3 is a profile of user 0.
63                                return new UserInfo(0, "name", 0);
64                            }
65                            return null;
66                        }
67                    };
68                }
69                return super.getSystemService(name);
70            }
71        });
72
73        mStorage = new LockSettingsStorage(getContext(), new LockSettingsStorage.Callback() {
74            @Override
75            public void initialize(SQLiteDatabase db) {
76                mStorage.writeKeyValue(db, "initializedKey", "initialValue", 0);
77            }
78        }) {
79            @Override
80            String getLockPatternFilename(int userId) {
81                return new File(mStorageDir,
82                        super.getLockPatternFilename(userId).replace('/', '-')).getAbsolutePath();
83            }
84
85            @Override
86            String getLockPasswordFilename(int userId) {
87                return new File(mStorageDir,
88                        super.getLockPasswordFilename(userId).replace('/', '-')).getAbsolutePath();
89            }
90        };
91    }
92
93    @Override
94    protected void tearDown() throws Exception {
95        super.tearDown();
96        mStorage.closeDatabase();
97    }
98
99    public void testKeyValue_InitializeWorked() {
100        assertEquals("initialValue", mStorage.readKeyValue("initializedKey", "default", 0));
101        mStorage.clearCache();
102        assertEquals("initialValue", mStorage.readKeyValue("initializedKey", "default", 0));
103    }
104
105    public void testKeyValue_WriteThenRead() {
106        mStorage.writeKeyValue("key", "value", 0);
107        assertEquals("value", mStorage.readKeyValue("key", "default", 0));
108        mStorage.clearCache();
109        assertEquals("value", mStorage.readKeyValue("key", "default", 0));
110    }
111
112    public void testKeyValue_DefaultValue() {
113        assertEquals("default", mStorage.readKeyValue("unititialized key", "default", 0));
114        assertEquals("default2", mStorage.readKeyValue("unititialized key", "default2", 0));
115    }
116
117    public void testKeyValue_Concurrency() {
118        final Object monitor = new Object();
119        List<Thread> threads = new ArrayList<>();
120        for (int i = 0; i < 100; i++) {
121            final int threadId = i;
122            threads.add(new Thread() {
123                @Override
124                public void run() {
125                    synchronized (monitor) {
126                        try {
127                            monitor.wait();
128                        } catch (InterruptedException e) {
129                            return;
130                        }
131                        mStorage.writeKeyValue("key", "1 from thread " + threadId, 0);
132                        mStorage.readKeyValue("key", "default", 0);
133                        mStorage.writeKeyValue("key", "2 from thread " + threadId, 0);
134                        mStorage.readKeyValue("key", "default", 0);
135                        mStorage.writeKeyValue("key", "3 from thread " + threadId, 0);
136                        mStorage.readKeyValue("key", "default", 0);
137                        mStorage.writeKeyValue("key", "4 from thread " + threadId, 0);
138                        mStorage.readKeyValue("key", "default", 0);
139                        mStorage.writeKeyValue("key", "5 from thread " + threadId, 0);
140                        mStorage.readKeyValue("key", "default", 0);
141                    }
142                }
143            });
144            threads.get(i).start();
145        }
146        mStorage.writeKeyValue("key", "initalValue", 0);
147        synchronized (monitor) {
148            monitor.notifyAll();
149        }
150        for (int i = 0; i < threads.size(); i++) {
151            try {
152                threads.get(i).join();
153            } catch (InterruptedException e) {
154            }
155        }
156        assertEquals('5', mStorage.readKeyValue("key", "default", 0).charAt(0));
157        mStorage.clearCache();
158        assertEquals('5', mStorage.readKeyValue("key", "default", 0).charAt(0));
159    }
160
161    public void testKeyValue_CacheStarvedWriter() {
162        final CountDownLatch latch = new CountDownLatch(1);
163        List<Thread> threads = new ArrayList<>();
164        for (int i = 0; i < 100; i++) {
165            final int threadId = i;
166            threads.add(new Thread() {
167                @Override
168                public void run() {
169                    try {
170                        latch.await();
171                    } catch (InterruptedException e) {
172                        return;
173                    }
174                    if (threadId == 50) {
175                        mStorage.writeKeyValue("starvedWriterKey", "value", 0);
176                    } else {
177                        mStorage.readKeyValue("starvedWriterKey", "default", 0);
178                    }
179                }
180            });
181            threads.get(i).start();
182        }
183        latch.countDown();
184        for (int i = 0; i < threads.size(); i++) {
185            try {
186                threads.get(i).join();
187            } catch (InterruptedException e) {
188            }
189        }
190        String cached = mStorage.readKeyValue("key", "default", 0);
191        mStorage.clearCache();
192        String storage = mStorage.readKeyValue("key", "default", 0);
193        assertEquals("Cached value didn't match stored value", storage, cached);
194    }
195
196    public void testRemoveUser() {
197        mStorage.writeKeyValue("key", "value", 0);
198        mStorage.writePasswordHash(new byte[]{1}, 0);
199        mStorage.writePatternHash(new byte[]{2}, 0);
200
201        mStorage.writeKeyValue("key", "value", 1);
202        mStorage.writePasswordHash(new byte[]{1}, 1);
203        mStorage.writePatternHash(new byte[]{2}, 1);
204
205        mStorage.removeUser(0);
206
207        assertEquals("value", mStorage.readKeyValue("key", "default", 1));
208        assertEquals("default", mStorage.readKeyValue("key", "default", 0));
209        assertNotNull(mStorage.readPasswordHash(1));
210        assertNull(mStorage.readPasswordHash(0));
211        assertNotNull(mStorage.readPatternHash(1));
212        assertNull(mStorage.readPatternHash(0));
213    }
214
215    public void testPassword_Default() {
216        assertNull(mStorage.readPasswordHash(0));
217    }
218
219    public void testPassword_Write() {
220        mStorage.writePasswordHash("thepassword".getBytes(), 0);
221
222        assertArrayEquals("thepassword".getBytes(), mStorage.readPasswordHash(0));
223        mStorage.clearCache();
224        assertArrayEquals("thepassword".getBytes(), mStorage.readPasswordHash(0));
225    }
226
227    public void testPassword_WriteProfileWritesParent() {
228        mStorage.writePasswordHash("parentpasswordd".getBytes(), 1);
229        mStorage.writePasswordHash("profilepassword".getBytes(), 2);
230
231        assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(1));
232        assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(2));
233        mStorage.clearCache();
234        assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(1));
235        assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(2));
236    }
237
238    public void testPassword_WriteParentWritesProfile() {
239        mStorage.writePasswordHash("profilepassword".getBytes(), 2);
240        mStorage.writePasswordHash("parentpasswordd".getBytes(), 1);
241
242        assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(1));
243        assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(2));
244        mStorage.clearCache();
245        assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(1));
246        assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(2));
247    }
248
249    public void testPattern_Default() {
250        assertNull(mStorage.readPasswordHash(0));
251    }
252
253    public void testPattern_Write() {
254        mStorage.writePatternHash("thepattern".getBytes(), 0);
255
256        assertArrayEquals("thepattern".getBytes(), mStorage.readPatternHash(0));
257        mStorage.clearCache();
258        assertArrayEquals("thepattern".getBytes(), mStorage.readPatternHash(0));
259    }
260
261    public void testPattern_WriteProfileWritesParent() {
262        mStorage.writePatternHash("parentpatternn".getBytes(), 1);
263        mStorage.writePatternHash("profilepattern".getBytes(), 2);
264
265        assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(1));
266        assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(2));
267        mStorage.clearCache();
268        assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(1));
269        assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(2));
270    }
271
272    public void testPattern_WriteParentWritesProfile() {
273        mStorage.writePatternHash("profilepattern".getBytes(), 2);
274        mStorage.writePatternHash("parentpatternn".getBytes(), 1);
275
276        assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(1));
277        assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(2));
278        mStorage.clearCache();
279        assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(1));
280        assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(2));
281    }
282
283    public void testPrefetch() {
284        mStorage.writeKeyValue("key", "toBeFetched", 0);
285        mStorage.writePatternHash("pattern".getBytes(), 0);
286        mStorage.writePasswordHash("password".getBytes(), 0);
287
288        mStorage.clearCache();
289        mStorage.prefetchUser(0);
290
291        assertEquals("toBeFetched", mStorage.readKeyValue("key", "default", 0));
292        assertArrayEquals("pattern".getBytes(), mStorage.readPatternHash(0));
293        assertArrayEquals("password".getBytes(), mStorage.readPasswordHash(0));
294    }
295
296    public void testFileLocation_Owner() {
297        LockSettingsStorage storage = new LockSettingsStorage(getContext(), null);
298
299        assertEquals("/data/system/gesture.key", storage.getLockPatternFilename(0));
300        assertEquals("/data/system/password.key", storage.getLockPasswordFilename(0));
301    }
302
303    public void testFileLocation_SecondaryUser() {
304        LockSettingsStorage storage = new LockSettingsStorage(getContext(), null);
305
306        assertEquals("/data/system/users/1/gesture.key", storage.getLockPatternFilename(1));
307        assertEquals("/data/system/users/1/password.key", storage.getLockPasswordFilename(1));
308    }
309
310    public void testFileLocation_ProfileToSecondary() {
311        LockSettingsStorage storage = new LockSettingsStorage(getContext(), null);
312
313        assertEquals("/data/system/users/1/gesture.key", storage.getLockPatternFilename(2));
314        assertEquals("/data/system/users/1/password.key", storage.getLockPasswordFilename(2));
315    }
316
317    public void testFileLocation_ProfileToOwner() {
318        LockSettingsStorage storage = new LockSettingsStorage(getContext(), null);
319
320        assertEquals("/data/system/gesture.key", storage.getLockPatternFilename(3));
321        assertEquals("/data/system/password.key", storage.getLockPasswordFilename(3));
322    }
323
324    private static void assertArrayEquals(byte[] expected, byte[] actual) {
325        if (!Arrays.equals(expected, actual)) {
326            fail("expected:<" + Arrays.toString(expected) +
327                    "> but was:<" + Arrays.toString(actual) + ">");
328        }
329    }
330}
331