blob: f9daf1234052fd36253833bd9b4f8505ed68222b [file] [log] [blame]
/*
* Copyright (C) 2015 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.targetprep;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.config.Option;
import com.android.tradefed.config.OptionClass;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.util.IRunUtil;
import com.android.tradefed.util.RunUtil;
/**
* A {@link ITargetPreparer} that waits for datetime to be set on device
*
* <p>Optionally this preparer can force a {@link TargetSetupError} if datetime is not set within
* timeout, or force host datetime onto device,
*/
@OptionClass(alias = "wait-for-datetime")
public class WaitForDeviceDatetimePreparer extends BaseTargetPreparer {
// 30s to wait for device datetime
private static final long DATETIME_WAIT_TIMEOUT = 30 * 1000;
// poll every 5s when waiting correct device datetime
private static final long DATETIME_CHECK_INTERVAL = 5 * 1000;
// allow 10s of margin for datetime difference between host/device
private static final long DATETIME_MARGIN = 10;
@Option(name = "force-datetime", description = "Force sync host datetime to device if device "
+ "fails to set datetime automatically.")
private boolean mForceDatetime = false;
@Option(name = "datetime-wait-timeout",
description = "Timeout in ms to wait for correct datetime on device.")
private long mDatetimeWaitTimeout = DATETIME_WAIT_TIMEOUT;
@Option(name = "force-setup-error",
description = "Throw an TargetSetupError if correct datetime was not set. "
+ "Only meaningful if \"force-datetime\" is not used.")
private boolean mForceSetupError = false;
@Override
public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
BuildError, DeviceNotAvailableException {
if (!waitForDeviceDatetime(device, mForceDatetime)) {
if (mForceSetupError) {
throw new TargetSetupError("datetime on device is incorrect after wait timeout",
device.getDeviceDescriptor());
} else {
CLog.w("datetime on device is incorrect after wait timeout.");
}
}
}
/**
* Sets the timeout for waiting on valid device datetime
*/
public void setDatetimeWaitTimeout(long datetimeWaitTimeout) {
mDatetimeWaitTimeout = datetimeWaitTimeout;
}
/**
* Sets the if datetime should be forced from host to device
*/
public void setForceDatetime(boolean forceDatetime) {
mForceDatetime = forceDatetime;
}
/**
* Sets the boolean for forcing a {@link TargetSetupError} if the datetime is not set correctly.
*/
public void setForceSetupError(boolean forceSetupError) {
mForceSetupError = forceSetupError;
}
/**
* Waits for a correct datetime on device, optionally force host datetime onto device
* @param forceDatetime
* @return <code>true</code> if datetime is correct or forced, <code>false</code> otherwise
*/
boolean waitForDeviceDatetime(ITestDevice device, boolean forceDatetime)
throws DeviceNotAvailableException {
return waitForDeviceDatetime(device, forceDatetime,
mDatetimeWaitTimeout, DATETIME_CHECK_INTERVAL);
}
/**
* Waits for a correct datetime on device, optionally force host datetime onto device
* @param forceDatetime
* @param datetimeWaitTimeout
* @param datetimeCheckInterval
* @return <code>true</code> if datetime is correct or forced, <code>false</code> otherwise
*/
boolean waitForDeviceDatetime(ITestDevice device, boolean forceDatetime,
long datetimeWaitTimeout, long datetimeCheckInterval)
throws DeviceNotAvailableException {
long start = System.currentTimeMillis();
while ((System.currentTimeMillis() - start) < datetimeWaitTimeout) {
long datetime = getDeviceDatetimeEpoch(device);
long now = System.currentTimeMillis() / 1000;
if (datetime == -1) {
if (forceDatetime) {
throw new UnsupportedOperationException(
"unexpected return from \"date\" command on device");
} else {
return false;
}
}
if ((Math.abs(now - datetime) < DATETIME_MARGIN)) {
return true;
}
getRunUtil().sleep(datetimeCheckInterval);
}
if (forceDatetime) {
device.setDate(null);
return true;
} else {
return false;
}
}
/**
* Retrieve device datetime in epoch format
* @param device
* @return datetime on device in epoch format, -1 if failed
*/
long getDeviceDatetimeEpoch(ITestDevice device) throws DeviceNotAvailableException {
String datetime = device.executeShellCommand("date '+%s'").trim();
try {
return Long.parseLong(datetime);
} catch (NumberFormatException nfe) {
CLog.v("returned datetime from device is not a number: '%s'", datetime);
return -1;
}
}
/**
* @return the {@link IRunUtil} to use
*/
protected IRunUtil getRunUtil() {
return RunUtil.getDefault();
}
}