Home | History | Annotate | Download | only in targetprep
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.android.tradefed.targetprep;
     17 
     18 import com.android.tradefed.build.IBuildInfo;
     19 import com.android.tradefed.config.Option;
     20 import com.android.tradefed.config.OptionClass;
     21 import com.android.tradefed.device.DeviceNotAvailableException;
     22 import com.android.tradefed.device.ITestDevice;
     23 import com.android.tradefed.log.LogUtil.CLog;
     24 import com.android.tradefed.util.IRunUtil;
     25 import com.android.tradefed.util.RunUtil;
     26 
     27 /**
     28  * A {@link ITargetPreparer} that waits for datetime to be set on device
     29  * <p>
     30  * Optionally this preparer can force a {@link TargetSetupError} if datetime is not set within
     31  * timeout, or force host datetime onto device,
     32  */
     33 @OptionClass(alias = "wait-for-datetime")
     34 public class WaitForDeviceDatetimePreparer implements ITargetPreparer {
     35 
     36     // 30s to wait for device datetime
     37     private static final long DATETIME_WAIT_TIMEOUT = 30 * 1000;
     38     // poll every 5s when waiting correct device datetime
     39     private static final long DATETIME_CHECK_INTERVAL = 5 * 1000;
     40     // allow 10s of margin for datetime difference between host/device
     41     private static final long DATETIME_MARGIN = 10;
     42 
     43     @Option(name = "force-datetime", description = "Force sync host datetime to device if device "
     44             + "fails to set datetime automatically.")
     45     private boolean mForceDatetime = false;
     46 
     47     @Option(name = "datetime-wait-timeout",
     48             description = "Timeout in ms to wait for correct datetime on device.")
     49     private long mDatetimeWaitTimeout = DATETIME_WAIT_TIMEOUT;
     50 
     51     @Option(name = "force-setup-error",
     52             description = "Throw an TargetSetupError if correct datetime was not set. "
     53                     + "Only meaningful if \"force-datetime\" is not used.")
     54     private boolean mForceSetupError = false;
     55 
     56     @Override
     57     public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
     58             BuildError, DeviceNotAvailableException {
     59         if (!waitForDeviceDatetime(device, mForceDatetime)) {
     60             if (mForceSetupError) {
     61                 throw new TargetSetupError("datetime on device is incorrect after wait timeout",
     62                         device.getDeviceDescriptor());
     63             } else {
     64                 CLog.w("datetime on device is incorrect after wait timeout.");
     65             }
     66         }
     67     }
     68 
     69     /**
     70      * Sets the timeout for waiting on valid device datetime
     71      */
     72     public void setDatetimeWaitTimeout(long datetimeWaitTimeout) {
     73         mDatetimeWaitTimeout = datetimeWaitTimeout;
     74     }
     75 
     76     /**
     77      * Sets the if datetime should be forced from host to device
     78      */
     79     public void setForceDatetime(boolean forceDatetime) {
     80         mForceDatetime = forceDatetime;
     81     }
     82 
     83     /**
     84      * Waits for a correct datetime on device, optionally force host datetime onto device
     85      * @param forceDatetime
     86      * @return <code>true</code> if datetime is correct or forced, <code>false</code> otherwise
     87      */
     88     boolean waitForDeviceDatetime(ITestDevice device, boolean forceDatetime)
     89             throws DeviceNotAvailableException {
     90         return waitForDeviceDatetime(device, forceDatetime,
     91                 mDatetimeWaitTimeout, DATETIME_CHECK_INTERVAL);
     92     }
     93 
     94     /**
     95      * Waits for a correct datetime on device, optionally force host datetime onto device
     96      * @param forceDatetime
     97      * @param datetimeWaitTimeout
     98      * @param datetimeCheckInterval
     99      * @return <code>true</code> if datetime is correct or forced, <code>false</code> otherwise
    100      */
    101     boolean waitForDeviceDatetime(ITestDevice device, boolean forceDatetime,
    102             long datetimeWaitTimeout, long datetimeCheckInterval)
    103             throws DeviceNotAvailableException {
    104         long start = System.currentTimeMillis();
    105         while ((System.currentTimeMillis() - start) < datetimeWaitTimeout) {
    106             long datetime = getDeviceDatetimeEpoch(device);
    107             long now = System.currentTimeMillis() / 1000;
    108             if (datetime == -1) {
    109                 if (forceDatetime) {
    110                     throw new UnsupportedOperationException(
    111                             "unexpected return from \"date\" command on device");
    112                 } else {
    113                     return false;
    114                 }
    115             }
    116             if ((Math.abs(now - datetime) < DATETIME_MARGIN)) {
    117                 return true;
    118             }
    119             getRunUtil().sleep(datetimeCheckInterval);
    120         }
    121         if (forceDatetime) {
    122             device.setDate(null);
    123             return true;
    124         } else {
    125             return false;
    126         }
    127     }
    128 
    129     /**
    130      * Retrieve device datetime in epoch format
    131      * @param device
    132      * @return datetime on device in epoch format, -1 if failed
    133      */
    134     long getDeviceDatetimeEpoch(ITestDevice device) throws DeviceNotAvailableException {
    135         String datetime = device.executeShellCommand("date '+%s'").trim();
    136         try {
    137             return Long.parseLong(datetime);
    138         } catch (NumberFormatException nfe) {
    139             CLog.v("returned datetime from device is not a number: '%s'", datetime);
    140             return -1;
    141         }
    142     }
    143 
    144     /**
    145      * @return the {@link IRunUtil} to use
    146      */
    147     protected IRunUtil getRunUtil() {
    148         return RunUtil.getDefault();
    149     }
    150 }
    151