1 /* 2 * Copyright 2024 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.pvmfw.test; 18 19 import static com.android.tradefed.device.TestDevice.MicrodroidBuilder; 20 21 import static com.google.common.truth.Truth.assertThat; 22 23 import static org.junit.Assume.assumeTrue; 24 25 import androidx.annotation.NonNull; 26 import androidx.annotation.Nullable; 27 28 import com.android.microdroid.test.host.MicrodroidHostTestCaseBase; 29 import com.android.tradefed.device.DeviceNotAvailableException; 30 import com.android.tradefed.device.ITestDevice; 31 import com.android.tradefed.device.TestDevice; 32 import com.android.tradefed.util.FileUtil; 33 34 import org.junit.After; 35 import org.junit.Before; 36 37 import java.io.File; 38 import java.util.Map; 39 40 /** Base class for testing custom pvmfw */ 41 public class CustomPvmfwHostTestCaseBase extends MicrodroidHostTestCaseBase { 42 @NonNull public static final String PVMFW_FILE_NAME = "pvmfw_test.bin"; 43 @NonNull public static final String BCC_FILE_NAME = "bcc.dat"; 44 @NonNull public static final String PACKAGE_FILE_NAME = "MicrodroidTestApp.apk"; 45 @NonNull public static final String PACKAGE_NAME = "com.android.microdroid.test"; 46 @NonNull public static final String MICRODROID_DEBUG_FULL = "full"; 47 @NonNull public static final String MICRODROID_DEBUG_NONE = "none"; 48 49 @NonNull public static final String MICRODROID_CONFIG_PATH = "assets/vm_config_apex.json"; 50 51 @NonNull 52 public static final String VM_REFERENCE_DT_PATH = "/data/local/tmp/pvmfw/reference_dt.dtb"; 53 54 @NonNull public static final String MICRODROID_LOG_PATH = TEST_ROOT + "log.txt"; 55 public static final int BOOT_COMPLETE_TIMEOUT_MS = 30000; // 30 seconds 56 public static final int BOOT_FAILURE_WAIT_TIME_MS = 10000; // 10 seconds 57 public static final int CONSOLE_OUTPUT_WAIT_MS = 5000; // 5 seconds 58 59 @NonNull public static final String CUSTOM_PVMFW_FILE_PREFIX = "pvmfw"; 60 @NonNull public static final String CUSTOM_PVMFW_FILE_SUFFIX = ".bin"; 61 62 @NonNull 63 public static final String CUSTOM_PVMFW_IMG_PATH = TRADEFED_TEST_ROOT + PVMFW_FILE_NAME; 64 65 @NonNull public static final String CUSTOM_PVMFW_IMG_PATH_PROP = "hypervisor.pvmfw.path"; 66 67 @Nullable private File mPvmfwBinFileOnHost; 68 @Nullable private File mBccFileOnHost; 69 @Nullable private File mVmReferenceDtFile; 70 private boolean mSecretKeeperSupported; 71 72 @NonNull private TestDevice mAndroidDevice; 73 @Nullable private ITestDevice mMicrodroidDevice; 74 75 @Nullable private File mCustomPvmfwFileOnHost; 76 77 @Before setUp()78 public void setUp() throws Exception { 79 mAndroidDevice = (TestDevice) getDevice(); 80 81 // Check device capabilities 82 assumeDeviceIsCapable(mAndroidDevice); 83 assumeTrue( 84 "Skip if protected VMs are not supported", 85 mAndroidDevice.supportsMicrodroid(/* protectedVm= */ true)); 86 87 mPvmfwBinFileOnHost = findTestFile(PVMFW_FILE_NAME); 88 mBccFileOnHost = findTestFile(BCC_FILE_NAME); 89 90 // This is prepared by AndroidTest.xml 91 mVmReferenceDtFile = mAndroidDevice.pullFile(VM_REFERENCE_DT_PATH); 92 93 mSecretKeeperSupported = isUpdatableVmSupported(); 94 95 // Prepare for system properties for custom pvmfw.img. 96 // File will be prepared later in individual test and then pushed to device 97 // when launching with launchProtectedVmAndWaitForBootCompleted(). 98 mCustomPvmfwFileOnHost = 99 FileUtil.createTempFile(CUSTOM_PVMFW_FILE_PREFIX, CUSTOM_PVMFW_FILE_SUFFIX); 100 setPropertyOrThrow(mAndroidDevice, CUSTOM_PVMFW_IMG_PATH_PROP, CUSTOM_PVMFW_IMG_PATH); 101 102 // Prepare for launching microdroid 103 mAndroidDevice.installPackage(findTestFile(PACKAGE_FILE_NAME), /* reinstall */ false); 104 prepareVirtualizationTestSetup(mAndroidDevice); 105 mMicrodroidDevice = null; 106 } 107 108 @After shutdown()109 public void shutdown() throws Exception { 110 shutdownMicrodroid(); 111 112 mAndroidDevice.uninstallPackage(PACKAGE_NAME); 113 114 FileUtil.deleteFile(mVmReferenceDtFile); 115 116 // Cleanup for custom pvmfw.img 117 setPropertyOrThrow(mAndroidDevice, CUSTOM_PVMFW_IMG_PATH_PROP, ""); 118 FileUtil.deleteFile(mCustomPvmfwFileOnHost); 119 120 cleanUpVirtualizationTestSetup(mAndroidDevice); 121 } 122 123 /** Returns android device */ 124 @NonNull getAndroidDevice()125 public TestDevice getAndroidDevice() { 126 return mAndroidDevice; 127 } 128 129 /** Returns pvmfw.bin file on host for building custom pvmfw with */ 130 @NonNull getPvmfwBinFile()131 public File getPvmfwBinFile() { 132 return mPvmfwBinFileOnHost; 133 } 134 135 /** Returns BCC file on host for building custom pvmfw with */ 136 @NonNull getBccFile()137 public File getBccFile() { 138 return mBccFileOnHost; 139 } 140 141 /** Returns VM reference DT, generated from DUT, on host for building custom pvmfw with. */ 142 @Nullable getVmReferenceDtFile()143 public File getVmReferenceDtFile() { 144 return mVmReferenceDtFile; 145 } 146 147 /** 148 * Returns a custom pvmfw file. 149 * 150 * <p>This is a temporary file on host. The file should been prepared as a custom pvmfw because 151 * calling {@link #launchProtectedVmAndWaitForBootCompleted}, so virtualization manager can read 152 * the file path from sysprop and boot pVM with it. 153 */ 154 @NonNull getCustomPvmfwFile()155 public File getCustomPvmfwFile() { 156 return mCustomPvmfwFileOnHost; 157 } 158 159 /** 160 * Returns whether a secretkeeper is supported. 161 * 162 * <p>If {@code true}, then VM reference DT must exist. (i.e. {@link #getVmReferenceDtFile} must 163 * exist {@code null}). 164 */ isSecretKeeperSupported()165 public boolean isSecretKeeperSupported() { 166 return mSecretKeeperSupported; 167 } 168 169 /** 170 * Launches protected VM with custom pvmfw ({@link #getCustomPvmfwFile}) and wait for boot 171 * completed. Throws exception when boot failed. 172 */ launchProtectedVmAndWaitForBootCompleted( String debugLevel, long adbTimeoutMs, @NonNull Map<String, File> bootFiles)173 public ITestDevice launchProtectedVmAndWaitForBootCompleted( 174 String debugLevel, long adbTimeoutMs, @NonNull Map<String, File> bootFiles) 175 throws DeviceNotAvailableException { 176 MicrodroidBuilder builder = 177 MicrodroidBuilder.fromDevicePath( 178 getPathForPackage(PACKAGE_NAME), MICRODROID_CONFIG_PATH) 179 .debugLevel(debugLevel) 180 .protectedVm(/* protectedVm= */ true) 181 .addBootFile(mCustomPvmfwFileOnHost, PVMFW_FILE_NAME) 182 .setAdbConnectTimeoutMs(adbTimeoutMs); 183 for (String name : bootFiles.keySet()) { 184 File file = bootFiles.get(name); 185 builder.addBootFile(file, name); 186 } 187 188 mMicrodroidDevice = builder.build(mAndroidDevice); 189 190 assertThat(mMicrodroidDevice.waitForBootComplete(BOOT_COMPLETE_TIMEOUT_MS)).isTrue(); 191 assertThat(mMicrodroidDevice.enableAdbRoot()).isTrue(); 192 return mMicrodroidDevice; 193 } 194 195 /** Shuts down microdroid if it's running */ shutdownMicrodroid()196 public void shutdownMicrodroid() throws Exception { 197 if (mMicrodroidDevice != null) { 198 mAndroidDevice.shutdownMicrodroid(mMicrodroidDevice); 199 mMicrodroidDevice = null; 200 } 201 } 202 } 203