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