blob: 46fbbb290ed25b0556969dc461ef155b8a4fec9f [file] [log] [blame]
/*
* Copyright 2022 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.server;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.CurrentTimeMillisLong;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.os.Build;
import android.os.Environment;
import android.os.SystemProperties;
import android.util.LocalLog;
import android.util.Slog;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/**
* A set of static methods that encapsulate knowledge of how the system clock time and associated
* metadata are stored on Android.
*/
public final class SystemClockTime {
private static final String TAG = "SystemClockTime";
/**
* A log that records the decisions / decision metadata that affected the device's system clock
* time. This is logged in bug reports to assist with debugging issues with time.
*/
@NonNull
private static final LocalLog sTimeDebugLog =
new LocalLog(30, false /* useLocalTimestamps */);
/**
* An annotation that indicates a "time confidence" value is expected.
*
* <p>The confidence indicates whether the time is expected to be correct. The confidence can be
* upgraded or downgraded over time. It can be used to decide whether a user could / should be
* asked to confirm the time. For example, during device set up low confidence would describe a
* time that has been initialized by default. The user may then be asked to confirm the time,
* moving it to a high confidence.
*/
@Retention(SOURCE)
@Target(TYPE_USE)
@IntDef(prefix = "TIME_CONFIDENCE_",
value = { TIME_CONFIDENCE_LOW, TIME_CONFIDENCE_HIGH })
public @interface TimeConfidence {
}
/** Used when confidence is low and would (ideally) be confirmed by a user. */
public static final @TimeConfidence int TIME_CONFIDENCE_LOW = 0;
/**
* Used when confidence in the time is high and does not need to be confirmed by a user.
*/
public static final @TimeConfidence int TIME_CONFIDENCE_HIGH = 100;
/**
* The confidence in the current time. Android's time confidence is held in memory because RTC
* hardware can forget / corrupt the time while the device is powered off. Therefore, on boot
* we can't assume the time is good, and so default it to "low" confidence until it is confirmed
* or explicitly set.
*/
private static @TimeConfidence int sTimeConfidence = TIME_CONFIDENCE_LOW;
private static final long sNativeData = init();
private SystemClockTime() {
}
/**
* Sets the system clock time to a reasonable lower bound. Used during boot-up to ensure the
* device has a time that is better than a default like 1970-01-01.
*/
public static void initializeIfRequired() {
// Use the most recent of Build.TIME, the root file system's timestamp, and the
// value of the ro.build.date.utc system property (which is in seconds).
final long systemBuildTime = Long.max(
1000L * SystemProperties.getLong("ro.build.date.utc", -1L),
Long.max(Environment.getRootDirectory().lastModified(), Build.TIME));
long currentTimeMillis = getCurrentTimeMillis();
if (currentTimeMillis < systemBuildTime) {
String logMsg = "Current time only " + currentTimeMillis
+ ", advancing to build time " + systemBuildTime;
Slog.i(TAG, logMsg);
setTimeAndConfidence(systemBuildTime, TIME_CONFIDENCE_LOW, logMsg);
}
}
/**
* Sets the system clock time and confidence. See also {@link #setConfidence(int, String)} for
* an alternative that only sets the confidence.
*
* @param unixEpochMillis the time to set
* @param confidence the confidence in {@code unixEpochMillis}. See {@link TimeConfidence} for
* details.
* @param logMsg a log message that can be included in bug reports that explains the update
*/
public static void setTimeAndConfidence(
@CurrentTimeMillisLong long unixEpochMillis, int confidence, @NonNull String logMsg) {
synchronized (SystemClockTime.class) {
setTime(sNativeData, unixEpochMillis);
sTimeConfidence = confidence;
sTimeDebugLog.log(logMsg);
}
}
/**
* Sets the system clock confidence. See also {@link #setTimeAndConfidence(long, int, String)}
* for an alternative that sets the time and confidence.
*
* @param confidence the confidence in the system clock time. See {@link TimeConfidence} for
* details.
* @param logMsg a log message that can be included in bug reports that explains the update
*/
public static void setConfidence(@TimeConfidence int confidence, @NonNull String logMsg) {
synchronized (SystemClockTime.class) {
sTimeConfidence = confidence;
sTimeDebugLog.log(logMsg);
}
}
/**
* Returns the system clock time. The same as {@link System#currentTimeMillis()}.
*/
private static @CurrentTimeMillisLong long getCurrentTimeMillis() {
return System.currentTimeMillis();
}
/**
* Returns the system clock confidence. See {@link TimeConfidence} for details.
*/
public static @TimeConfidence int getTimeConfidence() {
synchronized (SystemClockTime.class) {
return sTimeConfidence;
}
}
/**
* Adds an entry to the system time debug log that is included in bug reports. This method is
* intended to be used to record event that may lead to a time change, e.g. config or mode
* changes.
*/
public static void addDebugLogEntry(@NonNull String logMsg) {
sTimeDebugLog.log(logMsg);
}
/**
* Dumps information about recent time / confidence changes to the supplied writer.
*/
public static void dump(PrintWriter writer) {
sTimeDebugLog.dump(writer);
}
private static native long init();
private static native int setTime(long nativeData, @CurrentTimeMillisLong long millis);
}