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