Home | History | Annotate | Download | only in server
      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 
     17 package com.android.server;
     18 
     19 import android.content.Context;
     20 import android.content.ContextWrapper;
     21 import android.content.pm.UserInfo;
     22 import android.database.sqlite.SQLiteDatabase;
     23 import android.os.FileUtils;
     24 import android.os.UserManager;
     25 import android.test.AndroidTestCase;
     26 
     27 import java.io.File;
     28 import java.util.ArrayList;
     29 import java.util.Arrays;
     30 import java.util.List;
     31 import java.util.concurrent.CountDownLatch;
     32 
     33 public 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