1 /* 2 * Copyright (C) 2011 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 package com.android.tradefed.build; 17 18 import com.android.tradefed.config.Option; 19 import com.android.tradefed.config.OptionClass; 20 import com.android.tradefed.invoker.ExecutionFiles; 21 import com.android.tradefed.invoker.logger.CurrentInvocation; 22 import com.android.tradefed.log.LogUtil.CLog; 23 import com.android.tradefed.result.error.InfraErrorIdentifier; 24 import com.android.tradefed.targetprep.FlashingResourcesParser; 25 import com.android.tradefed.targetprep.IFlashingResourcesParser; 26 import com.android.tradefed.targetprep.TargetSetupError; 27 import com.android.tradefed.util.SystemUtil; 28 import com.android.tradefed.util.ZipUtil; 29 30 import com.google.common.annotations.VisibleForTesting; 31 import com.google.common.io.PatternFilenameFilter; 32 33 import java.io.File; 34 import java.io.IOException; 35 import java.util.ArrayList; 36 import java.util.Arrays; 37 import java.util.List; 38 39 /** 40 * A {@link IBuildProvider} that constructs a {@link IDeviceBuildInfo} based on a provided 41 * filesystem directory path. 42 * <p/> 43 * Specific device build files are recognized based on a configurable set of patterns. 44 */ 45 @OptionClass(alias = "local-device-build") 46 public class LocalDeviceBuildProvider extends StubBuildProvider { 47 48 private static final String BUILD_INFO_FILE = "android-info.txt"; 49 private static final String BUILD_DIR_OPTION_NAME = "build-dir"; 50 51 private String mBootloaderVersion = null; 52 private String mRadioVersion = null; 53 54 @Option(name = BUILD_DIR_OPTION_NAME, description = "the directory containing device files.") 55 private File mBuildDir = SystemUtil.getProductOutputDir(); 56 57 @Option(name = "device-img-pattern", description = 58 "the regex use to find device system image zip file within --build-dir.") 59 private String mImgPattern = ".*-img-.*\\.zip"; 60 61 @Option(name = "test-dir", description = "the directory containing test artifacts.") 62 private File mTestDir = null; 63 64 @Option(name = "test-dir-pattern", description = 65 "the regex use to find optional test artifact directory within --build-dir. " + 66 "Will be ignored if a test-dir is set.") 67 private String mTestDirPattern = ".*-tests-.*"; 68 69 @Option(name = "bootloader-pattern", description = 70 "the regex use to find device bootloader image file within --build-dir.") 71 private String mBootloaderPattern = "bootloader.*\\.img"; 72 73 @Option(name = "radio-pattern", description = 74 "the regex use to find device radio image file within --build-dir.") 75 private String mRadioPattern = "radio.*\\.img"; 76 77 /** 78 * {@inheritDoc} 79 */ 80 @Override getBuild()81 public IBuildInfo getBuild() throws BuildRetrievalError { 82 if (mBuildDir == null) { 83 throw new BuildRetrievalError( 84 "Product output directory is not specified. If running " 85 + "from a Android source tree, make sure `lunch` has been run; " 86 + "if outside, provide a valid path via --" 87 + BUILD_DIR_OPTION_NAME, 88 InfraErrorIdentifier.ARTIFACT_NOT_FOUND); 89 } 90 if (!mBuildDir.exists()) { 91 throw new BuildRetrievalError( 92 String.format( 93 "Directory '%s' does not exist. " 94 + "Please provide a valid path via --%s", 95 mBuildDir.getAbsolutePath(), BUILD_DIR_OPTION_NAME), 96 InfraErrorIdentifier.ARTIFACT_NOT_FOUND); 97 } 98 if (!mBuildDir.isDirectory()) { 99 throw new BuildRetrievalError( 100 String.format( 101 "Path '%s' is not a directory. " 102 + "Please provide a valid path via --%s", 103 mBuildDir.getAbsolutePath(), BUILD_DIR_OPTION_NAME), 104 InfraErrorIdentifier.ARTIFACT_NOT_FOUND); 105 } 106 CLog.d("Using device build files from %s", mBuildDir.getAbsolutePath()); 107 108 BuildInfo stubBuild = (BuildInfo)super.getBuild(); 109 DeviceBuildInfo buildInfo = new DeviceBuildInfo(stubBuild.getBuildId(), 110 stubBuild.getBuildTargetName()); 111 buildInfo.addAllBuildAttributes(stubBuild); 112 113 setDeviceImageFile(buildInfo); 114 parseBootloaderAndRadioVersions(buildInfo); 115 setTestsDir(buildInfo); 116 setBootloaderImage(buildInfo); 117 setRadioImage(buildInfo); 118 119 return buildInfo; 120 } 121 122 /** 123 * Parse bootloader and radio versions from the android build info file. 124 * 125 * @param buildInfo a {@link DeviceBuildInfo} 126 * @throws BuildRetrievalError 127 */ parseBootloaderAndRadioVersions(DeviceBuildInfo buildInfo)128 void parseBootloaderAndRadioVersions(DeviceBuildInfo buildInfo) throws BuildRetrievalError { 129 try { 130 IFlashingResourcesParser flashingResourcesParser; 131 flashingResourcesParser = new FlashingResourcesParser( 132 buildInfo.getDeviceImageFile()); 133 mBootloaderVersion = flashingResourcesParser.getRequiredBootloaderVersion(); 134 mRadioVersion = flashingResourcesParser.getRequiredBasebandVersion(); 135 } catch (TargetSetupError e) { 136 throw new BuildRetrievalError("Unable parse bootloader and radio versions", e); 137 } 138 } 139 140 /** 141 * Find and and set matching device image file to the build. 142 * 143 * @param buildInfo a {@link DeviceBuildInfo} to set the device image file 144 * @throws BuildRetrievalError 145 */ 146 @VisibleForTesting setDeviceImageFile(DeviceBuildInfo buildInfo)147 void setDeviceImageFile(DeviceBuildInfo buildInfo) throws BuildRetrievalError { 148 File deviceImgFile = findFileInDir(mImgPattern); 149 if (deviceImgFile == null) { 150 CLog.i("Unable to find build image zip on %s", mBuildDir.getAbsolutePath()); 151 deviceImgFile = createBuildImageZip(); 152 if (deviceImgFile == null) { 153 throw new BuildRetrievalError( 154 String.format( 155 "Could not find device image file matching matching '%s' in '%s'.", 156 mImgPattern, mBuildDir.getAbsolutePath()), 157 InfraErrorIdentifier.ARTIFACT_NOT_FOUND); 158 } 159 } 160 CLog.i("Set build image zip to %s", deviceImgFile.getAbsolutePath()); 161 buildInfo.setDeviceImageFile(deviceImgFile, buildInfo.getBuildId()); 162 } 163 164 /** 165 * Creates a build image zip file from the given build-dir 166 * 167 * @return the {@link File} referencing the zip output. 168 * @throws BuildRetrievalError 169 */ 170 @VisibleForTesting createBuildImageZip()171 File createBuildImageZip() throws BuildRetrievalError { 172 File zipFile = null; 173 File[] imageFiles = mBuildDir.listFiles(new PatternFilenameFilter(".*\\.img")); 174 File buildInfo = findFileInDir(BUILD_INFO_FILE); 175 List<File> buildFiles = new ArrayList<>(Arrays.asList(imageFiles)); 176 buildFiles.add(buildInfo); 177 try { 178 zipFile = ZipUtil.createZip(buildFiles); 179 } catch (IOException e) { 180 throw new BuildRetrievalError("Unable to create build image zip file", e); 181 } 182 CLog.i("Created build image zip on: %s", zipFile.getAbsolutePath()); 183 return zipFile; 184 } 185 setRadioImage(DeviceBuildInfo buildInfo)186 void setRadioImage(DeviceBuildInfo buildInfo) throws BuildRetrievalError { 187 File radioImgFile = findFileInDir(mRadioPattern); 188 if (radioImgFile != null) { 189 buildInfo.setBasebandImage(radioImgFile, mRadioVersion); 190 } 191 } 192 setBootloaderImage(DeviceBuildInfo buildInfo)193 void setBootloaderImage(DeviceBuildInfo buildInfo) throws BuildRetrievalError { 194 File bootloaderImgFile = findFileInDir(mBootloaderPattern); 195 if (bootloaderImgFile != null) { 196 buildInfo.setBootloaderImageFile(bootloaderImgFile, mBootloaderVersion); 197 } 198 } 199 200 /** 201 * Find and set a test directory to the build. 202 * 203 * @param buildInfo a {@link DeviceBuildInfo} to set the test directory 204 * @throws BuildRetrievalError 205 */ 206 @VisibleForTesting setTestsDir(DeviceBuildInfo buildInfo)207 void setTestsDir(DeviceBuildInfo buildInfo) throws BuildRetrievalError { 208 File testsDir = null; 209 // If test-dir is specified, use it 210 if (mTestDir != null) { 211 CLog.i("Looking for tests on %s", mTestDir.getAbsolutePath()); 212 testsDir = mTestDir; 213 } else { 214 CLog.i("Looking for tests on %s matching %s", mBuildDir.getAbsolutePath(), 215 mTestDirPattern); 216 testsDir = findFileInDir(mTestDirPattern); 217 } 218 if (testsDir != null) { 219 buildInfo.setTestsDir(testsDir, buildInfo.getBuildId()); 220 CLog.d("Using test files from %s", testsDir.getAbsolutePath()); 221 if (CurrentInvocation.getInvocationFiles() != null) { 222 CurrentInvocation.getInvocationFiles() 223 .put(ExecutionFiles.FilesKey.TESTS_DIRECTORY, testsDir); 224 } 225 } 226 } 227 228 /** 229 * Find a matching file in the build directory. 230 * 231 * @param regex Regular expression to match a file 232 * @return A matching {@link File} or null if none is found 233 * @throws BuildRetrievalError 234 */ 235 @VisibleForTesting findFileInDir(String regex)236 File findFileInDir(String regex) throws BuildRetrievalError { 237 return findFileInDir(regex, mBuildDir); 238 } 239 240 /** 241 * Find a matching file in a given directory. 242 * 243 * @param regex Regular expression to match a file 244 * @param dir a {@link File} referencing the directory to search 245 * @return A matching {@link File} or null if none is found 246 * @throws BuildRetrievalError 247 */ 248 @VisibleForTesting findFileInDir(String regex, File dir)249 File findFileInDir(String regex, File dir) throws BuildRetrievalError { 250 File[] files = dir.listFiles(new PatternFilenameFilter(regex)); 251 if (files.length == 0) { 252 return null; 253 } else if (files.length > 1) { 254 throw new BuildRetrievalError( 255 String.format( 256 "Found more than one file matching '%s' in '%s'.", 257 regex, mBuildDir.getAbsolutePath()), 258 InfraErrorIdentifier.ARTIFACT_NOT_FOUND); 259 } 260 return files[0]; 261 } 262 263 /** 264 * {@inheritDoc} 265 */ 266 @Override cleanUp(IBuildInfo info)267 public void cleanUp(IBuildInfo info) { 268 // ignore 269 } 270 getBootloaderVersion()271 String getBootloaderVersion() { 272 return mBootloaderVersion; 273 } 274 setBootloaderVersion(String bootloaderVersion)275 void setBootloaderVersion(String bootloaderVersion) { 276 mBootloaderVersion = bootloaderVersion; 277 } 278 getRadioVersion()279 String getRadioVersion() { 280 return mRadioVersion; 281 } 282 setRadioVersion(String radioVersion)283 void setRadioVersion(String radioVersion) { 284 mRadioVersion = radioVersion; 285 } 286 getBuildDir()287 File getBuildDir() { 288 return mBuildDir; 289 } 290 setBuildDir(File buildDir)291 void setBuildDir(File buildDir) { 292 this.mBuildDir = buildDir; 293 } 294 295 /** Returns the directory where the tests are located. */ getTestDir()296 public File getTestDir() { 297 return mTestDir; 298 } 299 setTestDir(File testDir)300 void setTestDir(File testDir) { 301 this.mTestDir = testDir; 302 } 303 getTestDirPattern()304 String getTestDirPattern() { 305 return mTestDirPattern; 306 } 307 setTestDirPattern(String testDirPattern)308 void setTestDirPattern(String testDirPattern) { 309 this.mTestDirPattern = testDirPattern; 310 } 311 } 312