1 /*
2  * Copyright (C) 2018 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.invoker.sandbox;
17 
18 import com.android.tradefed.build.BuildInfoKey.BuildInfoFileKey;
19 import com.android.tradefed.build.BuildRetrievalError;
20 import com.android.tradefed.build.IBuildInfo;
21 import com.android.tradefed.build.IBuildProvider;
22 import com.android.tradefed.build.VersionedFile;
23 import com.android.tradefed.config.IConfiguration;
24 import com.android.tradefed.config.IDeviceConfiguration;
25 import com.android.tradefed.device.DeviceNotAvailableException;
26 import com.android.tradefed.invoker.ExecutionFiles;
27 import com.android.tradefed.invoker.ExecutionFiles.FilesKey;
28 import com.android.tradefed.invoker.IInvocationContext;
29 import com.android.tradefed.invoker.IRescheduler;
30 import com.android.tradefed.invoker.InvocationExecution;
31 import com.android.tradefed.invoker.TestInformation;
32 import com.android.tradefed.log.ITestLogger;
33 import com.android.tradefed.log.LogUtil.CLog;
34 import com.android.tradefed.result.ITestInvocationListener;
35 import com.android.tradefed.targetprep.ITargetPreparer;
36 import com.android.tradefed.testtype.IInvocationContextReceiver;
37 
38 import java.io.File;
39 import java.util.ArrayList;
40 import java.util.List;
41 
42 /**
43  * Special sandbox execution of the invocation: This is the InvocationExection for when we are
44  * inside the sandbox running the command. The build should already be available in the context.
45  */
46 public class SandboxedInvocationExecution extends InvocationExecution {
47 
48     /** {@inheritDoc} */
49     @Override
fetchBuild( TestInformation testInfo, IConfiguration config, IRescheduler rescheduler, ITestInvocationListener listener)50     public boolean fetchBuild(
51             TestInformation testInfo,
52             IConfiguration config,
53             IRescheduler rescheduler,
54             ITestInvocationListener listener)
55             throws DeviceNotAvailableException, BuildRetrievalError {
56         // If the invocation is currently sandboxed, builds have already been downloaded.
57         CLog.d("Skipping download in the sandbox.");
58         if (!config.getConfigurationDescription().shouldUseSandbox()) {
59             throw new RuntimeException(
60                     "We should only skip download if we are a sandbox. Something went very wrong.");
61         }
62         // Even if we don't call them directly here, ensure they receive their dependencies for the
63         // buildNotTested callback.
64         for (String deviceName : testInfo.getContext().getDeviceConfigNames()) {
65             IDeviceConfiguration deviceConfig = config.getDeviceConfigByName(deviceName);
66             IBuildProvider provider = deviceConfig.getBuildProvider();
67             // Inject the context to the provider if it can receive it
68             if (provider instanceof IInvocationContextReceiver) {
69                 ((IInvocationContextReceiver) provider).setInvocationContext(testInfo.getContext());
70             }
71         }
72 
73         // Still set the test-tag on build infos for proper reporting
74         for (IBuildInfo info : testInfo.getContext().getBuildInfos()) {
75             setTestTag(info, config);
76         }
77         backFillTestInformation(testInfo, testInfo.getBuildInfo());
78         return true;
79     }
80 
81     @Override
cleanUpBuilds(IInvocationContext context, IConfiguration config)82     public void cleanUpBuilds(IInvocationContext context, IConfiguration config) {
83         // Don't clean the build info in subprocess. Let the parents do it.
84     }
85 
86     /** {@inheritDoc} */
87     @Override
getTargetPreparersToRun( IConfiguration config, String deviceName)88     protected List<ITargetPreparer> getTargetPreparersToRun(
89             IConfiguration config, String deviceName) {
90         List<ITargetPreparer> preparersToRun = new ArrayList<>();
91         preparersToRun.addAll(config.getDeviceConfigByName(deviceName).getTargetPreparers());
92         return preparersToRun;
93     }
94 
95     /** {@inheritDoc} */
96     @Override
getLabPreparersToRun(IConfiguration config, String deviceName)97     protected List<ITargetPreparer> getLabPreparersToRun(IConfiguration config, String deviceName) {
98         return new ArrayList<>();
99     }
100 
101     /**
102      * In order for sandbox to work without currently receiving the parent TestInformation back-fill
103      * some information to find artifacts properly.
104      */
backFillTestInformation(TestInformation testInfo, IBuildInfo primaryBuild)105     private void backFillTestInformation(TestInformation testInfo, IBuildInfo primaryBuild) {
106         ExecutionFiles execFiles = testInfo.executionFiles();
107         if (execFiles.get(FilesKey.TESTS_DIRECTORY) == null) {
108             File testsDir = primaryBuild.getFile(BuildInfoFileKey.TESTDIR_IMAGE);
109             if (testsDir != null && testsDir.exists()) {
110                 execFiles.put(FilesKey.TESTS_DIRECTORY, testsDir, true);
111             }
112         }
113         if (execFiles.get(FilesKey.TARGET_TESTS_DIRECTORY) == null) {
114             File targetDir = primaryBuild.getFile(BuildInfoFileKey.TARGET_LINKED_DIR);
115             if (targetDir != null && targetDir.exists()) {
116                 execFiles.put(FilesKey.TARGET_TESTS_DIRECTORY, targetDir, true);
117             }
118         }
119         if (execFiles.get(FilesKey.HOST_TESTS_DIRECTORY) == null) {
120             File hostDir = primaryBuild.getFile(BuildInfoFileKey.HOST_LINKED_DIR);
121             if (hostDir != null && hostDir.exists()) {
122                 execFiles.put(FilesKey.HOST_TESTS_DIRECTORY, hostDir, true);
123             }
124         }
125         // Link the remaining buildInfo files.
126         for (String key : primaryBuild.getVersionedFileKeys()) {
127             VersionedFile versionedFile = primaryBuild.getVersionedFile(key);
128             if (versionedFile != null
129                     && versionedFile.getFile().exists()
130                     && !execFiles.containsKey(key)) {
131                 execFiles.put(key, versionedFile.getFile());
132             }
133         }
134     }
135 
136     @Override
logHostAdb(IConfiguration config, ITestLogger logger)137     protected void logHostAdb(IConfiguration config, ITestLogger logger) {
138         // Do nothing, the parent sandbox will log it.
139     }
140 }
141