Merge "Improve debug logging for NetworkTimeHelper"

This commit is contained in:
Neil Fuller
2023-01-30 18:34:10 +00:00
committed by Android (Google) Code Review
4 changed files with 101 additions and 28 deletions

View File

@@ -44,5 +44,14 @@ class ExponentialBackOff {
void reset() {
mCurrentIntervalMillis = mInitIntervalMillis / MULTIPLIER;
}
@Override
public String toString() {
return "ExponentialBackOff{"
+ "mInitIntervalMillis=" + mInitIntervalMillis
+ ", mMaxIntervalMillis=" + mMaxIntervalMillis
+ ", mCurrentIntervalMillis=" + mCurrentIntervalMillis
+ '}';
}
}

View File

@@ -1695,6 +1695,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
pw.println("mFixInterval=" + mFixInterval);
pw.print(mGnssMetrics.dumpGnssMetricsAsText());
if (dumpAll) {
mNetworkTimeHelper.dump(pw);
pw.println("mSupportsPsds=" + mSupportsPsds);
pw.println(
"PsdsServerConfigured=" + mGnssConfiguration.isLongTermPsdsServerConfigured());

View File

@@ -15,9 +15,14 @@
*/
package com.android.server.location.gnss;
import android.annotation.CurrentTimeMillisLong;
import android.annotation.ElapsedRealtimeLong;
import android.annotation.NonNull;
import android.content.Context;
import android.os.Looper;
import java.io.PrintWriter;
/**
* An abstraction for use by {@link GnssLocationProvider}. This class allows switching between
* implementations with a compile-time constant change, which is less risky than rolling back a
@@ -32,15 +37,16 @@ abstract class NetworkTimeHelper {
* the looper passed to {@link #create(Context, Looper, InjectTimeCallback)}.
*/
interface InjectTimeCallback {
void injectTime(long unixEpochTimeMillis, long elapsedRealtimeMillis,
int uncertaintyMillis);
void injectTime(@CurrentTimeMillisLong long unixEpochTimeMillis,
@ElapsedRealtimeLong long elapsedRealtimeMillis, int uncertaintyMillis);
}
/**
* Creates the {@link NetworkTimeHelper} instance for use by {@link GnssLocationProvider}.
*/
static NetworkTimeHelper create(
Context context, Looper looper, InjectTimeCallback injectTimeCallback) {
@NonNull Context context, @NonNull Looper looper,
@NonNull InjectTimeCallback injectTimeCallback) {
return new NtpNetworkTimeHelper(context, looper, injectTimeCallback);
}
@@ -72,4 +78,8 @@ abstract class NetworkTimeHelper {
*/
abstract void onNetworkAvailable();
/**
* Dumps internal state during bugreports useful for debugging.
*/
abstract void dump(@NonNull PrintWriter pw);
}

View File

@@ -23,12 +23,17 @@ import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.SystemClock;
import android.util.IndentingPrintWriter;
import android.util.LocalLog;
import android.util.Log;
import android.util.NtpTrustedTime;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import java.io.PrintWriter;
/**
* Handles injecting network time to GNSS by explicitly making NTP requests when needed.
*/
@@ -60,6 +65,9 @@ class NtpNetworkTimeHelper extends NetworkTimeHelper {
private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
private static final String WAKELOCK_KEY = "NtpTimeHelper";
private final LocalLog mDumpLog = new LocalLog(10, /*useLocalTimestamps=*/false);
@GuardedBy("this")
private final ExponentialBackOff mNtpBackOff = new ExponentialBackOff(RETRY_INTERVAL,
MAX_RETRY_INTERVAL);
@@ -103,16 +111,39 @@ class NtpNetworkTimeHelper extends NetworkTimeHelper {
@Override
void demandUtcTimeInjection() {
retrieveAndInjectNtpTime();
retrieveAndInjectNtpTime("demandUtcTimeInjection");
}
@Override
synchronized void onNetworkAvailable() {
if (mInjectNtpTimeState == STATE_PENDING_NETWORK) {
retrieveAndInjectNtpTime();
retrieveAndInjectNtpTime("onNetworkAvailable");
}
}
@Override
void dump(PrintWriter pw) {
pw.println("NtpNetworkTimeHelper:");
IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
ipw.increaseIndent();
synchronized (this) {
ipw.println("mInjectNtpTimeState=" + mInjectNtpTimeState);
ipw.println("mPeriodicTimeInjection=" + mPeriodicTimeInjection);
ipw.println("mNtpBackOff=" + mNtpBackOff);
}
ipw.println("Debug log:");
ipw.increaseIndent();
mDumpLog.dump(ipw);
ipw.decreaseIndent();
ipw.println("NtpTrustedTime:");
ipw.increaseIndent();
mNtpTime.dump(ipw);
ipw.decreaseIndent();
}
/**
* @return {@code true} if there is a network available for outgoing connections,
* {@code false} otherwise.
@@ -122,14 +153,14 @@ class NtpNetworkTimeHelper extends NetworkTimeHelper {
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}
private synchronized void retrieveAndInjectNtpTime() {
private synchronized void retrieveAndInjectNtpTime(String reason) {
if (mInjectNtpTimeState == STATE_RETRIEVING_AND_INJECTING) {
// already downloading data
return;
}
if (!isNetworkConnected()) {
// try to inject the cached NTP time
injectCachedNtpTime();
maybeInjectCachedNtpTime(reason + "[Network not connected]");
// try again when network is up
mInjectNtpTimeState = STATE_PENDING_NETWORK;
return;
@@ -143,7 +174,8 @@ class NtpNetworkTimeHelper extends NetworkTimeHelper {
/** {@link NtpTrustedTime#forceRefresh} is a blocking network operation. */
private void blockingGetNtpTimeAndInject() {
long delay;
long debugId = SystemClock.elapsedRealtime();
long delayMillis;
// force refresh NTP cache when outdated
boolean refreshSuccess = true;
@@ -158,26 +190,30 @@ class NtpNetworkTimeHelper extends NetworkTimeHelper {
// only update when NTP time is fresh
// If refreshSuccess is false, cacheAge does not drop down.
if (injectCachedNtpTime()) {
delay = NTP_INTERVAL;
String injectReason = "blockingGetNtpTimeAndInject:"
+ ", debugId=" + debugId
+ ", refreshSuccess=" + refreshSuccess;
if (maybeInjectCachedNtpTime(injectReason)) {
delayMillis = NTP_INTERVAL;
mNtpBackOff.reset();
} else {
Log.e(TAG, "requestTime failed");
delay = mNtpBackOff.nextBackoffMillis();
logWarn("maybeInjectCachedNtpTime() returned false");
delayMillis = mNtpBackOff.nextBackoffMillis();
}
if (DEBUG) {
Log.d(TAG, String.format(
"mPeriodicTimeInjection=%s, refreshSuccess=%s, delay=%s",
mPeriodicTimeInjection,
refreshSuccess,
delay));
}
if (mPeriodicTimeInjection || !refreshSuccess) {
String debugMsg = "blockingGetNtpTimeAndInject: Scheduling later NTP retrieval"
+ ", debugId=" + debugId
+ ", mPeriodicTimeInjection=" + mPeriodicTimeInjection
+ ", refreshSuccess=" + refreshSuccess
+ ", delayMillis=" + delayMillis;
logDebug(debugMsg);
// Schedule next NTP injection.
// Since this is delayed, the wake lock is released right away, and will be held
// again when the delayed task runs.
mHandler.postDelayed(this::retrieveAndInjectNtpTime, delay);
String reason = "scheduled: debugId=" + debugId;
mHandler.postDelayed(() -> retrieveAndInjectNtpTime(reason), delayMillis);
}
}
// release wake lock held by task
@@ -185,24 +221,41 @@ class NtpNetworkTimeHelper extends NetworkTimeHelper {
}
/** Returns true if successfully inject cached NTP time. */
private synchronized boolean injectCachedNtpTime() {
private synchronized boolean maybeInjectCachedNtpTime(String reason) {
NtpTrustedTime.TimeResult ntpResult = mNtpTime.getCachedTimeResult();
if (ntpResult == null || ntpResult.getAgeMillis() >= NTP_INTERVAL) {
String debugMsg = "maybeInjectCachedNtpTime: Not injecting latest NTP time"
+ ", reason=" + reason
+ ", ntpResult=" + ntpResult;
logDebug(debugMsg);
return false;
}
long unixEpochTimeMillis = ntpResult.getTimeMillis();
long currentTimeMillis = System.currentTimeMillis();
String debugMsg = "maybeInjectCachedNtpTime: Injecting latest NTP time"
+ ", reason=" + reason
+ ", ntpResult=" + ntpResult
+ ", System time offset millis=" + (unixEpochTimeMillis - currentTimeMillis);
logDebug(debugMsg);
long timeReferenceMillis = ntpResult.getElapsedRealtimeMillis();
int uncertaintyMillis = ntpResult.getUncertaintyMillis();
if (DEBUG) {
long currentTimeMillis = System.currentTimeMillis();
Log.d(TAG, "NTP server returned: " + unixEpochTimeMillis
+ " ntpResult: " + ntpResult
+ " system time offset: " + (unixEpochTimeMillis - currentTimeMillis));
}
mHandler.post(() -> mCallback.injectTime(unixEpochTimeMillis, timeReferenceMillis,
uncertaintyMillis));
return true;
}
private void logWarn(String logMsg) {
mDumpLog.log(logMsg);
Log.e(TAG, logMsg);
}
private void logDebug(String debugMsg) {
mDumpLog.log(debugMsg);
if (DEBUG) {
Log.d(TAG, debugMsg);
}
}
}