1 /* 2 * Copyright (C) 2019 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.tests.dsu; 18 19 import com.android.tradefed.build.BuildRetrievalError; 20 import com.android.tradefed.build.IBuildInfo; 21 import com.android.tradefed.build.IDeviceBuildInfo; 22 import com.android.tradefed.config.Option; 23 import com.android.tradefed.config.Option.Importance; 24 import com.android.tradefed.device.DeviceNotAvailableException; 25 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; 26 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; 27 import com.android.tradefed.util.CommandResult; 28 import com.android.tradefed.util.ZipUtil2; 29 30 import org.apache.commons.compress.archivers.zip.ZipFile; 31 32 import org.junit.After; 33 import org.junit.Assert; 34 import org.junit.Test; 35 import org.junit.runner.RunWith; 36 37 import java.io.ByteArrayOutputStream; 38 import java.io.File; 39 import java.io.IOException; 40 import java.lang.Process; 41 import java.lang.Runtime; 42 import java.util.concurrent.TimeUnit; 43 44 /** 45 * Test Dynamic System Updates by booting in and out of a supplied system image 46 */ 47 @RunWith(DeviceJUnit4ClassRunner.class) 48 public class DSUEndtoEndTest extends BaseHostJUnit4Test { 49 private static final long kDefaultUserdataSize = 4L * 1024 * 1024 * 1024; 50 private static final String LPUNPACK_PATH = "bin/lpunpack"; 51 private static final String SIMG2IMG_PATH = "bin/simg2img"; 52 53 // Example: atest -v DSUEndtoEndTest -- --test-arg \ 54 // com.android.tradefed.testtype.HostTest:set-option:system_image_path:/full/path/to/system.img 55 @Option(name="system_image_path", 56 shortName='s', 57 description="full path to the system image to use. If not specified, attempt " + 58 "to download the image from the test infrastructure", 59 importance=Importance.ALWAYS) 60 private String mSystemImagePath; 61 62 @Option(name="userdata_size", 63 shortName='u', 64 description="size in bytes of the new userdata partition", 65 importance=Importance.ALWAYS) 66 private long mUserdataSize = kDefaultUserdataSize; 67 68 private File mUnsparseSystemImage; 69 70 @After teardown()71 public void teardown() throws Exception { 72 if (mUnsparseSystemImage != null) { 73 mUnsparseSystemImage.delete(); 74 } 75 } 76 77 @Test testDSU()78 public void testDSU() throws Exception { 79 String simg2imgPath = "simg2img"; 80 if (mSystemImagePath == null) { 81 IBuildInfo buildInfo = getBuild(); 82 File imgs = ((IDeviceBuildInfo) buildInfo).getDeviceImageFile(); 83 Assert.assertNotEquals("Failed to fetch system image. See system_image_path parameter", null, imgs); 84 File otaTools = buildInfo.getFile("otatools.zip"); 85 File tempdir = ZipUtil2.extractZipToTemp(otaTools, "otatools"); 86 File system = ZipUtil2.extractFileFromZip(new ZipFile(imgs), "system.img"); 87 if (system == null) { 88 File superImg = ZipUtil2.extractFileFromZip(new ZipFile(imgs), "super.img"); 89 String lpunpackPath = new File(tempdir, LPUNPACK_PATH).getAbsolutePath(); 90 String outputDir = superImg.getParentFile().getAbsolutePath(); 91 String[] cmd = {lpunpackPath, "-p", "system_a", superImg.getAbsolutePath(), outputDir}; 92 Process p = Runtime.getRuntime().exec(cmd); 93 p.waitFor(); 94 if (p.exitValue() == 0) { 95 mSystemImagePath = new File(outputDir, "system_a.img").getAbsolutePath(); 96 } else { 97 ByteArrayOutputStream stderr = new ByteArrayOutputStream(); 98 int len; 99 byte[] buf = new byte[1024]; 100 while ((len = p.getErrorStream().read(buf)) != -1) { 101 stderr.write(buf, 0, len); 102 } 103 Assert.assertEquals("non-zero exit value (" + stderr.toString("UTF-8") + ")", 0, p.exitValue()); 104 } 105 } else { 106 mSystemImagePath = system.getAbsolutePath(); 107 } 108 simg2imgPath = new File(tempdir, SIMG2IMG_PATH).getAbsolutePath(); 109 } 110 File gsi = new File(mSystemImagePath); 111 Assert.assertTrue("not a valid file", gsi.isFile()); 112 String[] cmd = {simg2imgPath, mSystemImagePath, mSystemImagePath + ".raw"}; 113 Process p = Runtime.getRuntime().exec(cmd); 114 p.waitFor(); 115 if (p.exitValue() == 0) { 116 mUnsparseSystemImage = new File(mSystemImagePath + ".raw"); 117 gsi = mUnsparseSystemImage; 118 } 119 120 boolean wasRoot = getDevice().isAdbRoot(); 121 if (!wasRoot) 122 Assert.assertTrue("Test requires root", getDevice().enableAdbRoot()); 123 124 expectGsiStatus("normal"); 125 126 // Sleep after installing to allow time for gsi_tool to reboot. This prevents a race between 127 // the device rebooting and waitForDeviceAvailable() returning. 128 getDevice().executeShellV2Command("gsi_tool install --userdata-size " + mUserdataSize + 129 " --gsi-size " + gsi.length() + " && sleep 10000000", gsi, null, 10, TimeUnit.MINUTES, 1); 130 getDevice().waitForDeviceAvailable(); 131 getDevice().enableAdbRoot(); 132 133 expectGsiStatus("running"); 134 135 getDevice().rebootUntilOnline(); 136 137 expectGsiStatus("installed"); 138 139 CommandResult result = getDevice().executeShellV2Command("gsi_tool enable"); 140 Assert.assertEquals("gsi_tool enable failed", 0, result.getExitCode().longValue()); 141 142 getDevice().reboot(); 143 144 expectGsiStatus("running"); 145 146 getDevice().reboot(); 147 148 expectGsiStatus("running"); 149 150 getDevice().executeShellV2Command("gsi_tool wipe"); 151 152 getDevice().rebootUntilOnline(); 153 154 expectGsiStatus("normal"); 155 156 if (wasRoot) { 157 getDevice().enableAdbRoot(); 158 } 159 } 160 expectGsiStatus(String expected)161 private void expectGsiStatus(String expected) throws Exception { 162 CommandResult result = getDevice().executeShellV2Command("gsi_tool status"); 163 String status = result.getStdout().split("\n", 2)[0].trim(); 164 Assert.assertEquals("Device not in expected DSU state", expected, status); 165 } 166 } 167 168