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.IBuildInfo; 20 import com.android.tradefed.build.IDeviceBuildInfo; 21 import com.android.tradefed.config.Option; 22 import com.android.tradefed.config.Option.Importance; 23 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; 24 import com.android.tradefed.util.FileUtil; 25 import com.android.tradefed.util.SparseImageUtil; 26 import com.android.tradefed.util.StreamUtil; 27 import com.android.tradefed.util.ZipUtil2; 28 29 import org.apache.commons.compress.archivers.zip.ZipFile; 30 import org.junit.Before; 31 import org.junit.After; 32 import org.junit.Assert; 33 import org.junit.Test; 34 import org.junit.runner.RunWith; 35 36 import java.io.File; 37 import java.io.IOException; 38 import java.util.concurrent.TimeUnit; 39 40 /** 41 * Test Dynamic System Updates by booting in and out of a supplied system image 42 */ 43 @RunWith(DeviceJUnit4ClassRunner.class) 44 public class DSUEndtoEndTest extends DsuTestBase { 45 private static final long kDefaultUserdataSize = 4L * 1024 * 1024 * 1024; 46 private static final String LPUNPACK_PATH = "bin/lpunpack"; 47 48 // Example: atest -v DSUEndtoEndTest -- --test-arg \ 49 // com.android.tradefed.testtype.HostTest:set-option:system_image_path:/full/path/to/system.img 50 @Option(name="system_image_path", 51 shortName='s', 52 description="full path to the system image to use. If not specified, attempt " + 53 "to download the image from the test infrastructure", 54 importance=Importance.ALWAYS) 55 private String mSystemImagePath; 56 57 private File mTempDir; 58 getTempPath(String relativePath)59 private File getTempPath(String relativePath) throws IOException { 60 if (mTempDir == null) { 61 mTempDir = FileUtil.createTempDir("DSUEndtoEndTest"); 62 } 63 return new File(mTempDir, relativePath); 64 } 65 66 /** Extract system.img from build info to a temproary file. */ extractSystemImageFromBuildInfo(IBuildInfo buildInfo)67 private File extractSystemImageFromBuildInfo(IBuildInfo buildInfo) 68 throws IOException, InterruptedException { 69 File imgZip = ((IDeviceBuildInfo) buildInfo).getDeviceImageFile(); 70 Assert.assertNotNull( 71 "Failed to fetch system image. See system_image_path parameter", imgZip); 72 73 File superImg = getTempPath("super.img"); 74 if (imgZip.isDirectory()) { 75 File systemImg = new File(imgZip, "system.img"); 76 if (systemImg.exists()) { 77 return systemImg; 78 } 79 superImg = new File(imgZip, "super.img"); 80 Assert.assertTrue( 81 "No system.img or super.img in img zip.", 82 superImg.exists()); 83 } else { 84 try (ZipFile zip = new ZipFile(imgZip)) { 85 File systemImg = getTempPath("system.img"); 86 if (ZipUtil2.extractFileFromZip(zip, "system.img", systemImg)) { 87 return systemImg; 88 } 89 Assert.assertTrue( 90 "No system.img or super.img in img zip.", 91 ZipUtil2.extractFileFromZip(zip, "super.img", superImg)); 92 } 93 } 94 95 if (SparseImageUtil.isSparse(superImg)) { 96 File unsparseSuperImage = getTempPath("super.raw"); 97 SparseImageUtil.unsparse(superImg, unsparseSuperImage); 98 superImg = unsparseSuperImage; 99 } 100 101 File otaTools = buildInfo.getFile("otatools.zip"); 102 Assert.assertNotNull("No otatools.zip in BuildInfo.", otaTools); 103 File otaToolsDir = getTempPath("otatools"); 104 ZipUtil2.extractZip(otaTools, otaToolsDir); 105 106 String lpunpackPath = new File(otaToolsDir, LPUNPACK_PATH).getAbsolutePath(); 107 File outputDir = getTempPath("lpunpack_output"); 108 outputDir.mkdirs(); 109 String[] cmd = { 110 lpunpackPath, "-p", "system_a", superImg.getAbsolutePath(), outputDir.getAbsolutePath() 111 }; 112 Process p = Runtime.getRuntime().exec(cmd); 113 p.waitFor(); 114 if (p.exitValue() != 0) { 115 String stderr = StreamUtil.getStringFromStream(p.getErrorStream()); 116 Assert.fail(String.format("lpunpack returned %d. (%s)", p.exitValue(), stderr)); 117 } 118 return new File(outputDir, "system_a.img"); 119 } 120 121 @Before setUp()122 public void setUp() { 123 mTempDir = null; 124 } 125 126 @After tearDown()127 public void tearDown() { 128 FileUtil.recursiveDelete(mTempDir); 129 } 130 131 @Test testDSU()132 public void testDSU() throws Exception { 133 File systemImage; 134 if (mSystemImagePath != null) { 135 systemImage = new File(mSystemImagePath); 136 } else { 137 systemImage = extractSystemImageFromBuildInfo(getBuild()); 138 } 139 Assert.assertTrue("not a valid file", systemImage.isFile()); 140 141 if (SparseImageUtil.isSparse(systemImage)) { 142 File unsparseSystemImage = getTempPath("system.raw"); 143 SparseImageUtil.unsparse(systemImage, unsparseSystemImage); 144 systemImage = unsparseSystemImage; 145 } 146 147 boolean wasRoot = getDevice().isAdbRoot(); 148 if (!wasRoot) 149 Assert.assertTrue("Test requires root", getDevice().enableAdbRoot()); 150 151 assertDsuStatus("normal"); 152 153 // Sleep after installing to allow time for gsi_tool to reboot. This prevents a race between 154 // the device rebooting and waitForDeviceAvailable() returning. 155 getDevice() 156 .executeShellV2Command( 157 String.format( 158 "gsi_tool install --userdata-size %d" 159 + " --gsi-size %d" 160 + " && sleep 10000000", 161 getDsuUserdataSize(kDefaultUserdataSize), systemImage.length()), 162 systemImage, 163 null, 164 10, 165 TimeUnit.MINUTES, 166 1); 167 getDevice().waitForDeviceAvailable(); 168 getDevice().enableAdbRoot(); 169 170 assertDsuStatus("running"); 171 172 getDevice().rebootUntilOnline(); 173 174 assertDsuStatus("installed"); 175 176 assertShellCommand("gsi_tool enable"); 177 178 getDevice().reboot(); 179 180 assertDsuStatus("running"); 181 182 getDevice().reboot(); 183 184 assertDsuStatus("running"); 185 186 assertShellCommand("gsi_tool wipe"); 187 188 getDevice().rebootUntilOnline(); 189 190 assertDsuStatus("normal"); 191 192 if (wasRoot) { 193 getDevice().enableAdbRoot(); 194 } 195 } 196 } 197 198