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.IRescheduler;
29 import com.android.tradefed.invoker.InvocationExecution;
30 import com.android.tradefed.invoker.TestInformation;
31 import com.android.tradefed.log.LogUtil.CLog;
32 import com.android.tradefed.result.ITestInvocationListener;
33 import com.android.tradefed.testtype.IInvocationContextReceiver;
34 
35 import java.io.File;
36 
37 /**
38  * Special sandbox execution of the invocation: This is the InvocationExection for when we are
39  * inside the sandbox running the command. The build should already be available in the context.
40  */
41 public class SandboxedInvocationExecution extends InvocationExecution {
42 
43     /** {@inheritDoc} */
44     @Override
fetchBuild( TestInformation testInfo, IConfiguration config, IRescheduler rescheduler, ITestInvocationListener listener)45     public boolean fetchBuild(
46             TestInformation testInfo,
47             IConfiguration config,
48             IRescheduler rescheduler,
49             ITestInvocationListener listener)
50             throws DeviceNotAvailableException, BuildRetrievalError {
51         // If the invocation is currently sandboxed, builds have already been downloaded.
52         CLog.d("Skipping download in the sandbox.");
53         if (!config.getConfigurationDescription().shouldUseSandbox()) {
54             throw new RuntimeException(
55                     "We should only skip download if we are a sandbox. Something went very wrong.");
56         }
57         // Even if we don't call them directly here, ensure they receive their dependencies for the
58         // buildNotTested callback.
59         for (String deviceName : testInfo.getContext().getDeviceConfigNames()) {
60             IDeviceConfiguration deviceConfig = config.getDeviceConfigByName(deviceName);
61             IBuildProvider provider = deviceConfig.getBuildProvider();
62             // Inject the context to the provider if it can receive it
63             if (provider instanceof IInvocationContextReceiver) {
64                 ((IInvocationContextReceiver) provider).setInvocationContext(testInfo.getContext());
65             }
66         }
67 
68         // Still set the test-tag on build infos for proper reporting
69         for (IBuildInfo info : testInfo.getContext().getBuildInfos()) {
70             setTestTag(info, config);
71         }
72         backFillTestInformation(testInfo, testInfo.getBuildInfo());
73         return true;
74     }
75 
76     /**
77      * In order for sandbox to work without currently receiving the parent TestInformation back-fill
78      * some information to find artifacts properly.
79      */
backFillTestInformation(TestInformation testInfo, IBuildInfo primaryBuild)80     private void backFillTestInformation(TestInformation testInfo, IBuildInfo primaryBuild) {
81         ExecutionFiles execFiles = testInfo.executionFiles();
82         if (execFiles.get(FilesKey.TESTS_DIRECTORY) == null) {
83             File testsDir = primaryBuild.getFile(BuildInfoFileKey.TESTDIR_IMAGE);
84             if (testsDir != null && testsDir.exists()) {
85                 execFiles.put(FilesKey.TESTS_DIRECTORY, testsDir);
86             }
87         }
88         if (execFiles.get(FilesKey.TARGET_TESTS_DIRECTORY) == null) {
89             File targetDir = primaryBuild.getFile(BuildInfoFileKey.TARGET_LINKED_DIR);
90             if (targetDir != null && targetDir.exists()) {
91                 execFiles.put(FilesKey.TARGET_TESTS_DIRECTORY, targetDir, true);
92             }
93         }
94         if (execFiles.get(FilesKey.HOST_TESTS_DIRECTORY) == null) {
95             File hostDir = primaryBuild.getFile(BuildInfoFileKey.HOST_LINKED_DIR);
96             if (hostDir != null && hostDir.exists()) {
97                 execFiles.put(FilesKey.HOST_TESTS_DIRECTORY, hostDir, true);
98             }
99         }
100         // Link the remaining buildInfo files.
101         for (String key : primaryBuild.getVersionedFileKeys()) {
102             VersionedFile versionedFile = primaryBuild.getVersionedFile(key);
103             if (versionedFile != null
104                     && versionedFile.getFile().exists()
105                     && !execFiles.containsKey(key)) {
106                 execFiles.put(key, versionedFile.getFile());
107             }
108         }
109     }
110 }
111