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 package com.android.tradefed.sandbox; 17 18 import com.android.ddmlib.Log.LogLevel; 19 import com.android.tradefed.config.Configuration; 20 import com.android.tradefed.config.ConfigurationException; 21 import com.android.tradefed.config.GlobalConfiguration; 22 import com.android.tradefed.config.IConfiguration; 23 import com.android.tradefed.config.IDeviceConfiguration; 24 import com.android.tradefed.config.SandboxConfigurationFactory; 25 import com.android.tradefed.device.IDeviceSelection; 26 import com.android.tradefed.log.FileLogger; 27 import com.android.tradefed.log.ILeveledLogOutput; 28 import com.android.tradefed.result.ITestInvocationListener; 29 import com.android.tradefed.result.SubprocessResultsReporter; 30 import com.android.tradefed.result.proto.StreamProtoResultReporter; 31 import com.android.tradefed.util.StreamUtil; 32 33 import java.io.File; 34 import java.io.IOException; 35 import java.io.PrintWriter; 36 import java.util.ArrayList; 37 import java.util.Arrays; 38 import java.util.HashSet; 39 import java.util.List; 40 import java.util.Set; 41 42 /** 43 * Runner class that creates a {@link IConfiguration} based on a command line and dump it to a file. 44 * args: <DumpCmd> <output File> <remaing command line> 45 */ 46 public class SandboxConfigDump { 47 48 public enum DumpCmd { 49 /** The full xml based on the command line will be outputted */ 50 FULL_XML, 51 /** Only non-versioned element of the xml will be outputted */ 52 NON_VERSIONED_CONFIG, 53 /** A run-ready config will be outputted */ 54 RUN_CONFIG, 55 /** Special mode that allows the sandbox to generate another layer of sandboxing. */ 56 TEST_MODE, 57 } 58 59 /** 60 * We do not output the versioned elements to avoid causing the parent process to have issues 61 * with them when trying to resolve them 62 */ 63 public static final Set<String> VERSIONED_ELEMENTS = new HashSet<>(); 64 65 static { 66 VERSIONED_ELEMENTS.add(Configuration.SYSTEM_STATUS_CHECKER_TYPE_NAME); 67 VERSIONED_ELEMENTS.add(Configuration.DEVICE_METRICS_COLLECTOR_TYPE_NAME); 68 VERSIONED_ELEMENTS.add(Configuration.MULTI_PRE_TARGET_PREPARER_TYPE_NAME); 69 VERSIONED_ELEMENTS.add(Configuration.MULTI_PREPARER_TYPE_NAME); 70 VERSIONED_ELEMENTS.add(Configuration.TARGET_PREPARER_TYPE_NAME); 71 VERSIONED_ELEMENTS.add(Configuration.TEST_TYPE_NAME); 72 } 73 74 /** 75 * Parse the args and creates a {@link IConfiguration} from it then dumps it to the result file. 76 */ parse(String[] args)77 public int parse(String[] args) { 78 // TODO: add some more checking 79 List<String> argList = new ArrayList<>(Arrays.asList(args)); 80 DumpCmd cmd = DumpCmd.valueOf(argList.remove(0)); 81 File resFile = new File(argList.remove(0)); 82 SandboxConfigurationFactory factory = SandboxConfigurationFactory.getInstance(); 83 PrintWriter pw = null; 84 try { 85 IConfiguration config = 86 factory.createConfigurationFromArgs(argList.toArray(new String[0]), cmd); 87 if (DumpCmd.RUN_CONFIG.equals(cmd) || DumpCmd.TEST_MODE.equals(cmd)) { 88 config.getCommandOptions().setShouldUseSandboxing(false); 89 config.getConfigurationDescription().setSandboxed(true); 90 // Set the reporter 91 ITestInvocationListener reporter = null; 92 if (getSandboxOptions(config).shouldUseProtoReporter()) { 93 reporter = new StreamProtoResultReporter(); 94 } else { 95 reporter = new SubprocessResultsReporter(); 96 ((SubprocessResultsReporter) reporter).setOutputTestLog(true); 97 } 98 config.setTestInvocationListener(reporter); 99 // Set log level for sandbox 100 ILeveledLogOutput logger = config.getLogOutput(); 101 logger.setLogLevel(LogLevel.VERBOSE); 102 if (logger instanceof FileLogger) { 103 // Ensure we get the stdout logging in FileLogger case. 104 ((FileLogger) logger).setLogLevelDisplay(LogLevel.VERBOSE); 105 } 106 // Turn off some of the invocation level options that would be duplicated in the 107 // parent. 108 config.getCommandOptions().setBugreportOnInvocationEnded(false); 109 config.getCommandOptions().setBugreportzOnInvocationEnded(false); 110 111 // Ensure in special conditions (placeholder devices) we can still allocate. 112 secureDeviceAllocation(config); 113 } 114 if (DumpCmd.TEST_MODE.equals(cmd)) { 115 // We allow one more layer of sandbox to be generated 116 config.getCommandOptions().setShouldUseSandboxing(true); 117 config.getConfigurationDescription().setSandboxed(false); 118 // Ensure we turn off test mode afterward to avoid infinite sandboxing 119 config.getCommandOptions().setUseSandboxTestMode(false); 120 } 121 pw = new PrintWriter(resFile); 122 if (DumpCmd.NON_VERSIONED_CONFIG.equals(cmd)) { 123 // Remove elements that are versioned. 124 config.dumpXml(pw, new ArrayList<>(VERSIONED_ELEMENTS)); 125 } else { 126 // FULL_XML in that case. 127 config.dumpXml(pw); 128 } 129 } catch (ConfigurationException | IOException e) { 130 e.printStackTrace(); 131 return 1; 132 } finally { 133 StreamUtil.close(pw); 134 } 135 return 0; 136 } 137 main(final String[] mainArgs)138 public static void main(final String[] mainArgs) { 139 try { 140 GlobalConfiguration.createGlobalConfiguration(new String[] {}); 141 } catch (ConfigurationException e) { 142 e.printStackTrace(); 143 System.exit(1); 144 } 145 SandboxConfigDump configDump = new SandboxConfigDump(); 146 int code = configDump.parse(mainArgs); 147 System.exit(code); 148 } 149 getSandboxOptions(IConfiguration config)150 private SandboxOptions getSandboxOptions(IConfiguration config) { 151 return (SandboxOptions) 152 config.getConfigurationObject(Configuration.SANBOX_OPTIONS_TYPE_NAME); 153 } 154 secureDeviceAllocation(IConfiguration config)155 private void secureDeviceAllocation(IConfiguration config) { 156 for (IDeviceConfiguration deviceConfig : config.getDeviceConfig()) { 157 IDeviceSelection requirements = deviceConfig.getDeviceRequirements(); 158 if (requirements.nullDeviceRequested() 159 || requirements.tcpDeviceRequested() 160 || requirements.gceDeviceRequested()) { 161 // Reset serials, ensure any null/tcp/gce-device can be selected. 162 requirements.setSerial(); 163 } 164 } 165 } 166 } 167