• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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