blob: caaf4d267930b41fd9916d9027b4edaeb853a212 [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
package org.chromium.base.test.util;
import android.os.Debug;
/** Encapsulates timeout logic, and disables timeouts when debugger is attached. */
public class TimeoutTimer {
private static final boolean IS_REAL_ANDROID =
System.getProperty("java.class.path").endsWith(".apk");
private static final long MS_TO_NANO = 1000000;
private final long mEndTimeNano;
private final long mTimeoutMs;
static {
if (!IS_REAL_ANDROID) {
try {
// BaseRobolectricTestRunner marks this class as "DoNotAcquire" so that
// System.nanoTime() will not return fake time.
Class.forName("android.os.Debug");
assert false : "Cannot use TimeoutTimer without using BaseRobolectricTestRunner";
} catch (Throwable e) {
}
}
}
/**
* @param timeoutMs Relative time for the timeout (unscaled).
*/
public TimeoutTimer(long timeoutMs) {
mTimeoutMs = ScalableTimeout.scaleTimeout(timeoutMs);
mEndTimeNano = System.nanoTime() + mTimeoutMs * MS_TO_NANO;
}
/** Whether this timer has expired. */
public boolean isTimedOut() {
return getRemainingMs() == 0;
}
private static boolean shouldPauseTimeouts() {
if (IS_REAL_ANDROID) {
return Debug.isDebuggerConnected();
}
// Our test runner sets this when --wait-for-java-debugger is passed.
// This will cause tests to never time out since the value is not updated when debugger
// detaches (oh well).
return "true".equals(System.getProperty("chromium.jdwp_active"));
}
/** Returns how much time is left in milliseconds. */
public long getRemainingMs() {
if (shouldPauseTimeouts()) {
// Never decreases, but still short enough that it's safe to wait() on and have a
// timeout happen once the debugger detaches.
return mTimeoutMs;
}
long ret = mEndTimeNano - System.nanoTime();
return ret < 0 ? 0 : ret / MS_TO_NANO;
}
}