LockSettingsStorageTests.java revision 1de89b3bec2f296763f3ecde9a36ecbca2110f3d
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.content.Context; 24import android.content.ContextWrapper; 25import android.content.pm.UserInfo; 26import android.database.sqlite.SQLiteDatabase; 27import android.os.FileUtils; 28import android.os.UserManager; 29import android.test.AndroidTestCase; 30 31import com.android.internal.widget.LockPatternUtils; 32import com.android.server.LockSettingsStorage.CredentialHash; 33import java.io.File; 34import java.util.ArrayList; 35import java.util.Arrays; 36import java.util.List; 37import java.util.concurrent.CountDownLatch; 38 39/** 40 * runtest frameworks-services -c com.android.server.LockSettingsStorageTests 41 */ 42public class LockSettingsStorageTests extends AndroidTestCase { 43 private final byte[] PASSWORD_0 = "thepassword0".getBytes(); 44 private final byte[] PASSWORD_1 = "password1".getBytes(); 45 private final byte[] PATTERN_0 = "123654".getBytes(); 46 private final byte[] PATTERN_1 = "147852369".getBytes(); 47 48 LockSettingsStorage mStorage; 49 File mStorageDir; 50 51 private File mDb; 52 53 @Override 54 protected void setUp() throws Exception { 55 super.setUp(); 56 mStorageDir = new File(getContext().getFilesDir(), "locksettings"); 57 mDb = getContext().getDatabasePath("locksettings.db"); 58 59 assertTrue(mStorageDir.exists() || mStorageDir.mkdirs()); 60 assertTrue(FileUtils.deleteContents(mStorageDir)); 61 assertTrue(!mDb.exists() || mDb.delete()); 62 63 final Context ctx = getContext(); 64 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)); 69 setContext(new ContextWrapper(ctx) { 70 @Override 71 public Object getSystemService(String name) { 72 if (USER_SERVICE.equals(name)) { 73 return mockUserManager; 74 } 75 return super.getSystemService(name); 76 } 77 }); 78 79 mStorage = new LockSettingsStorage(getContext(), new LockSettingsStorage.Callback() { 80 @Override 81 public void initialize(SQLiteDatabase db) { 82 mStorage.writeKeyValue(db, "initializedKey", "initialValue", 0); 83 } 84 }) { 85 @Override 86 String getLockPatternFilename(int userId) { 87 return new File(mStorageDir, 88 super.getLockPatternFilename(userId).replace('/', '-')).getAbsolutePath(); 89 } 90 91 @Override 92 String getLockPasswordFilename(int userId) { 93 return new File(mStorageDir, 94 super.getLockPasswordFilename(userId).replace('/', '-')).getAbsolutePath(); 95 } 96 97 @Override 98 String getChildProfileLockFile(int userId) { 99 return new File(mStorageDir, 100 super.getChildProfileLockFile(userId).replace('/', '-')).getAbsolutePath(); 101 } 102 }; 103 } 104 105 @Override 106 protected void tearDown() throws Exception { 107 super.tearDown(); 108 mStorage.closeDatabase(); 109 } 110 111 public void testKeyValue_InitializeWorked() { 112 assertEquals("initialValue", mStorage.readKeyValue("initializedKey", "default", 0)); 113 mStorage.clearCache(); 114 assertEquals("initialValue", mStorage.readKeyValue("initializedKey", "default", 0)); 115 } 116 117 public void testKeyValue_WriteThenRead() { 118 mStorage.writeKeyValue("key", "value", 0); 119 assertEquals("value", mStorage.readKeyValue("key", "default", 0)); 120 mStorage.clearCache(); 121 assertEquals("value", mStorage.readKeyValue("key", "default", 0)); 122 } 123 124 public void testKeyValue_DefaultValue() { 125 assertEquals("default", mStorage.readKeyValue("unititialized key", "default", 0)); 126 assertEquals("default2", mStorage.readKeyValue("unititialized key", "default2", 0)); 127 } 128 129 public void testKeyValue_Concurrency() { 130 final Object monitor = new Object(); 131 List<Thread> threads = new ArrayList<>(); 132 for (int i = 0; i < 100; i++) { 133 final int threadId = i; 134 threads.add(new Thread() { 135 @Override 136 public void run() { 137 synchronized (monitor) { 138 try { 139 monitor.wait(); 140 } catch (InterruptedException e) { 141 return; 142 } 143 mStorage.writeKeyValue("key", "1 from thread " + threadId, 0); 144 mStorage.readKeyValue("key", "default", 0); 145 mStorage.writeKeyValue("key", "2 from thread " + threadId, 0); 146 mStorage.readKeyValue("key", "default", 0); 147 mStorage.writeKeyValue("key", "3 from thread " + threadId, 0); 148 mStorage.readKeyValue("key", "default", 0); 149 mStorage.writeKeyValue("key", "4 from thread " + threadId, 0); 150 mStorage.readKeyValue("key", "default", 0); 151 mStorage.writeKeyValue("key", "5 from thread " + threadId, 0); 152 mStorage.readKeyValue("key", "default", 0); 153 } 154 } 155 }); 156 threads.get(i).start(); 157 } 158 mStorage.writeKeyValue("key", "initalValue", 0); 159 synchronized (monitor) { 160 monitor.notifyAll(); 161 } 162 for (int i = 0; i < threads.size(); i++) { 163 try { 164 threads.get(i).join(); 165 } catch (InterruptedException e) { 166 } 167 } 168 assertEquals('5', mStorage.readKeyValue("key", "default", 0).charAt(0)); 169 mStorage.clearCache(); 170 assertEquals('5', mStorage.readKeyValue("key", "default", 0).charAt(0)); 171 } 172 173 public void testKeyValue_CacheStarvedWriter() { 174 final CountDownLatch latch = new CountDownLatch(1); 175 List<Thread> threads = new ArrayList<>(); 176 for (int i = 0; i < 100; i++) { 177 final int threadId = i; 178 threads.add(new Thread() { 179 @Override 180 public void run() { 181 try { 182 latch.await(); 183 } catch (InterruptedException e) { 184 return; 185 } 186 if (threadId == 50) { 187 mStorage.writeKeyValue("starvedWriterKey", "value", 0); 188 } else { 189 mStorage.readKeyValue("starvedWriterKey", "default", 0); 190 } 191 } 192 }); 193 threads.get(i).start(); 194 } 195 latch.countDown(); 196 for (int i = 0; i < threads.size(); i++) { 197 try { 198 threads.get(i).join(); 199 } catch (InterruptedException e) { 200 } 201 } 202 String cached = mStorage.readKeyValue("key", "default", 0); 203 mStorage.clearCache(); 204 String storage = mStorage.readKeyValue("key", "default", 0); 205 assertEquals("Cached value didn't match stored value", storage, cached); 206 } 207 208 public void testRemoveUser() { 209 mStorage.writeKeyValue("key", "value", 0); 210 writePasswordBytes(PASSWORD_0, 0); 211 writePatternBytes(PATTERN_0, 0); 212 213 mStorage.writeKeyValue("key", "value", 1); 214 writePasswordBytes(PASSWORD_1, 1); 215 writePatternBytes(PATTERN_1, 1); 216 217 mStorage.removeUser(0); 218 219 assertEquals("value", mStorage.readKeyValue("key", "default", 1)); 220 assertEquals("default", mStorage.readKeyValue("key", "default", 0)); 221 assertEquals(LockPatternUtils.CREDENTIAL_TYPE_NONE, mStorage.readCredentialHash(0).type); 222 assertPatternBytes(PATTERN_1, 1); 223 } 224 225 public void testCredential_Default() { 226 assertEquals(mStorage.readCredentialHash(0).type, LockPatternUtils.CREDENTIAL_TYPE_NONE); 227 } 228 229 public void testPassword_Write() { 230 writePasswordBytes(PASSWORD_0, 0); 231 232 assertPasswordBytes(PASSWORD_0, 0); 233 mStorage.clearCache(); 234 assertPasswordBytes(PASSWORD_0, 0); 235 } 236 237 public void testPassword_WriteProfileWritesParent() { 238 writePasswordBytes(PASSWORD_0, 1); 239 writePasswordBytes(PASSWORD_1, 2); 240 241 assertPasswordBytes(PASSWORD_0, 1); 242 assertPasswordBytes(PASSWORD_1, 2); 243 mStorage.clearCache(); 244 assertPasswordBytes(PASSWORD_0, 1); 245 assertPasswordBytes(PASSWORD_1, 2); 246 } 247 248 public void testLockType_WriteProfileWritesParent() { 249 writePasswordBytes(PASSWORD_0, 10); 250 writePatternBytes(PATTERN_0, 20); 251 252 assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 253 mStorage.readCredentialHash(10).type); 254 assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 255 mStorage.readCredentialHash(20).type); 256 mStorage.clearCache(); 257 assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 258 mStorage.readCredentialHash(10).type); 259 assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 260 mStorage.readCredentialHash(20).type); 261 } 262 263 public void testPassword_WriteParentWritesProfile() { 264 writePasswordBytes(PASSWORD_0, 2); 265 writePasswordBytes(PASSWORD_1, 1); 266 267 assertPasswordBytes(PASSWORD_1, 1); 268 assertPasswordBytes(PASSWORD_0, 2); 269 mStorage.clearCache(); 270 assertPasswordBytes(PASSWORD_1, 1); 271 assertPasswordBytes(PASSWORD_0, 2); 272 } 273 274 public void testProfileLock_ReadWriteChildProfileLock() { 275 assertFalse(mStorage.hasChildProfileLock(20)); 276 mStorage.writeChildProfileLock(20, PASSWORD_0); 277 assertArrayEquals(PASSWORD_0, mStorage.readChildProfileLock(20)); 278 assertTrue(mStorage.hasChildProfileLock(20)); 279 mStorage.clearCache(); 280 assertArrayEquals(PASSWORD_0, mStorage.readChildProfileLock(20)); 281 assertTrue(mStorage.hasChildProfileLock(20)); 282 } 283 284 public void testPattern_Write() { 285 writePatternBytes(PATTERN_0, 0); 286 287 assertPatternBytes(PATTERN_0, 0); 288 mStorage.clearCache(); 289 assertPatternBytes(PATTERN_0, 0); 290 } 291 292 public void testPattern_WriteProfileWritesParent() { 293 writePatternBytes(PATTERN_0, 1); 294 writePatternBytes(PATTERN_1, 2); 295 296 assertPatternBytes(PATTERN_0, 1); 297 assertPatternBytes(PATTERN_1, 2); 298 mStorage.clearCache(); 299 assertPatternBytes(PATTERN_0, 1); 300 assertPatternBytes(PATTERN_1, 2); 301 } 302 303 public void testPattern_WriteParentWritesProfile() { 304 writePatternBytes(PATTERN_1, 2); 305 writePatternBytes(PATTERN_0, 1); 306 307 assertPatternBytes(PATTERN_0, 1); 308 assertPatternBytes(PATTERN_1, 2); 309 mStorage.clearCache(); 310 assertPatternBytes(PATTERN_0, 1); 311 assertPatternBytes(PATTERN_1, 2); 312 } 313 314 public void testPrefetch() { 315 mStorage.writeKeyValue("key", "toBeFetched", 0); 316 writePatternBytes(PATTERN_0, 0); 317 318 mStorage.clearCache(); 319 mStorage.prefetchUser(0); 320 321 assertEquals("toBeFetched", mStorage.readKeyValue("key", "default", 0)); 322 assertPatternBytes(PATTERN_0, 0); 323 } 324 325 public void testFileLocation_Owner() { 326 LockSettingsStorage storage = new LockSettingsStorage(getContext(), null); 327 328 assertEquals("/data/system/gesture.key", storage.getLegacyLockPatternFilename(0)); 329 assertEquals("/data/system/password.key", storage.getLegacyLockPasswordFilename(0)); 330 assertEquals("/data/system/gatekeeper.pattern.key", storage.getLockPatternFilename(0)); 331 assertEquals("/data/system/gatekeeper.password.key", storage.getLockPasswordFilename(0)); 332 } 333 334 public void testFileLocation_SecondaryUser() { 335 LockSettingsStorage storage = new LockSettingsStorage(getContext(), null); 336 337 assertEquals("/data/system/users/1/gatekeeper.pattern.key", storage.getLockPatternFilename(1)); 338 assertEquals("/data/system/users/1/gatekeeper.password.key", storage.getLockPasswordFilename(1)); 339 } 340 341 public void testFileLocation_ProfileToSecondary() { 342 LockSettingsStorage storage = new LockSettingsStorage(getContext(), null); 343 344 assertEquals("/data/system/users/2/gatekeeper.pattern.key", storage.getLockPatternFilename(2)); 345 assertEquals("/data/system/users/2/gatekeeper.password.key", storage.getLockPasswordFilename(2)); 346 } 347 348 public void testFileLocation_ProfileToOwner() { 349 LockSettingsStorage storage = new LockSettingsStorage(getContext(), null); 350 351 assertEquals("/data/system/users/3/gatekeeper.pattern.key", storage.getLockPatternFilename(3)); 352 assertEquals("/data/system/users/3/gatekeeper.password.key", storage.getLockPasswordFilename(3)); 353 } 354 355 private static void assertArrayEquals(byte[] expected, byte[] actual) { 356 if (!Arrays.equals(expected, actual)) { 357 fail("expected:<" + Arrays.toString(expected) + 358 "> but was:<" + Arrays.toString(actual) + ">"); 359 } 360 } 361 362 private void writePasswordBytes(byte[] password, int userId) { 363 mStorage.writeCredentialHash(CredentialHash.create( 364 password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD), userId); 365 } 366 367 private void writePatternBytes(byte[] pattern, int userId) { 368 mStorage.writeCredentialHash(CredentialHash.create( 369 pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN), userId); 370 } 371 372 private void assertPasswordBytes(byte[] password, int userId) { 373 CredentialHash cred = mStorage.readCredentialHash(userId); 374 assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, cred.type); 375 assertArrayEquals(password, cred.hash); 376 } 377 378 private void assertPatternBytes(byte[] pattern, int userId) { 379 CredentialHash cred = mStorage.readCredentialHash(userId); 380 assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PATTERN, cred.type); 381 assertArrayEquals(pattern, cred.hash); 382 } 383} 384