Home | History | Annotate | Download | only in encryptionapp
      1 /*
      2  * Copyright (C) 2016 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.cts.encryptionapp;
     18 
     19 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
     20 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
     21 
     22 import android.content.BroadcastReceiver;
     23 import android.content.ComponentName;
     24 import android.content.Context;
     25 import android.content.Intent;
     26 import android.content.IntentFilter;
     27 import android.content.pm.ComponentInfo;
     28 import android.content.pm.PackageManager;
     29 import android.content.pm.PackageManager.NameNotFoundException;
     30 import android.os.SystemClock;
     31 import android.os.UserManager;
     32 import android.provider.Settings;
     33 import android.support.test.uiautomator.UiDevice;
     34 import android.test.InstrumentationTestCase;
     35 import android.text.format.DateUtils;
     36 import android.util.Log;
     37 import android.view.KeyEvent;
     38 
     39 import java.io.File;
     40 import java.util.concurrent.CountDownLatch;
     41 import java.util.concurrent.TimeUnit;
     42 
     43 public class EncryptionAppTest extends InstrumentationTestCase {
     44     private static final String TAG = "EncryptionAppTest";
     45 
     46     private static final long TIMEOUT = 10 * DateUtils.SECOND_IN_MILLIS;
     47 
     48     private static final String KEY_BOOT = "boot";
     49 
     50     private static final String TEST_PKG = "com.android.cts.encryptionapp";
     51     private static final String TEST_ACTION = "com.android.cts.encryptionapp.TEST";
     52 
     53     private static final String OTHER_PKG = "com.android.cts.splitapp";
     54 
     55     private Context mCe;
     56     private Context mDe;
     57     private PackageManager mPm;
     58 
     59     private UiDevice mDevice;
     60     private AwareActivity mActivity;
     61 
     62     @Override
     63     public void setUp() throws Exception {
     64         super.setUp();
     65 
     66         mCe = getInstrumentation().getContext();
     67         mDe = mCe.createDeviceProtectedStorageContext();
     68         mPm = mCe.getPackageManager();
     69 
     70         mDevice = UiDevice.getInstance(getInstrumentation());
     71         assertNotNull(mDevice);
     72     }
     73 
     74     @Override
     75     public void tearDown() throws Exception {
     76         super.tearDown();
     77 
     78         if (mActivity != null) {
     79             mActivity.finish();
     80         }
     81     }
     82 
     83     public void testSetUp() throws Exception {
     84         // Write both CE/DE data for ourselves
     85         assertTrue("CE file", getTestFile(mCe).createNewFile());
     86         assertTrue("DE file", getTestFile(mDe).createNewFile());
     87 
     88         doBootCountBefore();
     89 
     90         mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(),
     91                 AwareActivity.class, null);
     92         mDevice.waitForIdle();
     93 
     94         // Set a PIN for this user
     95         mDevice.executeShellCommand("settings put global require_password_to_decrypt 0");
     96         mDevice.executeShellCommand("locksettings set-disabled false");
     97         mDevice.executeShellCommand("locksettings set-pin 12345");
     98     }
     99 
    100     public void testTearDown() throws Exception {
    101         // Just in case, always try tearing down keyguard
    102         dismissKeyguard();
    103 
    104         mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(),
    105                 AwareActivity.class, null);
    106         mDevice.waitForIdle();
    107 
    108         // Clear PIN for this user
    109         mDevice.executeShellCommand("locksettings clear --old 12345");
    110         mDevice.executeShellCommand("locksettings set-disabled true");
    111         mDevice.executeShellCommand("settings delete global require_password_to_decrypt");
    112     }
    113 
    114     public void doBootCountBefore() throws Exception {
    115         final int thisCount = getBootCount();
    116         mDe.getSharedPreferences(KEY_BOOT, 0).edit().putInt(KEY_BOOT, thisCount).commit();
    117     }
    118 
    119     public void doBootCountAfter() throws Exception {
    120         final int lastCount = mDe.getSharedPreferences(KEY_BOOT, 0).getInt(KEY_BOOT, -1);
    121         final int thisCount = getBootCount();
    122         assertTrue("Current boot count " + thisCount + " not greater than last " + lastCount,
    123                 thisCount > lastCount);
    124     }
    125 
    126     public void testVerifyUnlockedAndDismiss() throws Exception {
    127         doBootCountAfter();
    128         assertUnlocked();
    129         dismissKeyguard();
    130         assertUnlocked();
    131     }
    132 
    133     public void testVerifyLockedAndDismiss() throws Exception {
    134         doBootCountAfter();
    135         assertLocked();
    136 
    137         final CountDownLatch latch = new CountDownLatch(1);
    138         final BroadcastReceiver receiver = new BroadcastReceiver() {
    139             @Override
    140             public void onReceive(Context context, Intent intent) {
    141                 latch.countDown();
    142             }
    143         };
    144         mDe.registerReceiver(receiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED));
    145 
    146         dismissKeyguard();
    147 
    148         // Dismiss keyguard should have kicked off immediate broadcast
    149         assertTrue("USER_UNLOCKED", latch.await(1, TimeUnit.MINUTES));
    150 
    151         // And we should now be fully unlocked; we run immediately like this to
    152         // avoid missing BOOT_COMPLETED due to instrumentation being torn down.
    153         assertUnlocked();
    154     }
    155 
    156     private void enterTestPin() throws Exception {
    157         // TODO: change the combination on my luggage
    158         mDevice.waitForIdle();
    159         mDevice.pressKeyCode(KeyEvent.KEYCODE_1);
    160         mDevice.pressKeyCode(KeyEvent.KEYCODE_2);
    161         mDevice.pressKeyCode(KeyEvent.KEYCODE_3);
    162         mDevice.pressKeyCode(KeyEvent.KEYCODE_4);
    163         mDevice.pressKeyCode(KeyEvent.KEYCODE_5);
    164         mDevice.waitForIdle();
    165         mDevice.pressEnter();
    166         mDevice.waitForIdle();
    167     }
    168 
    169     private void dismissKeyguard() throws Exception {
    170         mDevice.wakeUp();
    171         mDevice.waitForIdle();
    172         mDevice.pressMenu();
    173         mDevice.waitForIdle();
    174         enterTestPin();
    175     }
    176 
    177     public void assertLocked() throws Exception {
    178         awaitBroadcast(Intent.ACTION_LOCKED_BOOT_COMPLETED);
    179 
    180         assertFalse("CE exists", getTestFile(mCe).exists());
    181         assertTrue("DE exists", getTestFile(mDe).exists());
    182 
    183         assertFalse("isUserUnlocked", mCe.getSystemService(UserManager.class).isUserUnlocked());
    184         assertFalse("isUserUnlocked", mDe.getSystemService(UserManager.class).isUserUnlocked());
    185 
    186         assertTrue("AwareProvider", AwareProvider.sCreated);
    187         assertFalse("UnawareProvider", UnawareProvider.sCreated);
    188 
    189         assertNotNull("AwareProvider",
    190                 mPm.resolveContentProvider("com.android.cts.encryptionapp.aware", 0));
    191         assertNull("UnawareProvider",
    192                 mPm.resolveContentProvider("com.android.cts.encryptionapp.unaware", 0));
    193 
    194         assertGetAware(true, 0);
    195         assertGetAware(true, MATCH_DIRECT_BOOT_AWARE);
    196         assertGetAware(false, MATCH_DIRECT_BOOT_UNAWARE);
    197         assertGetAware(true, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
    198 
    199         assertGetUnaware(false, 0);
    200         assertGetUnaware(false, MATCH_DIRECT_BOOT_AWARE);
    201         assertGetUnaware(true, MATCH_DIRECT_BOOT_UNAWARE);
    202         assertGetUnaware(true, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
    203 
    204         assertQuery(1, 0);
    205         assertQuery(1, MATCH_DIRECT_BOOT_AWARE);
    206         assertQuery(1, MATCH_DIRECT_BOOT_UNAWARE);
    207         assertQuery(2, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
    208     }
    209 
    210     public void assertUnlocked() throws Exception {
    211         awaitBroadcast(Intent.ACTION_LOCKED_BOOT_COMPLETED);
    212         awaitBroadcast(Intent.ACTION_BOOT_COMPLETED);
    213 
    214         assertTrue("CE exists", getTestFile(mCe).exists());
    215         assertTrue("DE exists", getTestFile(mDe).exists());
    216 
    217         assertTrue("isUserUnlocked", mCe.getSystemService(UserManager.class).isUserUnlocked());
    218         assertTrue("isUserUnlocked", mDe.getSystemService(UserManager.class).isUserUnlocked());
    219 
    220         assertTrue("AwareProvider", AwareProvider.sCreated);
    221         assertTrue("UnawareProvider", UnawareProvider.sCreated);
    222 
    223         assertNotNull("AwareProvider",
    224                 mPm.resolveContentProvider("com.android.cts.encryptionapp.aware", 0));
    225         assertNotNull("UnawareProvider",
    226                 mPm.resolveContentProvider("com.android.cts.encryptionapp.unaware", 0));
    227 
    228         assertGetAware(true, 0);
    229         assertGetAware(true, MATCH_DIRECT_BOOT_AWARE);
    230         assertGetAware(false, MATCH_DIRECT_BOOT_UNAWARE);
    231         assertGetAware(true, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
    232 
    233         assertGetUnaware(true, 0);
    234         assertGetUnaware(false, MATCH_DIRECT_BOOT_AWARE);
    235         assertGetUnaware(true, MATCH_DIRECT_BOOT_UNAWARE);
    236         assertGetUnaware(true, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
    237 
    238         assertQuery(2, 0);
    239         assertQuery(1, MATCH_DIRECT_BOOT_AWARE);
    240         assertQuery(1, MATCH_DIRECT_BOOT_UNAWARE);
    241         assertQuery(2, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
    242     }
    243 
    244     private void assertQuery(int count, int flags) throws Exception {
    245         final Intent intent = new Intent(TEST_ACTION);
    246         assertEquals("activity", count, mPm.queryIntentActivities(intent, flags).size());
    247         assertEquals("service", count, mPm.queryIntentServices(intent, flags).size());
    248         assertEquals("provider", count, mPm.queryIntentContentProviders(intent, flags).size());
    249         assertEquals("receiver", count, mPm.queryBroadcastReceivers(intent, flags).size());
    250     }
    251 
    252     private void assertGetUnaware(boolean visible, int flags) throws Exception {
    253         assertGet(visible, false, flags);
    254     }
    255 
    256     private void assertGetAware(boolean visible, int flags) throws Exception {
    257         assertGet(visible, true, flags);
    258     }
    259 
    260     private ComponentName buildName(String prefix, String type) {
    261         return new ComponentName(TEST_PKG, TEST_PKG + "." + prefix + type);
    262     }
    263 
    264     private void assertGet(boolean visible, boolean aware, int flags) throws Exception {
    265         final String prefix = aware ? "Aware" : "Unaware";
    266 
    267         ComponentName name;
    268         ComponentInfo info;
    269 
    270         name = buildName(prefix, "Activity");
    271         try {
    272             info = mPm.getActivityInfo(name, flags);
    273             assertTrue(name + " visible", visible);
    274             assertEquals(name + " directBootAware", aware, info.directBootAware);
    275         } catch (NameNotFoundException e) {
    276             assertFalse(name + " visible", visible);
    277         }
    278 
    279         name = buildName(prefix, "Service");
    280         try {
    281             info = mPm.getServiceInfo(name, flags);
    282             assertTrue(name + " visible", visible);
    283             assertEquals(name + " directBootAware", aware, info.directBootAware);
    284         } catch (NameNotFoundException e) {
    285             assertFalse(name + " visible", visible);
    286         }
    287 
    288         name = buildName(prefix, "Provider");
    289         try {
    290             info = mPm.getProviderInfo(name, flags);
    291             assertTrue(name + " visible", visible);
    292             assertEquals(name + " directBootAware", aware, info.directBootAware);
    293         } catch (NameNotFoundException e) {
    294             assertFalse(name + " visible", visible);
    295         }
    296 
    297         name = buildName(prefix, "Receiver");
    298         try {
    299             info = mPm.getReceiverInfo(name, flags);
    300             assertTrue(name + " visible", visible);
    301             assertEquals(name + " directBootAware", aware, info.directBootAware);
    302         } catch (NameNotFoundException e) {
    303             assertFalse(name + " visible", visible);
    304         }
    305     }
    306 
    307     private File getTestFile(Context context) {
    308         return new File(context.getFilesDir(), "test");
    309     }
    310 
    311     private int getBootCount() throws Exception {
    312         return Settings.Global.getInt(mDe.getContentResolver(), Settings.Global.BOOT_COUNT);
    313     }
    314 
    315     private void awaitBroadcast(String action) throws Exception {
    316         final Context otherContext = mDe.createPackageContext(OTHER_PKG, 0)
    317                 .createDeviceProtectedStorageContext();
    318         final File probe = new File(otherContext.getFilesDir(),
    319                 getBootCount() + "." + action);
    320         for (int i = 0; i < 150; i++) {
    321             Log.d(TAG, "Waiting for " + probe + "...");
    322             if (probe.exists()) {
    323                 return;
    324             }
    325             SystemClock.sleep(1000);
    326         }
    327         throw new AssertionError("Failed to find " + probe);
    328     }
    329 }
    330