blob: 13566a27ec84a7eac0d2acce56e27990ce40db5e [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.tradefed.host;
import com.android.tradefed.config.ConfigurationException;
import com.android.tradefed.config.Option;
import com.android.tradefed.config.OptionClass;
import com.android.tradefed.error.HarnessRuntimeException;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.result.error.InfraErrorIdentifier;
import com.android.tradefed.util.RunInterruptedException;
import java.io.File;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.Semaphore;
/**
* Host options holder class.
* This class is used to store host-wide options.
*/
@OptionClass(alias = "host_options", global_namespace = false)
public class HostOptions implements IHostOptions {
@Option(name = "concurrent-flasher-limit", description =
"The maximum number of concurrent flashers (may be useful to avoid memory constraints)")
private Integer mConcurrentFlasherLimit = 1;
@Option(
name = "concurrent-download-limit",
description =
"The maximum number of concurrent downloads (may be useful to avoid network "
+ "constraints)"
)
private Integer mConcurrentDownloadLimit = null;
@Option(
name = "concurrent-virtual-device-startup-limit",
description =
"The maximum number of concurrent virtual device startup to avoid resource"
+ " contentions depending on factors such as network, CPU, I/O etc.")
private Integer mConcurrentVirtualDeviceStartupLimit = null;
@Option(name = "concurrent-limits", description =
"The maximum number of concurrent actions of a given type.")
private Map<PermitLimitType, Integer> mConcurrentLimit = new HashMap<>();
@Option(
name = "fastboot-tmpdir",
description = "The location of temporary directory used by fastboot"
)
private File mFastbootTmpDir = null;
@Option(
name = "enable-fastbootd-mode",
description = "Feature flag to enable the support for fastbootd.")
private boolean mEnableFastbootdMode = true;
@Option(name = "download-cache-dir", description = "the directory for caching downloaded "
+ "flashing files. Should be on the same filesystem as java.io.tmpdir. Consider "
+ "changing the java.io.tmpdir property if you want to move downloads to a different "
+ "filesystem.")
private File mDownloadCacheDir = new File(System.getProperty("java.io.tmpdir"), "lc_cache");
@Option(name = "use-sso-client", description = "Use a SingleSignOn client for HTTP requests.")
private Boolean mUseSsoClient = true;
@Option(
name = "service-account-json-key-file",
description =
"Specify a service account json key file, and a String key name to identify it."
)
private Map<String, File> mJsonServiceAccountMap = new HashMap<>();
@Option(name = "label", description = "Labels to describe the host.")
private List<String> mLabels = new ArrayList<>();
@Option(
name = "known-tcp-device-ip-pool",
description =
"known remote device available via ip associated with the "
+ "tcp-device placeholder.")
private Set<String> mKnownTcpDeviceIpPool = new HashSet<>();
@Option(
name = "known-gce-device-ip-pool",
description =
"known remote device available via ip associated with the "
+ "gce-device placeholder.")
private Set<String> mKnownGceDeviceIpPool = new HashSet<>();
@Option(
name = "known-remote-device-ip-pool",
description =
"known remote device available via ip associated with the "
+ "remote-device placeholder.")
private Set<String> mKnownRemoteDeviceIpPool = new HashSet<>();
@Option(
name = "use-zip64-in-partial-download",
description = "Whether to use zip64 format in partial download.")
private boolean mUseZip64InPartialDownload = true;
@Option(
name = "use-network-interface",
description = "The network interface used to connect to test devices.")
private String mNetworkInterface = null;
@Option(
name = "preconfigured-virtual-device-pool",
description = "Preconfigured virtual device pool. (Value format: $hostname:$user.)")
private List<String> mPreconfiguredVirtualDevicePool = new ArrayList<>();
@Option(
name = "flash-with-fuse-zip",
description = "Use `fastboot flashall` on a folder of fuse mounted device image zip "
+ "instead of `fastboot update` with zip")
private boolean mFlashWithFuseZip = false;
@Option(
name = "cache-size-limit",
description =
"The maximum allowed size(bytes) of the local file cache. (default: 15GB)")
private Long mCacheSizeLimit = 15L * 1024L * 1024L * 1024L;
@Option(
name = "test-phase-timeout",
description =
"the maximum time to wait for test phase to finish before attempting to force"
+ "stop it. A value of zero will indicate no timeout.",
isTimeVal = true)
private long mTestPhaseTimeout = 0;
@Option(
name = "enable-incremental-flashing",
description = "Feature flag to enable incremental flashing on one host.")
private boolean mEnableIncrementalFlashing = false;
@Option(
name = "opt-out-incremental-flashing",
description = "Allows an host to fully opt-out of incremental flashing.")
private boolean mOptOutFromIncrementalFlashing = false;
@Option(
name = "disable-host-metric-reporting",
description = "Feature flag to disable the support for host metric reporting.")
private boolean mDisableHostMetricReporting = false;
private Map<PermitLimitType, Semaphore> mConcurrentLocks = new HashMap<>();
private Map<PermitLimitType, Integer> mInternalConcurrentLimits = new HashMap<>();
/** {@inheritDoc} */
@Override
public Long getCacheSizeLimit() {
return mCacheSizeLimit;
}
/** {@inheritDoc} */
@Override
public Integer getConcurrentFlasherLimit() {
return mConcurrentFlasherLimit;
}
/** {@inheritDoc} */
@Override
public Integer getConcurrentDownloadLimit() {
return mConcurrentDownloadLimit;
}
@Override
public Integer getConcurrentVirtualDeviceStartupLimit() {
return mConcurrentVirtualDeviceStartupLimit;
}
/** {@inheritDoc} */
@Override
public File getFastbootTmpDir() {
if (mFastbootTmpDir != null) {
if (!mFastbootTmpDir.exists() || !mFastbootTmpDir.isDirectory()) {
throw new HarnessRuntimeException(
String.format(
"Fastboot tmp dir '%s' is missing and was expected.",
mFastbootTmpDir),
InfraErrorIdentifier.LAB_HOST_FILESYSTEM_ERROR);
}
return mFastbootTmpDir;
}
return null;
}
/** {@inheritDoc} */
@Override
public boolean isFastbootdEnable() {
return mEnableFastbootdMode;
}
/** {@inheritDoc} */
@Override
public File getDownloadCacheDir() {
return mDownloadCacheDir;
}
/** {@inheritDoc} */
@Override
public Boolean shouldUseSsoClient() {
return mUseSsoClient;
}
/** {@inheritDoc} */
@Override
public Map<String, File> getServiceAccountJsonKeyFiles() {
return new HashMap<>(mJsonServiceAccountMap);
}
/** {@inheritDoc} */
@Override
public void validateOptions() throws ConfigurationException {
// Validation of host options
}
/** {@inheritDoc} */
@Override
public List<String> getLabels() {
return new ArrayList<>(mLabels);
}
/** {@inheritDoc} */
@Override
public Set<String> getKnownTcpDeviceIpPool() {
return new HashSet<>(mKnownTcpDeviceIpPool);
}
/** {@inheritDoc} */
@Override
public Set<String> getKnownGceDeviceIpPool() {
return new HashSet<>(mKnownGceDeviceIpPool);
}
/** {@inheritDoc} */
@Override
public Set<String> getKnownRemoteDeviceIpPool() {
return new HashSet<>(mKnownRemoteDeviceIpPool);
}
/** {@inheritDoc} */
@Override
public List<String> getKnownPreconfigureVirtualDevicePool() {
return new ArrayList<>(mPreconfiguredVirtualDevicePool);
}
/** {@inheritDoc} */
@Override
public boolean getUseZip64InPartialDownload() {
return mUseZip64InPartialDownload;
}
/** {@inheritDoc} */
@Override
public String getNetworkInterface() {
if (mNetworkInterface != null) {
return mNetworkInterface;
}
try {
for (Enumeration<NetworkInterface> enNetI = NetworkInterface.getNetworkInterfaces();
enNetI.hasMoreElements(); ) {
NetworkInterface netI = enNetI.nextElement();
if (!netI.isUp()) {
continue;
}
for (Enumeration<InetAddress> enumIpAddr = netI.getInetAddresses();
enumIpAddr.hasMoreElements(); ) {
InetAddress inetAddress = enumIpAddr.nextElement();
if (!inetAddress.isAnyLocalAddress()
&& !inetAddress.isLinkLocalAddress()
&& !inetAddress.isLoopbackAddress()
&& !inetAddress.isMulticastAddress()) {
mNetworkInterface = netI.getName();
return mNetworkInterface;
}
}
}
} catch (SocketException e) {
CLog.w("Failed to get host's active interface");
CLog.w(e);
}
return null;
}
@Override
public long getTestPhaseTimeout() {
return mTestPhaseTimeout;
}
@Override
public void initConcurrentLocks() {
// Do not reinit if it has been called before
if (!mConcurrentLocks.isEmpty()) {
return;
}
mInternalConcurrentLimits.putAll(mConcurrentLimit);
// Backfill flasher & download limit from their dedicated option
if (!mInternalConcurrentLimits.containsKey(PermitLimitType.CONCURRENT_FLASHER)) {
mInternalConcurrentLimits.put(
PermitLimitType.CONCURRENT_FLASHER, mConcurrentFlasherLimit);
}
if (!mInternalConcurrentLimits.containsKey(PermitLimitType.CONCURRENT_DOWNLOAD)) {
mInternalConcurrentLimits.put(
PermitLimitType.CONCURRENT_DOWNLOAD, mConcurrentDownloadLimit);
}
if (!mInternalConcurrentLimits.containsKey(
PermitLimitType.CONCURRENT_VIRTUAL_DEVICE_STARTUP)) {
mInternalConcurrentLimits.put(
PermitLimitType.CONCURRENT_VIRTUAL_DEVICE_STARTUP,
mConcurrentVirtualDeviceStartupLimit);
}
for (Entry<PermitLimitType, Integer> limits : mInternalConcurrentLimits.entrySet()) {
if (limits.getValue() == null) {
continue;
}
mConcurrentLocks.put(limits.getKey(),
new Semaphore(limits.getValue(), true /* fair */));
}
}
@Override
public void takePermit(PermitLimitType type) {
if (!mConcurrentLocks.containsKey(type)) {
return;
}
CLog.i(
"Requesting a '%s' permit out of the max limit of %s. Current queue "
+ "length: %s",
type,
mInternalConcurrentLimits.get(type),
mConcurrentLocks.get(type).getQueueLength());
try {
mConcurrentLocks.get(type).acquire();
} catch (InterruptedException e) {
throw new RunInterruptedException(e.getMessage(), e, InfraErrorIdentifier.UNDETERMINED);
}
}
@Override
public void returnPermit(PermitLimitType type) {
if (!mConcurrentLocks.containsKey(type)) {
return;
}
mConcurrentLocks.get(type).release();
}
@Override
public Integer getAvailablePermits(PermitLimitType type) {
if (!mConcurrentLocks.containsKey(type)) {
return Integer.MAX_VALUE;
}
return mConcurrentLocks.get(type).availablePermits();
}
@Override
public int getInUsePermits(PermitLimitType type) {
if (!mConcurrentLocks.containsKey(type)) {
return 0;
}
return mInternalConcurrentLimits.get(type) - mConcurrentLocks.get(type).availablePermits();
}
@Override
public boolean shouldFlashWithFuseZip() {
return mFlashWithFuseZip;
}
/** {@inheritDoc} */
@Override
public boolean isIncrementalFlashingEnabled() {
return mEnableIncrementalFlashing;
}
/** {@inheritDoc} */
@Override
public boolean isOptOutOfIncrementalFlashing() {
return mOptOutFromIncrementalFlashing;
}
/** {@inheritDoc} */
@Override
public boolean isHostMetricReportingDisabled() {
return mDisableHostMetricReporting;
}
}