1 /* 2 * Copyright (C) 2010 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.config; 18 19 import com.android.tradefed.build.BuildRetrievalError; 20 import com.android.tradefed.build.IBuildProvider; 21 import com.android.tradefed.command.CommandOptions; 22 import com.android.tradefed.command.ICommandOptions; 23 import com.android.tradefed.config.OptionSetter.FieldDef; 24 import com.android.tradefed.config.filter.GlobalTestFilter; 25 import com.android.tradefed.config.proxy.TradefedDelegator; 26 import com.android.tradefed.device.IDeviceRecovery; 27 import com.android.tradefed.device.IDeviceSelection; 28 import com.android.tradefed.device.TestDeviceOptions; 29 import com.android.tradefed.device.metric.IMetricCollector; 30 import com.android.tradefed.invoker.tracing.CloseableTraceScope; 31 import com.android.tradefed.log.ILeveledLogOutput; 32 import com.android.tradefed.log.LogUtil.CLog; 33 import com.android.tradefed.log.StdoutLogger; 34 import com.android.tradefed.postprocessor.BasePostProcessor; 35 import com.android.tradefed.postprocessor.IPostProcessor; 36 import com.android.tradefed.result.FileSystemLogSaver; 37 import com.android.tradefed.result.ILogSaver; 38 import com.android.tradefed.result.ITestInvocationListener; 39 import com.android.tradefed.result.TextResultReporter; 40 import com.android.tradefed.result.skipped.SkipManager; 41 import com.android.tradefed.retry.BaseRetryDecision; 42 import com.android.tradefed.retry.IRetryDecision; 43 import com.android.tradefed.sandbox.SandboxOptions; 44 import com.android.tradefed.sandbox.TradefedSandbox; 45 import com.android.tradefed.suite.checker.ISystemStatusChecker; 46 import com.android.tradefed.targetprep.ILabPreparer; 47 import com.android.tradefed.targetprep.ITargetPreparer; 48 import com.android.tradefed.targetprep.multi.IMultiTargetPreparer; 49 import com.android.tradefed.testtype.IRemoteTest; 50 import com.android.tradefed.testtype.StubTest; 51 import com.android.tradefed.testtype.coverage.CoverageOptions; 52 import com.android.tradefed.util.FileUtil; 53 import com.android.tradefed.util.IDisableable; 54 import com.android.tradefed.util.QuotationAwareTokenizer; 55 import com.android.tradefed.util.SystemUtil; 56 import com.android.tradefed.util.keystore.IKeyStoreClient; 57 58 import com.google.common.annotations.VisibleForTesting; 59 import com.google.common.collect.ImmutableSet; 60 61 import org.kxml2.io.KXmlSerializer; 62 63 import java.io.File; 64 import java.io.IOException; 65 import java.io.PrintStream; 66 import java.io.PrintWriter; 67 import java.lang.reflect.InvocationTargetException; 68 import java.util.ArrayList; 69 import java.util.Collection; 70 import java.util.HashMap; 71 import java.util.HashSet; 72 import java.util.LinkedHashMap; 73 import java.util.List; 74 import java.util.Map; 75 import java.util.Map.Entry; 76 import java.util.Set; 77 import java.util.regex.Matcher; 78 import java.util.regex.Pattern; 79 80 /** 81 * A concrete {@link IConfiguration} implementation that stores the loaded config objects in a map. 82 */ 83 public class Configuration implements IConfiguration { 84 85 // type names for built in configuration objects 86 public static final String BUILD_PROVIDER_TYPE_NAME = "build_provider"; 87 public static final String TARGET_PREPARER_TYPE_NAME = "target_preparer"; 88 public static final String LAB_PREPARER_TYPE_NAME = "lab_preparer"; 89 // Variation of Multi_target_preparer that runs BEFORE each device target_preparer. 90 public static final String MULTI_PRE_TARGET_PREPARER_TYPE_NAME = "multi_pre_target_preparer"; 91 public static final String MULTI_PREPARER_TYPE_NAME = "multi_target_preparer"; 92 public static final String TEST_TYPE_NAME = "test"; 93 public static final String DEVICE_RECOVERY_TYPE_NAME = "device_recovery"; 94 public static final String LOGGER_TYPE_NAME = "logger"; 95 public static final String LOG_SAVER_TYPE_NAME = "log_saver"; 96 public static final String RESULT_REPORTER_TYPE_NAME = "result_reporter"; 97 public static final String CMD_OPTIONS_TYPE_NAME = "cmd_options"; 98 public static final String DEVICE_REQUIREMENTS_TYPE_NAME = "device_requirements"; 99 public static final String DEVICE_OPTIONS_TYPE_NAME = "device_options"; 100 public static final String SYSTEM_STATUS_CHECKER_TYPE_NAME = "system_checker"; 101 public static final String CONFIGURATION_DESCRIPTION_TYPE_NAME = "config_desc"; 102 public static final String DEVICE_NAME = "device"; 103 public static final String DEVICE_METRICS_COLLECTOR_TYPE_NAME = "metrics_collector"; 104 public static final String METRIC_POST_PROCESSOR_TYPE_NAME = "metric_post_processor"; 105 public static final String SANDBOX_TYPE_NAME = "sandbox"; 106 public static final String SANBOX_OPTIONS_TYPE_NAME = "sandbox_options"; 107 public static final String RETRY_DECISION_TYPE_NAME = "retry_decision"; 108 public static final String COVERAGE_OPTIONS_TYPE_NAME = "coverage"; 109 public static final String GLOBAL_FILTERS_TYPE_NAME = "global_filters"; 110 public static final String SKIP_MANAGER_TYPE_NAME = "skip_manager"; 111 112 public static final Set<String> NON_MODULE_OBJECTS = 113 ImmutableSet.of( 114 BUILD_PROVIDER_TYPE_NAME, 115 CMD_OPTIONS_TYPE_NAME, 116 DEVICE_RECOVERY_TYPE_NAME, 117 LOGGER_TYPE_NAME, 118 LOG_SAVER_TYPE_NAME, 119 RESULT_REPORTER_TYPE_NAME, 120 SANDBOX_TYPE_NAME, 121 SANBOX_OPTIONS_TYPE_NAME, 122 RETRY_DECISION_TYPE_NAME, 123 GLOBAL_FILTERS_TYPE_NAME, 124 SKIP_MANAGER_TYPE_NAME); 125 126 private static Map<String, ObjTypeInfo> sObjTypeMap = null; 127 private static Set<String> sMultiDeviceSupportedTag = 128 ImmutableSet.of( 129 BUILD_PROVIDER_TYPE_NAME, 130 TARGET_PREPARER_TYPE_NAME, 131 LAB_PREPARER_TYPE_NAME, 132 DEVICE_RECOVERY_TYPE_NAME, 133 DEVICE_REQUIREMENTS_TYPE_NAME, 134 DEVICE_OPTIONS_TYPE_NAME); 135 // regexp pattern used to parse map option values 136 private static final Pattern OPTION_KEY_VALUE_PATTERN = Pattern.compile("(?<!\\\\)="); 137 138 private static final Pattern CONFIG_EXCEPTION_PATTERN = 139 Pattern.compile("Could not find option with name '(.*)'"); 140 141 /** Mapping of config object type name to config objects. */ 142 private Map<String, List<Object>> mConfigMap; 143 private final String mName; 144 private final String mDescription; 145 // original command line used to create this given configuration. 146 private String[] mCommandLine; 147 148 // Track options that had no effect 149 private Set<String> mInopOptions = new HashSet<>(); 150 151 // used to track the files that where dynamically downloaded 152 private Set<File> mRemoteFiles = new HashSet<>(); 153 154 /** 155 * Container struct for built-in config object type 156 */ 157 private static class ObjTypeInfo { 158 final Class<?> mExpectedType; 159 /** 160 * true if a list (ie many objects in a single config) are supported for this type 161 */ 162 final boolean mIsListSupported; 163 ObjTypeInfo(Class<?> expectedType, boolean isList)164 ObjTypeInfo(Class<?> expectedType, boolean isList) { 165 mExpectedType = expectedType; 166 mIsListSupported = isList; 167 } 168 } 169 170 /** 171 * Determine if given config object type name is a built in object 172 * 173 * @param typeName the config object type name 174 * @return <code>true</code> if name is a built in object type 175 */ isBuiltInObjType(String typeName)176 static boolean isBuiltInObjType(String typeName) { 177 return getObjTypeMap().containsKey(typeName); 178 } 179 getObjTypeMap()180 private static synchronized Map<String, ObjTypeInfo> getObjTypeMap() { 181 if (sObjTypeMap == null) { 182 sObjTypeMap = new HashMap<String, ObjTypeInfo>(); 183 sObjTypeMap.put(BUILD_PROVIDER_TYPE_NAME, new ObjTypeInfo(IBuildProvider.class, false)); 184 sObjTypeMap.put(TARGET_PREPARER_TYPE_NAME, 185 new ObjTypeInfo(ITargetPreparer.class, true)); 186 sObjTypeMap.put(LAB_PREPARER_TYPE_NAME, new ObjTypeInfo(ILabPreparer.class, true)); 187 sObjTypeMap.put( 188 MULTI_PRE_TARGET_PREPARER_TYPE_NAME, 189 new ObjTypeInfo(IMultiTargetPreparer.class, true)); 190 sObjTypeMap.put(MULTI_PREPARER_TYPE_NAME, 191 new ObjTypeInfo(IMultiTargetPreparer.class, true)); 192 sObjTypeMap.put(TEST_TYPE_NAME, new ObjTypeInfo(IRemoteTest.class, true)); 193 sObjTypeMap.put(DEVICE_RECOVERY_TYPE_NAME, 194 new ObjTypeInfo(IDeviceRecovery.class, false)); 195 sObjTypeMap.put(LOGGER_TYPE_NAME, new ObjTypeInfo(ILeveledLogOutput.class, false)); 196 sObjTypeMap.put(LOG_SAVER_TYPE_NAME, new ObjTypeInfo(ILogSaver.class, false)); 197 sObjTypeMap.put(RESULT_REPORTER_TYPE_NAME, 198 new ObjTypeInfo(ITestInvocationListener.class, true)); 199 sObjTypeMap.put(CMD_OPTIONS_TYPE_NAME, new ObjTypeInfo(ICommandOptions.class, 200 false)); 201 sObjTypeMap.put(DEVICE_REQUIREMENTS_TYPE_NAME, new ObjTypeInfo(IDeviceSelection.class, 202 false)); 203 sObjTypeMap.put(DEVICE_OPTIONS_TYPE_NAME, new ObjTypeInfo(TestDeviceOptions.class, 204 false)); 205 sObjTypeMap.put(DEVICE_NAME, new ObjTypeInfo(IDeviceConfiguration.class, true)); 206 sObjTypeMap.put(SYSTEM_STATUS_CHECKER_TYPE_NAME, 207 new ObjTypeInfo(ISystemStatusChecker.class, true)); 208 sObjTypeMap.put( 209 CONFIGURATION_DESCRIPTION_TYPE_NAME, 210 new ObjTypeInfo(ConfigurationDescriptor.class, false)); 211 sObjTypeMap.put( 212 DEVICE_METRICS_COLLECTOR_TYPE_NAME, 213 new ObjTypeInfo(IMetricCollector.class, true)); 214 sObjTypeMap.put( 215 METRIC_POST_PROCESSOR_TYPE_NAME, 216 new ObjTypeInfo(BasePostProcessor.class, true)); 217 sObjTypeMap.put(SANBOX_OPTIONS_TYPE_NAME, new ObjTypeInfo(SandboxOptions.class, false)); 218 sObjTypeMap.put(RETRY_DECISION_TYPE_NAME, new ObjTypeInfo(IRetryDecision.class, false)); 219 sObjTypeMap.put( 220 COVERAGE_OPTIONS_TYPE_NAME, new ObjTypeInfo(CoverageOptions.class, false)); 221 sObjTypeMap.put( 222 GLOBAL_FILTERS_TYPE_NAME, new ObjTypeInfo(GlobalTestFilter.class, false)); 223 sObjTypeMap.put(SKIP_MANAGER_TYPE_NAME, new ObjTypeInfo(SkipManager.class, false)); 224 } 225 return sObjTypeMap; 226 } 227 228 /** 229 * Determine if a given config object type is allowed to exists inside a device tag 230 * configuration. 231 * Authorized type are: build_provider, target_preparer, device_recovery, device_requirements, 232 * device_options 233 * 234 * @param typeName the config object type name 235 * @return True if name is allowed to exists inside the device tag 236 */ doesBuiltInObjSupportMultiDevice(String typeName)237 static boolean doesBuiltInObjSupportMultiDevice(String typeName) { 238 return getMultiDeviceSupportedTag().contains(typeName); 239 } 240 241 /** 242 * Return the {@link Set} of tags that are supported in a device tag for multi device 243 * configuration. 244 */ getMultiDeviceSupportedTag()245 public static synchronized Set<String> getMultiDeviceSupportedTag() { 246 return sMultiDeviceSupportedTag; 247 } 248 249 /** 250 * Creates an {@link Configuration} with default config objects. 251 */ Configuration(String name, String description)252 public Configuration(String name, String description) { 253 mName = name; 254 mDescription = description; 255 mConfigMap = new LinkedHashMap<String, List<Object>>(); 256 setDeviceConfig(new DeviceConfigurationHolder(ConfigurationDef.DEFAULT_DEVICE_NAME)); 257 setCommandOptions(new CommandOptions()); 258 setTest(new StubTest()); 259 setLogOutput(new StdoutLogger()); 260 setLogSaver(new FileSystemLogSaver()); // FileSystemLogSaver saves to tmp by default. 261 setTestInvocationListener(new TextResultReporter()); 262 // Init an empty list of target_preparers 263 setConfigurationObjectListNoThrow(TARGET_PREPARER_TYPE_NAME, new ArrayList<>()); 264 setConfigurationObjectListNoThrow(LAB_PREPARER_TYPE_NAME, new ArrayList<>()); 265 setMultiPreTargetPreparers(new ArrayList<>()); 266 setMultiTargetPreparers(new ArrayList<>()); 267 setSystemStatusCheckers(new ArrayList<ISystemStatusChecker>()); 268 setConfigurationDescriptor(new ConfigurationDescriptor()); 269 setDeviceMetricCollectors(new ArrayList<>()); 270 setPostProcessors(new ArrayList<>()); 271 setCoverageOptions(new CoverageOptions()); 272 setConfigurationObjectNoThrow(SANBOX_OPTIONS_TYPE_NAME, new SandboxOptions()); 273 setConfigurationObjectNoThrow(RETRY_DECISION_TYPE_NAME, new BaseRetryDecision()); 274 setConfigurationObjectNoThrow(GLOBAL_FILTERS_TYPE_NAME, new GlobalTestFilter()); 275 setConfigurationObjectNoThrow(SKIP_MANAGER_TYPE_NAME, new SkipManager()); 276 } 277 278 /** 279 * If we are in multi device mode, we cannot allow fetching the regular references because 280 * they are most likely wrong. 281 */ notAllowedInMultiMode(String function)282 private void notAllowedInMultiMode(String function) { 283 if (getConfigurationObjectList(DEVICE_NAME).size() > 1) { 284 throw new UnsupportedOperationException(String.format("Calling %s is not allowed " 285 + "in multi device mode", function)); 286 } 287 if (getConfigurationObjectList(DEVICE_NAME).isEmpty()) { 288 throw new UnsupportedOperationException( 289 "We should always have at least 1 Device config"); 290 } 291 } 292 293 /** {@inheritDoc} */ 294 @Override getName()295 public String getName() { 296 return mName; 297 } 298 299 /** 300 * @return a short user readable description this {@link Configuration} 301 */ getDescription()302 public String getDescription() { 303 return mDescription; 304 } 305 306 /** 307 * {@inheritDoc} 308 */ 309 @Override setCommandLine(String[] arrayArgs)310 public void setCommandLine(String[] arrayArgs) { 311 mCommandLine = arrayArgs; 312 } 313 314 /** 315 * {@inheritDoc} 316 */ 317 @Override getCommandLine()318 public String getCommandLine() { 319 // FIXME: obfuscated passwords from command line. 320 if (mCommandLine != null && mCommandLine.length != 0) { 321 return QuotationAwareTokenizer.combineTokens(mCommandLine); 322 } 323 // If no args were available return null. 324 return null; 325 } 326 327 /** 328 * {@inheritDoc} 329 */ 330 @SuppressWarnings("unchecked") 331 @Override getBuildProvider()332 public IBuildProvider getBuildProvider() { 333 notAllowedInMultiMode("getBuildProvider"); 334 return ((List<IDeviceConfiguration>)getConfigurationObjectList(DEVICE_NAME)) 335 .get(0).getBuildProvider(); 336 } 337 338 /** 339 * {@inheritDoc} 340 */ 341 @SuppressWarnings("unchecked") 342 @Override getTargetPreparers()343 public List<ITargetPreparer> getTargetPreparers() { 344 notAllowedInMultiMode("getTargetPreparers"); 345 return ((List<IDeviceConfiguration>)getConfigurationObjectList(DEVICE_NAME)) 346 .get(0).getTargetPreparers(); 347 } 348 349 /** {@inheritDoc} */ 350 @SuppressWarnings("unchecked") 351 @Override getLabPreparers()352 public List<ITargetPreparer> getLabPreparers() { 353 notAllowedInMultiMode("getLabPreparers"); 354 return ((List<IDeviceConfiguration>) getConfigurationObjectList(DEVICE_NAME)) 355 .get(0) 356 .getLabPreparers(); 357 } 358 359 /** 360 * {@inheritDoc} 361 */ 362 @SuppressWarnings("unchecked") 363 @Override getTests()364 public List<IRemoteTest> getTests() { 365 return (List<IRemoteTest>) getConfigurationObjectList(TEST_TYPE_NAME); 366 } 367 368 /** 369 * {@inheritDoc} 370 */ 371 @SuppressWarnings("unchecked") 372 @Override getDeviceRecovery()373 public IDeviceRecovery getDeviceRecovery() { 374 notAllowedInMultiMode("getDeviceRecovery"); 375 return ((List<IDeviceConfiguration>)getConfigurationObjectList(DEVICE_NAME)) 376 .get(0).getDeviceRecovery(); 377 } 378 379 /** 380 * {@inheritDoc} 381 */ 382 @Override getLogOutput()383 public ILeveledLogOutput getLogOutput() { 384 return (ILeveledLogOutput) getConfigurationObject(LOGGER_TYPE_NAME); 385 } 386 387 /** 388 * {@inheritDoc} 389 */ 390 @Override getLogSaver()391 public ILogSaver getLogSaver() { 392 return (ILogSaver) getConfigurationObject(LOG_SAVER_TYPE_NAME); 393 } 394 395 /** {@inheritDoc} */ 396 @Override getRetryDecision()397 public IRetryDecision getRetryDecision() { 398 return (IRetryDecision) getConfigurationObject(RETRY_DECISION_TYPE_NAME); 399 } 400 401 /** 402 * {@inheritDoc} 403 */ 404 @SuppressWarnings("unchecked") 405 @Override getMultiTargetPreparers()406 public List<IMultiTargetPreparer> getMultiTargetPreparers() { 407 return (List<IMultiTargetPreparer>) getConfigurationObjectList(MULTI_PREPARER_TYPE_NAME); 408 } 409 410 /** {@inheritDoc} */ 411 @SuppressWarnings("unchecked") 412 @Override getMultiPreTargetPreparers()413 public List<IMultiTargetPreparer> getMultiPreTargetPreparers() { 414 return (List<IMultiTargetPreparer>) 415 getConfigurationObjectList(MULTI_PRE_TARGET_PREPARER_TYPE_NAME); 416 } 417 418 /** 419 * {@inheritDoc} 420 */ 421 @SuppressWarnings("unchecked") 422 @Override getSystemStatusCheckers()423 public List<ISystemStatusChecker> getSystemStatusCheckers() { 424 return (List<ISystemStatusChecker>) 425 getConfigurationObjectList(SYSTEM_STATUS_CHECKER_TYPE_NAME); 426 } 427 428 /** 429 * {@inheritDoc} 430 */ 431 @SuppressWarnings("unchecked") 432 @Override getTestInvocationListeners()433 public List<ITestInvocationListener> getTestInvocationListeners() { 434 return (List<ITestInvocationListener>) getConfigurationObjectList( 435 RESULT_REPORTER_TYPE_NAME); 436 } 437 438 /** {@inheritDoc} */ 439 @SuppressWarnings("unchecked") 440 @Override getMetricCollectors()441 public List<IMetricCollector> getMetricCollectors() { 442 return (List<IMetricCollector>) 443 getConfigurationObjectList(DEVICE_METRICS_COLLECTOR_TYPE_NAME); 444 } 445 446 @SuppressWarnings("unchecked") 447 @Override getPostProcessors()448 public List<IPostProcessor> getPostProcessors() { 449 return (List<IPostProcessor>) getConfigurationObjectList(METRIC_POST_PROCESSOR_TYPE_NAME); 450 } 451 452 /** {@inheritDoc} */ 453 @Override getCommandOptions()454 public ICommandOptions getCommandOptions() { 455 return (ICommandOptions) getConfigurationObject(CMD_OPTIONS_TYPE_NAME); 456 } 457 458 /** {@inheritDoc} */ 459 @Override getConfigurationDescription()460 public ConfigurationDescriptor getConfigurationDescription() { 461 return (ConfigurationDescriptor) 462 getConfigurationObject(CONFIGURATION_DESCRIPTION_TYPE_NAME); 463 } 464 465 /** {@inheritDoc} */ 466 @SuppressWarnings("unchecked") 467 @Override getDeviceRequirements()468 public IDeviceSelection getDeviceRequirements() { 469 notAllowedInMultiMode("getDeviceRequirements"); 470 return ((List<IDeviceConfiguration>)getConfigurationObjectList(DEVICE_NAME)) 471 .get(0).getDeviceRequirements(); 472 } 473 474 /** 475 * {@inheritDoc} 476 */ 477 @SuppressWarnings("unchecked") 478 @Override getDeviceOptions()479 public TestDeviceOptions getDeviceOptions() { 480 notAllowedInMultiMode("getDeviceOptions"); 481 return ((List<IDeviceConfiguration>)getConfigurationObjectList(DEVICE_NAME)) 482 .get(0).getDeviceOptions(); 483 } 484 485 /** 486 * {@inheritDoc} 487 */ 488 @Override getConfigurationObjectList(String typeName)489 public List<?> getConfigurationObjectList(String typeName) { 490 return mConfigMap.get(typeName); 491 } 492 493 /** 494 * {@inheritDoc} 495 */ 496 @SuppressWarnings("unchecked") 497 @Override getDeviceConfigByName(String nameDevice)498 public IDeviceConfiguration getDeviceConfigByName(String nameDevice) { 499 for (IDeviceConfiguration deviceHolder : 500 (List<IDeviceConfiguration>)getConfigurationObjectList(DEVICE_NAME)) { 501 if (deviceHolder.getDeviceName().equals(nameDevice)) { 502 return deviceHolder; 503 } 504 } 505 return null; 506 } 507 508 /** 509 * {@inheritDoc} 510 */ 511 @SuppressWarnings("unchecked") 512 @Override getDeviceConfig()513 public List<IDeviceConfiguration> getDeviceConfig() { 514 return (List<IDeviceConfiguration>)getConfigurationObjectList(DEVICE_NAME); 515 } 516 517 /** {@inheritDoc} */ 518 @SuppressWarnings("unchecked") 519 @Override getCoverageOptions()520 public CoverageOptions getCoverageOptions() { 521 return (CoverageOptions) getConfigurationObject(COVERAGE_OPTIONS_TYPE_NAME); 522 } 523 524 /** {@inheritDoc} */ 525 @SuppressWarnings("unchecked") 526 @Override getGlobalFilters()527 public GlobalTestFilter getGlobalFilters() { 528 return (GlobalTestFilter) getConfigurationObject(GLOBAL_FILTERS_TYPE_NAME); 529 } 530 531 /** {@inheritDoc} */ 532 @SuppressWarnings("unchecked") 533 @Override getSkipManager()534 public SkipManager getSkipManager() { 535 return (SkipManager) getConfigurationObject(SKIP_MANAGER_TYPE_NAME); 536 } 537 538 /** 539 * {@inheritDoc} 540 */ 541 @Override getConfigurationObject(String typeName)542 public Object getConfigurationObject(String typeName) { 543 List<?> configObjects = getConfigurationObjectList(typeName); 544 if (configObjects == null) { 545 return null; 546 } 547 ObjTypeInfo typeInfo = getObjTypeMap().get(typeName); 548 if (typeInfo != null && typeInfo.mIsListSupported) { 549 throw new IllegalStateException( 550 String.format( 551 "Wrong method call for type %s. Used getConfigurationObject() for a " 552 + "config object that is stored as a list", 553 typeName)); 554 } 555 if (configObjects.size() != 1) { 556 throw new IllegalStateException(String.format( 557 "Attempted to retrieve single object for %s, but %d are present", 558 typeName, configObjects.size())); 559 } 560 return configObjects.get(0); 561 } 562 563 /** {@inheritDoc} */ 564 @Override getAllConfigurationObjectsOfType(String configType)565 public Collection<Object> getAllConfigurationObjectsOfType(String configType) { 566 Collection<Object> objectsCopy = new ArrayList<Object>(); 567 if (doesBuiltInObjSupportMultiDevice(configType)) { 568 for (IDeviceConfiguration deviceConfig : getDeviceConfig()) { 569 objectsCopy.addAll(deviceConfig.getAllObjectOfType(configType)); 570 } 571 } else { 572 List<?> configObjects = getConfigurationObjectList(configType); 573 if (configObjects != null) { 574 objectsCopy.addAll(configObjects); 575 } 576 } 577 return objectsCopy; 578 } 579 580 /** 581 * Return a copy of all config objects 582 */ getAllConfigurationObjects()583 private Collection<Object> getAllConfigurationObjects() { 584 return getAllConfigurationObjects(null, true); 585 } 586 587 /** 588 * Return a copy of all config objects, minus the object configuration of the type specified. 589 * Returns all the config objects if param is null. 590 */ getAllConfigurationObjects( String excludedConfigName, boolean includeDisabled)591 private Collection<Object> getAllConfigurationObjects( 592 String excludedConfigName, boolean includeDisabled) { 593 Collection<Object> objectsCopy = new ArrayList<Object>(); 594 for (Entry<String, List<Object>> entryList : mConfigMap.entrySet()) { 595 if (excludedConfigName != null && excludedConfigName.equals(entryList.getKey())) { 596 continue; 597 } 598 if (includeDisabled) { 599 objectsCopy.addAll(entryList.getValue()); 600 } else { 601 for (Object o : entryList.getValue()) { 602 if (o instanceof IDisableable && ((IDisableable) o).isDisabled()) { 603 continue; 604 } 605 objectsCopy.add(o); 606 } 607 } 608 } 609 return objectsCopy; 610 } 611 612 /** Return a copy of all config objects that are not disabled via {@link IDisableable}. */ getAllNonDisabledConfigurationObjects()613 private Collection<Object> getAllNonDisabledConfigurationObjects() { 614 String excluded = null; 615 // Inside the sandbox disable lab preparers 616 if (System.getenv(TradefedSandbox.SANDBOX_ENABLED) != null) { 617 excluded = LAB_PREPARER_TYPE_NAME; 618 } 619 return getAllConfigurationObjects(excluded, false); 620 } 621 622 /** 623 * Creates an OptionSetter which is appropriate for setting options on all objects which 624 * will be returned by {@link #getAllConfigurationObjects}. 625 */ createOptionSetter()626 private OptionSetter createOptionSetter() throws ConfigurationException { 627 return new OptionSetter(getAllConfigurationObjects()); 628 } 629 630 /** 631 * Injects an option value into the set of configuration objects. 632 * 633 * Uses provided arguments as is and fails if arguments have invalid format or 634 * provided ambiguously, e.g. {@code optionKey} argument is provided for non-map option, 635 * or the value for an option of integer type cannot be parsed as an integer number. 636 * 637 * @param optionSetter setter to use for the injection 638 * @param optionName name of the option 639 * @param optionKey map key, if the option is of map type 640 * @param optionValue value of the option or map value, if the option is of map type 641 * @param source source of the option 642 * @throws ConfigurationException if option value cannot be injected 643 */ internalInjectOptionValue(OptionSetter optionSetter, String optionName, String optionKey, String optionValue, String source)644 private void internalInjectOptionValue(OptionSetter optionSetter, String optionName, 645 String optionKey, String optionValue, String source) throws ConfigurationException { 646 if (optionSetter == null) { 647 throw new IllegalArgumentException("optionSetter cannot be null"); 648 } 649 650 // Set all fields that match this option name / key 651 List<FieldDef> affectedFields = optionSetter.setOptionValue( 652 optionName, optionKey, optionValue); 653 654 boolean requiredForRerun = false; 655 // Update the source for each affected field 656 for (FieldDef field : affectedFields) { 657 requiredForRerun |= field.field.getAnnotation(Option.class).requiredForRerun(); 658 if (requiredForRerun) { 659 // Only need to check if the option is required for rerun once if it's set to true. 660 break; 661 } 662 } 663 664 if (requiredForRerun) { 665 OptionDef optionDef = new OptionDef(optionName, optionKey, optionValue, source, null); 666 getConfigurationDescription().addRerunOption(optionDef); 667 } 668 } 669 670 /** 671 * Injects an option value into the set of configuration objects. 672 * 673 * If the option to be set is of map type, an attempt to parse {@code optionValue} argument 674 * into key-value pair is made. In this case {@code optionValue} must have an equal sign 675 * separating a key and a value (e.g. my_key=my_value). 676 * In case a key or a value themselves contain an equal sign, this equal sign in them 677 * must be escaped using a backslash (e.g. a\=b=y\=z). 678 * 679 * @param optionSetter setter to use for the injection 680 * @param optionName name of the option 681 * @param optionValue value of the option 682 * @throws ConfigurationException if option value cannot be injected 683 */ internalInjectOptionValue(OptionSetter optionSetter, String optionName, String optionValue)684 private void internalInjectOptionValue(OptionSetter optionSetter, String optionName, 685 String optionValue) throws ConfigurationException { 686 // Cannot continue without optionSetter 687 if (optionSetter == null) { 688 throw new IllegalArgumentException("optionSetter cannot be null"); 689 } 690 691 // If the option is not a map, then the key is null... 692 if (!optionSetter.isMapOption(optionName)) { 693 internalInjectOptionValue(optionSetter, optionName, null, optionValue, null); 694 return; 695 } 696 697 // ..., otherwise try to parse the value to retrieve the key 698 String[] parts = OPTION_KEY_VALUE_PATTERN.split(optionValue); 699 if (parts.length != 2) { 700 throw new ConfigurationException(String.format( 701 "option '%s' has an invalid format for value %s:w", 702 optionName, optionValue)); 703 } 704 internalInjectOptionValue(optionSetter, optionName, 705 parts[0].replace("\\\\=", "="), parts[1].replace("\\\\=", "="), null); 706 } 707 708 /** 709 * {@inheritDoc} 710 */ 711 @Override injectOptionValue(String optionName, String optionValue)712 public void injectOptionValue(String optionName, String optionValue) 713 throws ConfigurationException { 714 internalInjectOptionValue(createOptionSetter(), optionName, optionValue); 715 } 716 717 /** 718 * {@inheritDoc} 719 */ 720 @Override injectOptionValue(String optionName, String optionKey, String optionValue)721 public void injectOptionValue(String optionName, String optionKey, String optionValue) 722 throws ConfigurationException { 723 internalInjectOptionValue(createOptionSetter(), optionName, optionKey, optionValue, null); 724 } 725 726 /** 727 * {@inheritDoc} 728 */ 729 @Override injectOptionValueWithSource(String optionName, String optionKey, String optionValue, String source)730 public void injectOptionValueWithSource(String optionName, String optionKey, String optionValue, 731 String source) throws ConfigurationException { 732 internalInjectOptionValue(createOptionSetter(), optionName, optionKey, optionValue, source); 733 } 734 735 /** 736 * {@inheritDoc} 737 */ 738 @Override injectOptionValues(List<OptionDef> optionDefs)739 public void injectOptionValues(List<OptionDef> optionDefs) throws ConfigurationException { 740 if (optionDefs.isEmpty()) { 741 return; 742 } 743 OptionSetter optionSetter = createOptionSetter(); 744 for (OptionDef optionDef : optionDefs) { 745 internalInjectOptionValue(optionSetter, optionDef.name, optionDef.key, optionDef.value, 746 optionDef.source); 747 } 748 } 749 750 /** {@inheritDoc} */ 751 @Override safeInjectOptionValues(List<OptionDef> optionDefs)752 public void safeInjectOptionValues(List<OptionDef> optionDefs) throws ConfigurationException { 753 if (optionDefs.isEmpty()) { 754 return; 755 } 756 OptionSetter optionSetter = createOptionSetter(); 757 for (OptionDef optionDef : optionDefs) { 758 try { 759 internalInjectOptionValue( 760 optionSetter, 761 optionDef.name, 762 optionDef.key, 763 optionDef.value, 764 optionDef.source); 765 } catch (ConfigurationException e) { 766 // Ignoring 767 } 768 } 769 } 770 771 /** 772 * Creates a shallow copy of this object. 773 */ 774 @Override clone()775 public Configuration clone() { 776 Configuration clone = new Configuration(getName(), getDescription()); 777 for (Map.Entry<String, List<Object>> entry : mConfigMap.entrySet()) { 778 if (DEVICE_NAME.equals(entry.getKey())) { 779 List<Object> newDeviceConfigList = new ArrayList<Object>(); 780 for (Object deviceConfig : entry.getValue()) { 781 IDeviceConfiguration config = ((IDeviceConfiguration) deviceConfig); 782 IDeviceConfiguration newDeviceConfig = config.clone(); 783 newDeviceConfigList.add(newDeviceConfig); 784 } 785 clone.setConfigurationObjectListNoThrow(entry.getKey(), newDeviceConfigList); 786 } else { 787 clone.setConfigurationObjectListNoThrow(entry.getKey(), entry.getValue()); 788 } 789 } 790 clone.setCommandLine(this.mCommandLine); 791 return clone; 792 } 793 794 /** {@inheritDoc} */ 795 @Override partialDeepClone(List<String> objectToDeepClone, IKeyStoreClient client)796 public IConfiguration partialDeepClone(List<String> objectToDeepClone, IKeyStoreClient client) 797 throws ConfigurationException { 798 Configuration clonedConfig = this.clone(); 799 List<String> objToDeepClone = new ArrayList<>(objectToDeepClone); 800 if (objectToDeepClone.contains(Configuration.DEVICE_NAME)) { 801 objToDeepClone.remove(Configuration.DEVICE_NAME); 802 objToDeepClone.addAll(getMultiDeviceSupportedTag()); 803 } 804 for (String objType : objToDeepClone) { 805 if (doesBuiltInObjSupportMultiDevice(objType)) { 806 for (int i = 0; i < clonedConfig.getDeviceConfig().size(); i++) { 807 IDeviceConfiguration deepCopyConfig = clonedConfig.getDeviceConfig().get(i); 808 List<?> listOfType = 809 cloneListTFObject(deepCopyConfig.getAllObjectOfType(objType)); 810 clonedConfig.getDeviceConfig().get(i).removeObjectType(objType); 811 for (Object o : listOfType) { 812 clonedConfig.getDeviceConfig().get(i).addSpecificConfig(o, objType); 813 if (o instanceof IConfigurationReceiver) { 814 ((IConfigurationReceiver) o).setConfiguration(clonedConfig); 815 } 816 } 817 } 818 } else { 819 clonedConfig.setConfigurationObjectList( 820 objType, 821 cloneListTFObject(clonedConfig.getConfigurationObjectList(objType))); 822 } 823 } 824 return clonedConfig; 825 } 826 cloneListTFObject(List<?> objects)827 private List<?> cloneListTFObject(List<?> objects) throws ConfigurationException { 828 List<Object> copiedList = new ArrayList<>(); 829 for (Object o : objects) { 830 copiedList.add(cloneTFobject(o)); 831 } 832 return copiedList; 833 } 834 cloneTFobject(Object o)835 private Object cloneTFobject(Object o) throws ConfigurationException { 836 try { 837 Object clone = o.getClass().getConstructor().newInstance(); 838 OptionCopier.copyOptions(o, clone); 839 return clone; 840 } catch (InstantiationException 841 | IllegalAccessException 842 | IllegalArgumentException 843 | InvocationTargetException 844 | NoSuchMethodException 845 | SecurityException e) { 846 // Shouldn't happen, except in unit tests 847 throw new ConfigurationException(String.format("Failed to copy %s", o), e); 848 } 849 } 850 addToDefaultDeviceConfig(Object obj, String type)851 private void addToDefaultDeviceConfig(Object obj, String type) { 852 try { 853 getDeviceConfigByName(ConfigurationDef.DEFAULT_DEVICE_NAME) 854 .addSpecificConfig(obj, type); 855 } catch (ConfigurationException e) { 856 // should never happen 857 throw new IllegalArgumentException(e); 858 } 859 } 860 861 /** 862 * {@inheritDoc} 863 */ 864 @Override setBuildProvider(IBuildProvider provider)865 public void setBuildProvider(IBuildProvider provider) { 866 notAllowedInMultiMode("setBuildProvider"); 867 addToDefaultDeviceConfig(provider, BUILD_PROVIDER_TYPE_NAME); 868 } 869 870 /** 871 * {@inheritDoc} 872 */ 873 @Override setTestInvocationListeners(List<ITestInvocationListener> listeners)874 public void setTestInvocationListeners(List<ITestInvocationListener> listeners) { 875 setConfigurationObjectListNoThrow(RESULT_REPORTER_TYPE_NAME, listeners); 876 } 877 878 /** {@inheritDoc} */ 879 @Override setDeviceMetricCollectors(List<IMetricCollector> collectors)880 public void setDeviceMetricCollectors(List<IMetricCollector> collectors) { 881 setConfigurationObjectListNoThrow(DEVICE_METRICS_COLLECTOR_TYPE_NAME, collectors); 882 } 883 884 /** {@inheritDoc} */ 885 @Override setPostProcessors(List<IPostProcessor> processors)886 public void setPostProcessors(List<IPostProcessor> processors) { 887 setConfigurationObjectListNoThrow(METRIC_POST_PROCESSOR_TYPE_NAME, processors); 888 } 889 890 /** 891 * {@inheritDoc} 892 */ 893 @Override setTestInvocationListener(ITestInvocationListener listener)894 public void setTestInvocationListener(ITestInvocationListener listener) { 895 setConfigurationObjectNoThrow(RESULT_REPORTER_TYPE_NAME, listener); 896 } 897 898 /** 899 * {@inheritDoc} 900 */ 901 @Override setDeviceConfig(IDeviceConfiguration deviceConfig)902 public void setDeviceConfig(IDeviceConfiguration deviceConfig) { 903 setConfigurationObjectNoThrow(DEVICE_NAME, deviceConfig); 904 } 905 906 /** 907 * {@inheritDoc} 908 */ 909 @Override setDeviceConfigList(List<IDeviceConfiguration> deviceConfigs)910 public void setDeviceConfigList(List<IDeviceConfiguration> deviceConfigs) { 911 setConfigurationObjectListNoThrow(DEVICE_NAME, deviceConfigs); 912 } 913 914 /** {@inheritDoc} */ 915 @Override setCoverageOptions(CoverageOptions coverageOptions)916 public void setCoverageOptions(CoverageOptions coverageOptions) { 917 setConfigurationObjectNoThrow(COVERAGE_OPTIONS_TYPE_NAME, coverageOptions); 918 } 919 920 /** 921 * {@inheritDoc} 922 */ 923 @Override setTest(IRemoteTest test)924 public void setTest(IRemoteTest test) { 925 setConfigurationObjectNoThrow(TEST_TYPE_NAME, test); 926 } 927 928 /** 929 * {@inheritDoc} 930 */ 931 @Override setTests(List<IRemoteTest> tests)932 public void setTests(List<IRemoteTest> tests) { 933 setConfigurationObjectListNoThrow(TEST_TYPE_NAME, tests); 934 } 935 936 /** 937 * {@inheritDoc} 938 */ 939 @Override setMultiTargetPreparers(List<IMultiTargetPreparer> multiTargPreps)940 public void setMultiTargetPreparers(List<IMultiTargetPreparer> multiTargPreps) { 941 setConfigurationObjectListNoThrow(MULTI_PREPARER_TYPE_NAME, multiTargPreps); 942 } 943 944 /** 945 * {@inheritDoc} 946 */ 947 @Override setMultiTargetPreparer(IMultiTargetPreparer multiTargPrep)948 public void setMultiTargetPreparer(IMultiTargetPreparer multiTargPrep) { 949 setConfigurationObjectNoThrow(MULTI_PREPARER_TYPE_NAME, multiTargPrep); 950 } 951 952 /** {@inheritDoc} */ 953 @Override setMultiPreTargetPreparers(List<IMultiTargetPreparer> multiPreTargPreps)954 public void setMultiPreTargetPreparers(List<IMultiTargetPreparer> multiPreTargPreps) { 955 setConfigurationObjectListNoThrow(MULTI_PRE_TARGET_PREPARER_TYPE_NAME, multiPreTargPreps); 956 } 957 958 /** {@inheritDoc} */ 959 @Override setMultiPreTargetPreparer(IMultiTargetPreparer multiPreTargPrep)960 public void setMultiPreTargetPreparer(IMultiTargetPreparer multiPreTargPrep) { 961 setConfigurationObjectNoThrow(MULTI_PRE_TARGET_PREPARER_TYPE_NAME, multiPreTargPrep); 962 } 963 964 /** 965 * {@inheritDoc} 966 */ 967 @Override setSystemStatusCheckers(List<ISystemStatusChecker> systemCheckers)968 public void setSystemStatusCheckers(List<ISystemStatusChecker> systemCheckers) { 969 setConfigurationObjectListNoThrow(SYSTEM_STATUS_CHECKER_TYPE_NAME, systemCheckers); 970 } 971 972 /** 973 * {@inheritDoc} 974 */ 975 @Override setSystemStatusChecker(ISystemStatusChecker systemChecker)976 public void setSystemStatusChecker(ISystemStatusChecker systemChecker) { 977 setConfigurationObjectNoThrow(SYSTEM_STATUS_CHECKER_TYPE_NAME, systemChecker); 978 } 979 980 /** {@inheritDoc} */ 981 @Override setLogOutput(ILeveledLogOutput logger)982 public void setLogOutput(ILeveledLogOutput logger) { 983 setConfigurationObjectNoThrow(LOGGER_TYPE_NAME, logger); 984 } 985 986 /** {@inheritDoc} */ 987 @Override setLogSaver(ILogSaver logSaver)988 public void setLogSaver(ILogSaver logSaver) { 989 setConfigurationObjectNoThrow(LOG_SAVER_TYPE_NAME, logSaver); 990 } 991 992 /** {@inheritDoc} */ 993 @Override setRetryDecision(IRetryDecision decisionRetry)994 public void setRetryDecision(IRetryDecision decisionRetry) { 995 setConfigurationObjectNoThrow(RETRY_DECISION_TYPE_NAME, decisionRetry); 996 } 997 998 /** Sets the {@link ConfigurationDescriptor} to be used in the configuration. */ setConfigurationDescriptor(ConfigurationDescriptor configDescriptor)999 private void setConfigurationDescriptor(ConfigurationDescriptor configDescriptor) { 1000 setConfigurationObjectNoThrow(CONFIGURATION_DESCRIPTION_TYPE_NAME, configDescriptor); 1001 } 1002 1003 /** {@inheritDoc} */ 1004 @Override setDeviceRecovery(IDeviceRecovery recovery)1005 public void setDeviceRecovery(IDeviceRecovery recovery) { 1006 notAllowedInMultiMode("setDeviceRecovery"); 1007 addToDefaultDeviceConfig(recovery, DEVICE_RECOVERY_TYPE_NAME); 1008 } 1009 1010 /** 1011 * {@inheritDoc} 1012 */ 1013 @Override setTargetPreparer(ITargetPreparer preparer)1014 public void setTargetPreparer(ITargetPreparer preparer) { 1015 notAllowedInMultiMode("setTargetPreparer"); 1016 addToDefaultDeviceConfig(preparer, TARGET_PREPARER_TYPE_NAME); 1017 } 1018 1019 /** {@inheritDoc} */ 1020 @Override setTargetPreparers(List<ITargetPreparer> preparers)1021 public void setTargetPreparers(List<ITargetPreparer> preparers) { 1022 notAllowedInMultiMode("setTargetPreparers"); 1023 getDeviceConfigByName(ConfigurationDef.DEFAULT_DEVICE_NAME).getTargetPreparers().clear(); 1024 for (ITargetPreparer prep : preparers) { 1025 addToDefaultDeviceConfig(prep, TARGET_PREPARER_TYPE_NAME); 1026 } 1027 } 1028 1029 /** {@inheritDoc} */ 1030 @Override setLabPreparer(ITargetPreparer preparer)1031 public void setLabPreparer(ITargetPreparer preparer) { 1032 notAllowedInMultiMode("setLabPreparer"); 1033 addToDefaultDeviceConfig(preparer, LAB_PREPARER_TYPE_NAME); 1034 } 1035 1036 /** {@inheritDoc} */ 1037 @Override setLabPreparers(List<ITargetPreparer> preparers)1038 public void setLabPreparers(List<ITargetPreparer> preparers) { 1039 notAllowedInMultiMode("setLabPreparers"); 1040 getDeviceConfigByName(ConfigurationDef.DEFAULT_DEVICE_NAME).getLabPreparers().clear(); 1041 for (ITargetPreparer prep : preparers) { 1042 addToDefaultDeviceConfig(prep, LAB_PREPARER_TYPE_NAME); 1043 } 1044 } 1045 1046 /** 1047 * {@inheritDoc} 1048 */ 1049 @Override setCommandOptions(ICommandOptions cmdOptions)1050 public void setCommandOptions(ICommandOptions cmdOptions) { 1051 setConfigurationObjectNoThrow(CMD_OPTIONS_TYPE_NAME, cmdOptions); 1052 } 1053 1054 /** 1055 * {@inheritDoc} 1056 */ 1057 @Override setDeviceRequirements(IDeviceSelection devRequirements)1058 public void setDeviceRequirements(IDeviceSelection devRequirements) { 1059 notAllowedInMultiMode("setDeviceRequirements"); 1060 addToDefaultDeviceConfig(devRequirements, DEVICE_REQUIREMENTS_TYPE_NAME); 1061 } 1062 1063 /** 1064 * {@inheritDoc} 1065 */ 1066 @Override setDeviceOptions(TestDeviceOptions devOptions)1067 public void setDeviceOptions(TestDeviceOptions devOptions) { 1068 notAllowedInMultiMode("setDeviceOptions"); 1069 addToDefaultDeviceConfig(devOptions, DEVICE_OPTIONS_TYPE_NAME); 1070 } 1071 1072 /** 1073 * {@inheritDoc} 1074 */ 1075 @Override setConfigurationObject(String typeName, Object configObject)1076 public synchronized void setConfigurationObject(String typeName, Object configObject) 1077 throws ConfigurationException { 1078 if (configObject == null) { 1079 throw new IllegalArgumentException("configObject cannot be null"); 1080 } 1081 mConfigMap.remove(typeName); 1082 addObject(typeName, configObject); 1083 } 1084 1085 /** 1086 * {@inheritDoc} 1087 */ 1088 @Override setConfigurationObjectList(String typeName, List<?> configList)1089 public synchronized void setConfigurationObjectList(String typeName, List<?> configList) 1090 throws ConfigurationException { 1091 if (configList == null) { 1092 throw new IllegalArgumentException("configList cannot be null"); 1093 } 1094 mConfigMap.remove(typeName); 1095 mConfigMap.put(typeName, new ArrayList<Object>(1)); 1096 for (Object configObject : configList) { 1097 addObject(typeName, configObject); 1098 } 1099 } 1100 1101 /** {@inheritDoc} */ 1102 @Override isDeviceConfiguredFake(String deviceName)1103 public boolean isDeviceConfiguredFake(String deviceName) { 1104 IDeviceConfiguration deviceConfig = getDeviceConfigByName(deviceName); 1105 if (deviceConfig == null) { 1106 return false; 1107 } 1108 return deviceConfig.isFake(); 1109 } 1110 1111 /** 1112 * Adds a loaded object to this configuration. 1113 * 1114 * @param typeName the unique object type name of the configuration object 1115 * @param configObject the configuration object 1116 * @throws ConfigurationException if object was not the correct type 1117 */ addObject(String typeName, Object configObject)1118 private synchronized void addObject(String typeName, Object configObject) 1119 throws ConfigurationException { 1120 List<Object> objList = mConfigMap.get(typeName); 1121 if (objList == null) { 1122 objList = new ArrayList<Object>(1); 1123 mConfigMap.put(typeName, objList); 1124 } 1125 ObjTypeInfo typeInfo = getObjTypeMap().get(typeName); 1126 if (typeInfo != null && !typeInfo.mExpectedType.isInstance(configObject)) { 1127 throw new ConfigurationException(String.format( 1128 "The config object %s is not the correct type. Expected %s, received %s", 1129 typeName, typeInfo.mExpectedType.getCanonicalName(), 1130 configObject.getClass().getCanonicalName())); 1131 } 1132 if (typeInfo != null && !typeInfo.mIsListSupported && objList.size() > 0) { 1133 throw new ConfigurationException(String.format( 1134 "Only one config object allowed for %s, but multiple were specified.", 1135 typeName)); 1136 } 1137 objList.add(configObject); 1138 if (configObject instanceof IConfigurationReceiver) { 1139 ((IConfigurationReceiver) configObject).setConfiguration(this); 1140 } 1141 // Inject to object inside device holder too. 1142 if (configObject instanceof IDeviceConfiguration) { 1143 for (Object obj : ((IDeviceConfiguration) configObject).getAllObjects()) { 1144 if (obj instanceof IConfigurationReceiver) { 1145 ((IConfigurationReceiver) obj).setConfiguration(this); 1146 } 1147 } 1148 } 1149 } 1150 1151 /** 1152 * A wrapper around {@link #setConfigurationObject(String, Object)} that 1153 * will not throw {@link ConfigurationException}. 1154 * <p/> 1155 * Intended to be used in cases where its guaranteed that 1156 * <var>configObject</var> is the correct type. 1157 * 1158 * @param typeName 1159 * @param configObject 1160 */ setConfigurationObjectNoThrow(String typeName, Object configObject)1161 private void setConfigurationObjectNoThrow(String typeName, Object configObject) { 1162 try { 1163 setConfigurationObject(typeName, configObject); 1164 } catch (ConfigurationException e) { 1165 // should never happen 1166 throw new IllegalArgumentException(e); 1167 } 1168 } 1169 1170 /** 1171 * A wrapper around {@link #setConfigurationObjectList(String, List)} that 1172 * will not throw {@link ConfigurationException}. 1173 * <p/> 1174 * Intended to be used in cases where its guaranteed that 1175 * <var>configObject</var> is the correct type 1176 * 1177 * @param typeName 1178 * @param configList 1179 */ setConfigurationObjectListNoThrow(String typeName, List<?> configList)1180 private void setConfigurationObjectListNoThrow(String typeName, List<?> configList) { 1181 try { 1182 setConfigurationObjectList(typeName, configList); 1183 } catch (ConfigurationException e) { 1184 // should never happen 1185 throw new IllegalArgumentException(e); 1186 } 1187 } 1188 1189 /** 1190 * {@inheritDoc} 1191 */ 1192 @Override setOptionsFromCommandLineArgs(List<String> listArgs)1193 public List<String> setOptionsFromCommandLineArgs(List<String> listArgs) 1194 throws ConfigurationException { 1195 return setOptionsFromCommandLineArgs(listArgs, null); 1196 } 1197 1198 /** 1199 * {@inheritDoc} 1200 */ 1201 @Override setOptionsFromCommandLineArgs(List<String> listArgs, IKeyStoreClient keyStoreClient)1202 public List<String> setOptionsFromCommandLineArgs(List<String> listArgs, 1203 IKeyStoreClient keyStoreClient) 1204 throws ConfigurationException { 1205 try (CloseableTraceScope ignored = 1206 new CloseableTraceScope("setOptionsFromCommandLineArgs")) { 1207 // We get all the objects except the one describing the Configuration itself which does 1208 // not 1209 // allow passing its option via command line. 1210 ArgsOptionParser parser = 1211 new ArgsOptionParser( 1212 getAllConfigurationObjects(CONFIGURATION_DESCRIPTION_TYPE_NAME, true)); 1213 if (keyStoreClient != null) { 1214 parser.setKeyStore(keyStoreClient); 1215 } 1216 try { 1217 List<String> leftOver = parser.parse(listArgs); 1218 mInopOptions.addAll(parser.getInopOptions()); 1219 return leftOver; 1220 } catch (ConfigurationException e) { 1221 Matcher m = CONFIG_EXCEPTION_PATTERN.matcher(e.getMessage()); 1222 if (!m.matches()) { 1223 throw e; 1224 } 1225 String optionName = m.group(1); 1226 try { 1227 // In case the option exists in the config descriptor, we change the error 1228 // message 1229 // to be more specific about why the option is rejected. 1230 OptionSetter setter = new OptionSetter(getConfigurationDescription()); 1231 setter.getTypeForOption(optionName); 1232 } catch (ConfigurationException stillThrowing) { 1233 // Throw the original exception since it cannot be found at all. 1234 throw e; 1235 } 1236 throw new OptionNotAllowedException( 1237 String.format( 1238 "Option '%s' cannot be specified via " 1239 + "command line. Only in the configuration xml.", 1240 optionName)); 1241 } 1242 } 1243 } 1244 1245 /** {@inheritDoc} */ 1246 @Override setBestEffortOptionsFromCommandLineArgs( List<String> listArgs, IKeyStoreClient keyStoreClient)1247 public List<String> setBestEffortOptionsFromCommandLineArgs( 1248 List<String> listArgs, IKeyStoreClient keyStoreClient) throws ConfigurationException { 1249 // We get all the objects except the one describing the Configuration itself which does not 1250 // allow passing its option via command line. 1251 ArgsOptionParser parser = 1252 new ArgsOptionParser( 1253 getAllConfigurationObjects(CONFIGURATION_DESCRIPTION_TYPE_NAME, true)); 1254 if (keyStoreClient != null) { 1255 parser.setKeyStore(keyStoreClient); 1256 } 1257 return parser.parseBestEffort(listArgs, /* Force continue */ true); 1258 } 1259 1260 /** 1261 * Outputs a command line usage help text for this configuration to given 1262 * printStream. 1263 * 1264 * @param out the {@link PrintStream} to use. 1265 * @throws ConfigurationException 1266 */ 1267 @Override printCommandUsage(boolean importantOnly, PrintStream out)1268 public void printCommandUsage(boolean importantOnly, PrintStream out) 1269 throws ConfigurationException { 1270 out.println(String.format("'%s' configuration: %s", getName(), getDescription())); 1271 out.println(); 1272 if (importantOnly) { 1273 out.println("Printing help for only the important options. " + 1274 "To see help for all options, use the --help-all flag"); 1275 out.println(); 1276 } 1277 for (Map.Entry<String, List<Object>> configObjectsEntry : mConfigMap.entrySet()) { 1278 for (Object configObject : configObjectsEntry.getValue()) { 1279 if (configObject instanceof IDeviceConfiguration) { 1280 // We expand the Device Config Object. 1281 for (Object subconfigObject : ((IDeviceConfiguration)configObject) 1282 .getAllObjects()) { 1283 printCommandUsageForObject(importantOnly, out, configObjectsEntry.getKey(), 1284 subconfigObject); 1285 } 1286 } else { 1287 printCommandUsageForObject(importantOnly, out, configObjectsEntry.getKey(), 1288 configObject); 1289 } 1290 } 1291 } 1292 } 1293 printCommandUsageForObject(boolean importantOnly, PrintStream out, String key, Object obj)1294 private void printCommandUsageForObject(boolean importantOnly, PrintStream out, String key, 1295 Object obj) throws ConfigurationException { 1296 String optionHelp = printOptionsForObject(importantOnly, key, obj); 1297 // only print help for object if optionHelp is non zero length 1298 if (optionHelp.length() > 0) { 1299 String classAlias = ""; 1300 if (obj.getClass().isAnnotationPresent(OptionClass.class)) { 1301 final OptionClass classAnnotation = obj.getClass().getAnnotation( 1302 OptionClass.class); 1303 classAlias = String.format("'%s' ", classAnnotation.alias()); 1304 } 1305 out.printf(" %s%s options:", classAlias, key); 1306 out.println(); 1307 out.print(optionHelp); 1308 out.println(); 1309 } 1310 } 1311 1312 /** 1313 * Prints out the available config options for given configuration object. 1314 * 1315 * @param importantOnly print only the important options 1316 * @param objectTypeName the config object type name. Used to generate more 1317 * descriptive error messages 1318 * @param configObject the config object 1319 * @return a {@link String} of option help text 1320 * @throws ConfigurationException 1321 */ printOptionsForObject(boolean importantOnly, String objectTypeName, Object configObject)1322 private String printOptionsForObject(boolean importantOnly, String objectTypeName, 1323 Object configObject) throws ConfigurationException { 1324 return ArgsOptionParser.getOptionHelp(importantOnly, configObject); 1325 } 1326 1327 /** 1328 * {@inheritDoc} 1329 */ 1330 @Override validateOptions()1331 public void validateOptions() throws ConfigurationException { 1332 ArgsOptionParser argsParser = new ArgsOptionParser(getAllNonDisabledConfigurationObjects()); 1333 argsParser.validateMandatoryOptions(); 1334 ICommandOptions options = getCommandOptions(); 1335 if (options.getShardCount() != null && options.getShardCount() < 1) { 1336 throw new ConfigurationException("a shard count must be a positive number"); 1337 } 1338 if (options.getShardIndex() != null 1339 && (options.getShardCount() == null || options.getShardIndex() < 0 1340 || options.getShardIndex() >= options.getShardCount())) { 1341 throw new ConfigurationException("a shard index must be in range [0, shard count)"); 1342 } 1343 } 1344 1345 /** {@inheritDoc} */ 1346 @Override resolveDynamicOptions(DynamicRemoteFileResolver resolver)1347 public void resolveDynamicOptions(DynamicRemoteFileResolver resolver) 1348 throws ConfigurationException, BuildRetrievalError { 1349 List<Object> configObjects = new ArrayList<>(getAllNonDisabledConfigurationObjects()); 1350 // Resolve regardless of sharding if we are in remote environment because we know that's 1351 // where the execution will occur. 1352 if (!isRemoteEnvironment()) { 1353 ICommandOptions options = getCommandOptions(); 1354 if (getConfigurationObject(TradefedDelegator.DELEGATE_OBJECT) != null) { 1355 configObjects.clear(); 1356 configObjects.add(getConfigurationObject(TradefedDelegator.DELEGATE_OBJECT)); 1357 CLog.d("Resolving only delegator object dynamic download."); 1358 } else if (options.getShardCount() != null 1359 && options.getShardCount() > 1 1360 && options.getShardIndex() == null 1361 && !getCommandOptions().shouldUseSandboxing() 1362 && !getCommandOptions().shouldUseRemoteSandboxMode()) { 1363 CLog.w("Skipping dynamic download due to local sharding detected."); 1364 return; 1365 } 1366 } 1367 1368 ArgsOptionParser argsParser = new ArgsOptionParser(configObjects); 1369 CLog.d("Resolve and download remote files from @Option"); 1370 // Setup and validate the GCS File paths 1371 mRemoteFiles.addAll(argsParser.validateRemoteFilePath(resolver)); 1372 } 1373 1374 /** Returns whether or not the environment of TF is a remote invocation. */ 1375 @VisibleForTesting isRemoteEnvironment()1376 protected boolean isRemoteEnvironment() { 1377 return SystemUtil.isRemoteEnvironment(); 1378 } 1379 1380 /** {@inheritDoc} */ 1381 @Override cleanConfigurationData()1382 public void cleanConfigurationData() { 1383 for (File file : mRemoteFiles) { 1384 FileUtil.recursiveDelete(file); 1385 } 1386 mRemoteFiles.clear(); 1387 } 1388 1389 /** {@inheritDoc} */ 1390 @Override addFilesToClean(Set<File> toBeCleaned)1391 public void addFilesToClean(Set<File> toBeCleaned) { 1392 mRemoteFiles.addAll(toBeCleaned); 1393 } 1394 1395 /** {@inheritDoc} */ 1396 @Override getFilesToClean()1397 public Set<File> getFilesToClean() { 1398 return mRemoteFiles; 1399 } 1400 1401 /** {@inheritDoc} */ 1402 @Override getInopOptions()1403 public Set<String> getInopOptions() { 1404 return mInopOptions; 1405 } 1406 1407 /** 1408 * {@inheritDoc} 1409 */ 1410 @Override dumpXml(PrintWriter output)1411 public void dumpXml(PrintWriter output) throws IOException { 1412 dumpXml(output, new ArrayList<String>()); 1413 } 1414 1415 /** {@inheritDoc} */ 1416 @Override dumpXml(PrintWriter output, List<String> excludeFilters)1417 public void dumpXml(PrintWriter output, List<String> excludeFilters) throws IOException { 1418 dumpXml(output, excludeFilters, true, true); 1419 } 1420 1421 /** {@inheritDoc} */ 1422 @Override dumpXml( PrintWriter output, List<String> excludeFilters, boolean printDeprecatedOptions, boolean printUnchangedOptions)1423 public void dumpXml( 1424 PrintWriter output, 1425 List<String> excludeFilters, 1426 boolean printDeprecatedOptions, 1427 boolean printUnchangedOptions) 1428 throws IOException { 1429 KXmlSerializer serializer = new KXmlSerializer(); 1430 serializer.setOutput(output); 1431 serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); 1432 serializer.startDocument("UTF-8", null); 1433 serializer.startTag(null, ConfigurationUtil.CONFIGURATION_NAME); 1434 1435 for (IMultiTargetPreparer multiPreTargerPrep : getMultiPreTargetPreparers()) { 1436 ConfigurationUtil.dumpClassToXml( 1437 serializer, 1438 MULTI_PRE_TARGET_PREPARER_TYPE_NAME, 1439 multiPreTargerPrep, 1440 excludeFilters, 1441 printDeprecatedOptions, 1442 printUnchangedOptions); 1443 output.flush(); 1444 } 1445 1446 for (IMultiTargetPreparer multipreparer : getMultiTargetPreparers()) { 1447 ConfigurationUtil.dumpClassToXml( 1448 serializer, 1449 MULTI_PREPARER_TYPE_NAME, 1450 multipreparer, 1451 excludeFilters, 1452 printDeprecatedOptions, 1453 printUnchangedOptions); 1454 } 1455 1456 if (getDeviceConfig().size() > 1) { 1457 // Handle multi device. 1458 for (IDeviceConfiguration deviceConfig : getDeviceConfig()) { 1459 serializer.startTag(null, Configuration.DEVICE_NAME); 1460 serializer.attribute(null, "name", deviceConfig.getDeviceName()); 1461 if (deviceConfig.isFake()) { 1462 serializer.attribute(null, "isFake", "true"); 1463 } 1464 ConfigurationUtil.dumpClassToXml( 1465 serializer, 1466 BUILD_PROVIDER_TYPE_NAME, 1467 deviceConfig.getBuildProvider(), 1468 excludeFilters, 1469 printDeprecatedOptions, 1470 printUnchangedOptions); 1471 for (ITargetPreparer preparer : deviceConfig.getTargetPreparers()) { 1472 ConfigurationUtil.dumpClassToXml( 1473 serializer, 1474 TARGET_PREPARER_TYPE_NAME, 1475 preparer, 1476 excludeFilters, 1477 printDeprecatedOptions, 1478 printUnchangedOptions); 1479 } 1480 for (ITargetPreparer preparer : deviceConfig.getLabPreparers()) { 1481 ConfigurationUtil.dumpClassToXml( 1482 serializer, 1483 LAB_PREPARER_TYPE_NAME, 1484 preparer, 1485 excludeFilters, 1486 printDeprecatedOptions, 1487 printUnchangedOptions); 1488 } 1489 ConfigurationUtil.dumpClassToXml( 1490 serializer, 1491 DEVICE_RECOVERY_TYPE_NAME, 1492 deviceConfig.getDeviceRecovery(), 1493 excludeFilters, 1494 printDeprecatedOptions, 1495 printUnchangedOptions); 1496 ConfigurationUtil.dumpClassToXml( 1497 serializer, 1498 DEVICE_REQUIREMENTS_TYPE_NAME, 1499 deviceConfig.getDeviceRequirements(), 1500 excludeFilters, 1501 printDeprecatedOptions, 1502 printUnchangedOptions); 1503 ConfigurationUtil.dumpClassToXml( 1504 serializer, 1505 DEVICE_OPTIONS_TYPE_NAME, 1506 deviceConfig.getDeviceOptions(), 1507 excludeFilters, 1508 printDeprecatedOptions, 1509 printUnchangedOptions); 1510 serializer.endTag(null, Configuration.DEVICE_NAME); 1511 } 1512 } else { 1513 // Put single device tags 1514 ConfigurationUtil.dumpClassToXml( 1515 serializer, 1516 BUILD_PROVIDER_TYPE_NAME, 1517 getBuildProvider(), 1518 excludeFilters, 1519 printDeprecatedOptions, 1520 printUnchangedOptions); 1521 for (ITargetPreparer preparer : getLabPreparers()) { 1522 ConfigurationUtil.dumpClassToXml( 1523 serializer, 1524 LAB_PREPARER_TYPE_NAME, 1525 preparer, 1526 excludeFilters, 1527 printDeprecatedOptions, 1528 printUnchangedOptions); 1529 } 1530 for (ITargetPreparer preparer : getTargetPreparers()) { 1531 ConfigurationUtil.dumpClassToXml( 1532 serializer, 1533 TARGET_PREPARER_TYPE_NAME, 1534 preparer, 1535 excludeFilters, 1536 printDeprecatedOptions, 1537 printUnchangedOptions); 1538 } 1539 ConfigurationUtil.dumpClassToXml( 1540 serializer, 1541 DEVICE_RECOVERY_TYPE_NAME, 1542 getDeviceRecovery(), 1543 excludeFilters, 1544 printDeprecatedOptions, 1545 printUnchangedOptions); 1546 ConfigurationUtil.dumpClassToXml( 1547 serializer, 1548 DEVICE_REQUIREMENTS_TYPE_NAME, 1549 getDeviceRequirements(), 1550 excludeFilters, 1551 printDeprecatedOptions, 1552 printUnchangedOptions); 1553 ConfigurationUtil.dumpClassToXml( 1554 serializer, 1555 DEVICE_OPTIONS_TYPE_NAME, 1556 getDeviceOptions(), 1557 excludeFilters, 1558 printDeprecatedOptions, 1559 printUnchangedOptions); 1560 } 1561 for (IRemoteTest test : getTests()) { 1562 ConfigurationUtil.dumpClassToXml( 1563 serializer, 1564 TEST_TYPE_NAME, 1565 test, 1566 excludeFilters, 1567 printDeprecatedOptions, 1568 printUnchangedOptions); 1569 } 1570 ConfigurationUtil.dumpClassToXml( 1571 serializer, 1572 CONFIGURATION_DESCRIPTION_TYPE_NAME, 1573 getConfigurationDescription(), 1574 excludeFilters, 1575 printDeprecatedOptions, 1576 printUnchangedOptions); 1577 ConfigurationUtil.dumpClassToXml( 1578 serializer, 1579 LOGGER_TYPE_NAME, 1580 getLogOutput(), 1581 excludeFilters, 1582 printDeprecatedOptions, 1583 printUnchangedOptions); 1584 ConfigurationUtil.dumpClassToXml( 1585 serializer, 1586 LOG_SAVER_TYPE_NAME, 1587 getLogSaver(), 1588 excludeFilters, 1589 printDeprecatedOptions, 1590 printUnchangedOptions); 1591 for (ITestInvocationListener listener : getTestInvocationListeners()) { 1592 ConfigurationUtil.dumpClassToXml( 1593 serializer, 1594 RESULT_REPORTER_TYPE_NAME, 1595 listener, 1596 excludeFilters, 1597 printDeprecatedOptions, 1598 printUnchangedOptions); 1599 } 1600 ConfigurationUtil.dumpClassToXml( 1601 serializer, 1602 CMD_OPTIONS_TYPE_NAME, 1603 getCommandOptions(), 1604 excludeFilters, 1605 printDeprecatedOptions, 1606 printUnchangedOptions); 1607 1608 for (IMetricCollector collector : getMetricCollectors()) { 1609 ConfigurationUtil.dumpClassToXml( 1610 serializer, 1611 DEVICE_METRICS_COLLECTOR_TYPE_NAME, 1612 collector, 1613 excludeFilters, 1614 printDeprecatedOptions, 1615 printUnchangedOptions); 1616 } 1617 1618 for (IPostProcessor processor : getPostProcessors()) { 1619 ConfigurationUtil.dumpClassToXml( 1620 serializer, 1621 METRIC_POST_PROCESSOR_TYPE_NAME, 1622 processor, 1623 excludeFilters, 1624 printDeprecatedOptions, 1625 printUnchangedOptions); 1626 } 1627 1628 for (ISystemStatusChecker checker : getSystemStatusCheckers()) { 1629 ConfigurationUtil.dumpClassToXml( 1630 serializer, 1631 SYSTEM_STATUS_CHECKER_TYPE_NAME, 1632 checker, 1633 excludeFilters, 1634 printDeprecatedOptions, 1635 printUnchangedOptions); 1636 } 1637 1638 ConfigurationUtil.dumpClassToXml( 1639 serializer, 1640 SANBOX_OPTIONS_TYPE_NAME, 1641 getConfigurationObject(SANBOX_OPTIONS_TYPE_NAME), 1642 excludeFilters, 1643 printDeprecatedOptions, 1644 printUnchangedOptions); 1645 ConfigurationUtil.dumpClassToXml( 1646 serializer, 1647 RETRY_DECISION_TYPE_NAME, 1648 getRetryDecision(), 1649 excludeFilters, 1650 printDeprecatedOptions, 1651 printUnchangedOptions); 1652 ConfigurationUtil.dumpClassToXml( 1653 serializer, 1654 COVERAGE_OPTIONS_TYPE_NAME, 1655 getCoverageOptions(), 1656 excludeFilters, 1657 printDeprecatedOptions, 1658 printUnchangedOptions); 1659 ConfigurationUtil.dumpClassToXml( 1660 serializer, 1661 GLOBAL_FILTERS_TYPE_NAME, 1662 getGlobalFilters(), 1663 excludeFilters, 1664 printDeprecatedOptions, 1665 printUnchangedOptions); 1666 ConfigurationUtil.dumpClassToXml( 1667 serializer, 1668 SKIP_MANAGER_TYPE_NAME, 1669 getSkipManager(), 1670 excludeFilters, 1671 printDeprecatedOptions, 1672 printUnchangedOptions); 1673 1674 serializer.endTag(null, ConfigurationUtil.CONFIGURATION_NAME); 1675 serializer.endDocument(); 1676 } 1677 } 1678