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 android.appsecurity.cts; 18 19 import static android.appsecurity.cts.Utils.waitForBootCompleted; 20 21 import static org.junit.Assert.assertNotNull; 22 import static org.junit.Assert.assertTrue; 23 24 import android.platform.test.annotations.RequiresDevice; 25 26 import com.android.ddmlib.Log; 27 import com.android.tradefed.device.DeviceNotAvailableException; 28 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; 29 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; 30 31 import org.junit.After; 32 import org.junit.Before; 33 import org.junit.Test; 34 import org.junit.runner.RunWith; 35 36 /** 37 * Set of tests that verify behavior of direct boot, if supported. 38 * <p> 39 * Note that these tests drive PIN setup manually instead of relying on device 40 * administrators, which are not supported by all devices. 41 */ 42 @RunWith(DeviceJUnit4ClassRunner.class) 43 public class DirectBootHostTest extends BaseHostJUnit4Test { 44 private static final String TAG = "DirectBootHostTest"; 45 46 private static final String PKG = "com.android.cts.encryptionapp"; 47 private static final String CLASS = PKG + ".EncryptionAppTest"; 48 private static final String APK = "CtsEncryptionApp.apk"; 49 50 private static final String OTHER_APK = "CtsSplitApp.apk"; 51 private static final String OTHER_PKG = "com.android.cts.splitapp"; 52 53 private static final String MODE_NATIVE = "native"; 54 private static final String MODE_EMULATED = "emulated"; 55 private static final String MODE_NONE = "none"; 56 57 private static final String FEATURE_DEVICE_ADMIN = "feature:android.software.device_admin"; 58 private static final String FEATURE_AUTOMOTIVE = "feature:android.hardware.type.automotive"; 59 60 private static final long SHUTDOWN_TIME_MS = 30 * 1000; 61 62 @Before setUp()63 public void setUp() throws Exception { 64 Utils.prepareSingleUser(getDevice()); 65 assertNotNull(getAbi()); 66 assertNotNull(getBuild()); 67 68 getDevice().uninstallPackage(PKG); 69 getDevice().uninstallPackage(OTHER_PKG); 70 } 71 72 @After tearDown()73 public void tearDown() throws Exception { 74 getDevice().uninstallPackage(PKG); 75 getDevice().uninstallPackage(OTHER_PKG); 76 } 77 78 /** 79 * Automotive devices MUST support native FBE. 80 */ 81 @Test testAutomotiveNativeFbe()82 public void testAutomotiveNativeFbe() throws Exception { 83 if (!isSupportedDevice()) { 84 Log.v(TAG, "Device not supported; skipping test"); 85 return; 86 } else if (!isAutomotiveDevice()) { 87 Log.v(TAG, "Device not automotive; skipping test"); 88 return; 89 } 90 91 assertTrue("Automotive devices must support native FBE", 92 MODE_NATIVE.equals(getFbeMode())); 93 } 94 95 /** 96 * If device has native FBE, verify lifecycle. 97 */ 98 @Test testDirectBootNative()99 public void testDirectBootNative() throws Exception { 100 if (!isSupportedDevice()) { 101 Log.v(TAG, "Device not supported; skipping test"); 102 return; 103 } else if (!MODE_NATIVE.equals(getFbeMode())) { 104 Log.v(TAG, "Device doesn't have native FBE; skipping test"); 105 return; 106 } 107 108 doDirectBootTest(MODE_NATIVE); 109 } 110 111 /** 112 * If device doesn't have native FBE, enable emulation and verify lifecycle. 113 */ 114 @Test 115 @RequiresDevice testDirectBootEmulated()116 public void testDirectBootEmulated() throws Exception { 117 if (!isSupportedDevice()) { 118 Log.v(TAG, "Device not supported; skipping test"); 119 return; 120 } else if (MODE_NATIVE.equals(getFbeMode())) { 121 Log.v(TAG, "Device has native FBE; skipping test"); 122 return; 123 } 124 125 doDirectBootTest(MODE_EMULATED); 126 } 127 128 /** 129 * If device doesn't have native FBE, verify normal lifecycle. 130 */ 131 @Test testDirectBootNone()132 public void testDirectBootNone() throws Exception { 133 if (!isSupportedDevice()) { 134 Log.v(TAG, "Device not supported; skipping test"); 135 return; 136 } else if (MODE_NATIVE.equals(getFbeMode())) { 137 Log.v(TAG, "Device has native FBE; skipping test"); 138 return; 139 } 140 141 doDirectBootTest(MODE_NONE); 142 } 143 doDirectBootTest(String mode)144 public void doDirectBootTest(String mode) throws Exception { 145 boolean doTest = true; 146 try { 147 // Set up test app and secure lock screens 148 new InstallMultiple().addApk(APK).run(); 149 new InstallMultiple().addApk(OTHER_APK).run(); 150 151 // To receive boot broadcasts, kick our other app out of stopped state 152 getDevice().executeShellCommand("am start -a android.intent.action.MAIN" 153 + " --user current" 154 + " -c android.intent.category.LAUNCHER com.android.cts.splitapp/.MyActivity"); 155 156 // Give enough time for PackageManager to persist stopped state 157 Thread.sleep(15000); 158 159 runDeviceTestsAsCurrentUser(PKG, CLASS, "testSetUp"); 160 161 // Give enough time for vold to update keys 162 Thread.sleep(15000); 163 164 // Reboot system into known state with keys ejected 165 if (MODE_EMULATED.equals(mode)) { 166 final String res = getDevice().executeShellCommand("sm set-emulate-fbe true"); 167 if (res != null && res.contains("Emulation not supported")) { 168 doTest = false; 169 } 170 getDevice().waitForDeviceNotAvailable(SHUTDOWN_TIME_MS); 171 getDevice().waitForDeviceOnline(120000); 172 } else { 173 getDevice().rebootUntilOnline(); 174 } 175 waitForBootCompleted(getDevice()); 176 177 if (doTest) { 178 if (MODE_NONE.equals(mode)) { 179 runDeviceTestsAsCurrentUser(PKG, CLASS, "testVerifyUnlockedAndDismiss"); 180 } else { 181 runDeviceTestsAsCurrentUser(PKG, CLASS, "testVerifyLockedAndDismiss"); 182 } 183 } 184 185 } finally { 186 try { 187 // Remove secure lock screens and tear down test app 188 runDeviceTestsAsCurrentUser(PKG, CLASS, "testTearDown"); 189 } finally { 190 getDevice().uninstallPackage(PKG); 191 192 // Get ourselves back into a known-good state 193 if (MODE_EMULATED.equals(mode)) { 194 getDevice().executeShellCommand("sm set-emulate-fbe false"); 195 getDevice().waitForDeviceNotAvailable(SHUTDOWN_TIME_MS); 196 getDevice().waitForDeviceOnline(); 197 } else { 198 getDevice().rebootUntilOnline(); 199 } 200 getDevice().waitForDeviceAvailable(); 201 } 202 } 203 } 204 runDeviceTestsAsCurrentUser( String packageName, String testClassName, String testMethodName)205 private void runDeviceTestsAsCurrentUser( 206 String packageName, String testClassName, String testMethodName) 207 throws DeviceNotAvailableException { 208 Utils.runDeviceTestsAsCurrentUser(getDevice(), packageName, testClassName, testMethodName); 209 } 210 getFbeMode()211 private String getFbeMode() throws Exception { 212 return getDevice().executeShellCommand("sm get-fbe-mode").trim(); 213 } 214 isSupportedDevice()215 private boolean isSupportedDevice() throws Exception { 216 return getDevice().hasFeature(FEATURE_DEVICE_ADMIN); 217 } 218 isAutomotiveDevice()219 private boolean isAutomotiveDevice() throws Exception { 220 return getDevice().hasFeature(FEATURE_AUTOMOTIVE); 221 } 222 223 private class InstallMultiple extends BaseInstallMultiple<InstallMultiple> { InstallMultiple()224 public InstallMultiple() { 225 super(getDevice(), getBuild(), getAbi()); 226 } 227 } 228 } 229