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