1 /*
2  * Copyright (C) 2020 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.annotations.VisibleForTesting;
19 import com.android.tradefed.build.BuildInfoKey.BuildInfoFileKey;
20 import com.android.tradefed.config.IConfiguration;
21 import com.android.tradefed.config.IConfigurationReceiver;
22 import com.android.tradefed.config.Option;
23 import com.android.tradefed.config.remote.ExtendedFile;
24 import com.android.tradefed.dependency.TestDependencyResolver;
25 import com.android.tradefed.device.DeviceNotAvailableException;
26 import com.android.tradefed.device.ITestDevice;
27 import com.android.tradefed.invoker.ExecutionFiles;
28 import com.android.tradefed.invoker.IInvocationContext;
29 import com.android.tradefed.invoker.logger.CurrentInvocation;
30 import com.android.tradefed.invoker.logger.CurrentInvocation.InvocationInfo;
31 import com.android.tradefed.result.error.InfraErrorIdentifier;
32 import com.android.tradefed.targetprep.DeviceFlashPreparer;
33 import com.android.tradefed.targetprep.ITargetPreparer;
34 import com.android.tradefed.testtype.IInvocationContextReceiver;
35 import com.android.tradefed.util.FileUtil;
36 import com.android.tradefed.util.FlashingResourceUtil;
37 
38 import java.io.File;
39 import java.io.IOException;
40 import java.util.LinkedHashMap;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.Map.Entry;
44 
45 /** A new type of provider that allows to get all the dependencies for a test. */
46 public class DependenciesResolver
47         implements IBuildProvider,
48                 IDeviceBuildProvider,
49                 IInvocationContextReceiver,
50                 IConfigurationReceiver {
51 
52     @Option(name = "build-id", description = "build id to supply.")
53     private String mBuildId = "0";
54 
55     @Option(name = "branch", description = "build branch name to supply.")
56     private String mBranch = null;
57 
58     @Option(name = "build-flavor", description = "build flavor name to supply.")
59     private String mBuildFlavor = null;
60 
61     @Option(name = "build-os", description = "build os name to supply.")
62     private String mBuildOs = "linux";
63 
64     @Option(name = "dependency", description = "The set of dependency to provide for the test")
65     private Map<String, File> mDependencies = new LinkedHashMap<>();
66 
67     private File mTestsDir;
68     private IInvocationContext mInvocationContext;
69     private IConfiguration mConfiguration;
70 
71     @Override
getBuild(ITestDevice device)72     public IBuildInfo getBuild(ITestDevice device)
73             throws BuildRetrievalError, DeviceNotAvailableException {
74         IDeviceBuildInfo build =
75                 new DeviceBuildInfo(
76                         mBuildId, String.format("%s-%s-%s", mBranch, mBuildOs, mBuildFlavor));
77         build.setBuildBranch(mBranch);
78         build.setBuildFlavor(mBuildFlavor);
79         Map<String, File> mCopiedDependencies = new LinkedHashMap<>(mDependencies);
80         // Complete flashing dependencies
81         if (isFlasherEnabled(mConfiguration.getTargetPreparers())) {
82             completeFlashingDependencies(mCopiedDependencies);
83         }
84         // TODO: Resolve the extra files
85 
86         // Handle the flashing files
87         FlashingResourceUtil.setUpFlashingResources(build, mCopiedDependencies);
88         // Handle the remaining files
89         for (Entry<String, File> dependency : mCopiedDependencies.entrySet()) {
90             File f =
91                     TestDependencyResolver.resolveDependencyFromContext(
92                             dependency.getValue(), build, mInvocationContext);
93             if (f != null) {
94                 getInvocationFiles().put(dependency.getKey(), f);
95                 String version = "1";
96                 if (f instanceof ExtendedFile) {
97                     version = ((ExtendedFile) f).getBuildId();
98                 }
99                 build.setFile(dependency.getKey(), f, version);
100             }
101         }
102         // Create a tests dir if there are none
103         if (build.getTestsDir() == null) {
104             try {
105                 mTestsDir =
106                         FileUtil.createTempDir(
107                                 "bootstrap-dep-test-dir",
108                                 CurrentInvocation.getInfo(InvocationInfo.WORK_FOLDER));
109             } catch (IOException e) {
110                 throw new BuildRetrievalError(
111                         e.getMessage(), e, InfraErrorIdentifier.FAIL_TO_CREATE_FILE);
112             }
113             build.setTestsDir(mTestsDir, "1");
114         }
115         return build;
116     }
117 
118     @Override
getBuild()119     public IBuildInfo getBuild() throws BuildRetrievalError {
120         throw new IllegalArgumentException("Should not be called");
121     }
122 
123     @Override
cleanUp(IBuildInfo info)124     public void cleanUp(IBuildInfo info) {
125         info.cleanUp();
126     }
127 
128     @Override
setInvocationContext(IInvocationContext invocationContext)129     public void setInvocationContext(IInvocationContext invocationContext) {
130         mInvocationContext = invocationContext;
131     }
132 
133     @Override
setConfiguration(IConfiguration configuration)134     public void setConfiguration(IConfiguration configuration) {
135         mConfiguration = configuration;
136     }
137 
138     @VisibleForTesting
getDependencies()139     public final Map<String, File> getDependencies() {
140         return mDependencies;
141     }
142 
143     @VisibleForTesting
getInvocationFiles()144     ExecutionFiles getInvocationFiles() {
145         return CurrentInvocation.getInvocationFiles();
146     }
147 
148     /** Returns true if a flasher is present and enabled for the run. */
isFlasherEnabled(List<ITargetPreparer> preparers)149     private boolean isFlasherEnabled(List<ITargetPreparer> preparers) {
150         boolean flashing = false;
151         for (ITargetPreparer p : preparers) {
152             if (p instanceof DeviceFlashPreparer && !((DeviceFlashPreparer) p).isDisabled()) {
153                 flashing = true;
154             }
155         }
156         return flashing;
157     }
158 
completeFlashingDependencies(Map<String, File> dependencies)159     private void completeFlashingDependencies(Map<String, File> dependencies) {
160         if (dependencies.containsKey(BuildInfoFileKey.DEVICE_IMAGE.getFileKey())) {
161             return;
162         }
163         // Complete the dependencies to flash the device
164         String baseLink = String.format("ab://%s/%s/%s/", mBranch, mBuildFlavor, mBuildId);
165         dependencies.put(
166                 BuildInfoFileKey.DEVICE_IMAGE.getFileKey(), new File(baseLink + ".*-img-.*.zip"));
167         dependencies.put(
168                 BuildInfoFileKey.BOOTLOADER_IMAGE.getFileKey(),
169                 new File(baseLink + ".*bootloader.img"));
170         dependencies.put(
171                 BuildInfoFileKey.BASEBAND_IMAGE.getFileKey(), new File(baseLink + ".*radio.img"));
172         dependencies.put(
173                 BuildInfoFileKey.RAMDISK_IMAGE.getFileKey(), new File(baseLink + ".*ramdisk.img"));
174     }
175 }
176