1 /*
2  * Copyright (C) 2017 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 
17 package com.android.tradefed.util;
18 
19 import com.android.tradefed.build.IBuildInfo;
20 import com.android.tradefed.build.IDeviceBuildInfo;
21 import com.android.tradefed.log.LogUtil.CLog;
22 
23 import com.google.common.annotations.VisibleForTesting;
24 
25 import java.io.File;
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.List;
29 
30 
31 /** Utility class for making system calls. */
32 public class SystemUtil {
33 
34     @VisibleForTesting static SystemUtil singleton = new SystemUtil();
35 
36     // Environment variables for the test cases directory in target out directory and host out
37     // directory.
38     public enum EnvVariable {
39         ANDROID_TARGET_OUT_TESTCASES,
40         ANDROID_HOST_OUT_TESTCASES,
41     }
42 
43     static final String ENV_ANDROID_PRODUCT_OUT = "ANDROID_PRODUCT_OUT";
44 
45     private static final String HOST_TESTCASES = "host/testcases";
46     private static final String TARGET_TESTCASES = "target/testcases";
47 
48     /**
49      * Get the value of an environment variable.
50      *
51      * <p>The wrapper function is created for mock in unit test.
52      *
53      * @param name the name of the environment variable.
54      * @return {@link String} value of the given environment variable.
55      */
56     @VisibleForTesting
getEnv(String name)57     String getEnv(String name) {
58         return System.getenv(name);
59     }
60 
61     /** Get a list of {@link File} pointing to tests directories external to Tradefed. */
getExternalTestCasesDirs()62     public static List<File> getExternalTestCasesDirs() {
63         List<File> testCasesDirs = new ArrayList<File>();
64         // TODO(b/36782030): Support running both HOST and TARGET tests.
65         List<String> testCasesDirNames =
66                 // List order matters. ConfigurationFactory caller uses first dir with test config.
67                 Arrays.asList(
68                         singleton.getEnv(EnvVariable.ANDROID_TARGET_OUT_TESTCASES.name()),
69                         singleton.getEnv(EnvVariable.ANDROID_HOST_OUT_TESTCASES.name()));
70         for (String testCasesDirName : testCasesDirNames) {
71             if (testCasesDirName != null) {
72                 File dir = new File(testCasesDirName);
73                 if (dir.exists() && dir.isDirectory()) {
74                     CLog.d("Found test case dir: %s", testCasesDirName);
75                     testCasesDirs.add(dir);
76                 } else {
77                     CLog.w(
78                             "Path %s for test cases directory does not exist or it's not a "
79                                     + "directory.",
80                             testCasesDirName);
81                 }
82             }
83         }
84         return testCasesDirs;
85     }
86 
87     /**
88      * Get the file associated with the env. variable.
89      *
90      * @param envVariable ANDROID_TARGET_OUT_TESTCASES or ANDROID_HOST_OUT_TESTCASES
91      * @return The directory associated.
92      */
getExternalTestCasesDir(EnvVariable envVariable)93     public static File getExternalTestCasesDir(EnvVariable envVariable) {
94         String var = System.getenv(envVariable.name());
95         if (var == null) {
96             return null;
97         }
98         File dir = new File(var);
99         if (dir.exists() && dir.isDirectory()) {
100             CLog.d("Found test case dir: %s for %s.", dir.getAbsolutePath(), envVariable.name());
101             return dir;
102         }
103         return null;
104     }
105 
106     /**
107      * Get a list of {@link File} of the test cases directories
108      *
109      * @param buildInfo the build artifact information. Set it to null if build info is not
110      *     available or there is no need to get test cases directories from build info.
111      * @return a list of {@link File} of directories of the test cases folder of build output, based
112      *     on the value of environment variables and the given build info.
113      */
getTestCasesDirs(IBuildInfo buildInfo)114     public static List<File> getTestCasesDirs(IBuildInfo buildInfo) {
115         List<File> testCasesDirs = new ArrayList<File>();
116         testCasesDirs.addAll(getExternalTestCasesDirs());
117 
118         // TODO: Remove this logic after Versioned TF V2 is implemented, in which staging build
119         // artifact will be done by the parent process, and the test cases dirs will be set by
120         // environment variables.
121         // Add tests dir from build info.
122         if (buildInfo instanceof IDeviceBuildInfo) {
123             IDeviceBuildInfo deviceBuildInfo = (IDeviceBuildInfo) buildInfo;
124             File testsDir = deviceBuildInfo.getTestsDir();
125             // Add all possible paths to the testcases directory list.
126             if (testsDir != null) {
127                 testCasesDirs.addAll(
128                         Arrays.asList(
129                                 testsDir,
130                                 FileUtil.getFileForPath(testsDir, HOST_TESTCASES),
131                                 FileUtil.getFileForPath(testsDir, TARGET_TESTCASES)));
132             }
133         }
134 
135         return testCasesDirs;
136     }
137 
138     /**
139      * Gets the product specific output dir from an Android build tree. Typically this location
140      * contains images for various device partitions, bootloader, radio and so on.
141      *
142      * <p>Note: the method does not guarantee that this path exists.
143      *
144      * @return the location of the output dir or <code>null</code> if the current build is not
145      */
getProductOutputDir()146     public static File getProductOutputDir() {
147         String path = singleton.getEnv(ENV_ANDROID_PRODUCT_OUT);
148         if (path == null) {
149             return null;
150         } else {
151             return new File(path);
152         }
153     }
154 }
155