1 /*
2  * Copyright 2022 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.server;
17 
18 import static java.lang.annotation.ElementType.TYPE_USE;
19 import static java.lang.annotation.RetentionPolicy.SOURCE;
20 
21 import android.annotation.CurrentTimeMillisLong;
22 import android.annotation.IntDef;
23 import android.annotation.NonNull;
24 import android.os.Build;
25 import android.os.Environment;
26 import android.os.SystemProperties;
27 import android.util.LocalLog;
28 import android.util.Slog;
29 
30 import java.io.PrintWriter;
31 import java.lang.annotation.Retention;
32 import java.lang.annotation.Target;
33 
34 /**
35  * A set of static methods that encapsulate knowledge of how the system clock time and associated
36  * metadata are stored on Android.
37  */
38 public final class SystemClockTime {
39 
40     private static final String TAG = "SystemClockTime";
41 
42     /**
43      * A log that records the decisions / decision metadata that affected the device's system clock
44      * time. This is logged in bug reports to assist with debugging issues with time.
45      */
46     @NonNull
47     private static final LocalLog sTimeDebugLog =
48             new LocalLog(30, false /* useLocalTimestamps */);
49 
50 
51     /**
52      * An annotation that indicates a "time confidence" value is expected.
53      *
54      * <p>The confidence indicates whether the time is expected to be correct. The confidence can be
55      * upgraded or downgraded over time. It can be used to decide whether a user could / should be
56      * asked to confirm the time. For example, during device set up low confidence would describe a
57      * time that has been initialized by default. The user may then be asked to confirm the time,
58      * moving it to a high confidence.
59      */
60     @Retention(SOURCE)
61     @Target(TYPE_USE)
62     @IntDef(prefix = "TIME_CONFIDENCE_",
63             value = { TIME_CONFIDENCE_LOW, TIME_CONFIDENCE_HIGH })
64     public @interface TimeConfidence {
65     }
66 
67     /** Used when confidence is low and would (ideally) be confirmed by a user. */
68     public static final @TimeConfidence int TIME_CONFIDENCE_LOW = 0;
69 
70     /**
71      * Used when confidence in the time is high and does not need to be confirmed by a user.
72      */
73     public static final @TimeConfidence int TIME_CONFIDENCE_HIGH = 100;
74 
75     /**
76      * The confidence in the current time. Android's time confidence is held in memory because RTC
77      * hardware can forget / corrupt the time while the device is powered off. Therefore, on boot
78      * we can't assume the time is good, and so default it to "low" confidence until it is confirmed
79      * or explicitly set.
80      */
81     private static @TimeConfidence int sTimeConfidence = TIME_CONFIDENCE_LOW;
82 
83     private static final long sNativeData = init();
84 
SystemClockTime()85     private SystemClockTime() {
86     }
87 
88     /**
89      * Sets the system clock time to a reasonable lower bound. Used during boot-up to ensure the
90      * device has a time that is better than a default like 1970-01-01.
91      */
initializeIfRequired()92     public static void initializeIfRequired() {
93         // Use the most recent of Build.TIME, the root file system's timestamp, and the
94         // value of the ro.build.date.utc system property (which is in seconds).
95         final long systemBuildTime = Long.max(
96                 1000L * SystemProperties.getLong("ro.build.date.utc", -1L),
97                 Long.max(Environment.getRootDirectory().lastModified(), Build.TIME));
98         long currentTimeMillis = getCurrentTimeMillis();
99         if (currentTimeMillis < systemBuildTime) {
100             String logMsg = "Current time only " + currentTimeMillis
101                     + ", advancing to build time " + systemBuildTime;
102             Slog.i(TAG, logMsg);
103             setTimeAndConfidence(systemBuildTime, TIME_CONFIDENCE_LOW, logMsg);
104         }
105     }
106 
107     /**
108      * Sets the system clock time and confidence. See also {@link #setConfidence(int, String)} for
109      * an alternative that only sets the confidence.
110      *
111      * @param unixEpochMillis the time to set
112      * @param confidence the confidence in {@code unixEpochMillis}. See {@link TimeConfidence} for
113      *     details.
114      * @param logMsg a log message that can be included in bug reports that explains the update
115      */
setTimeAndConfidence( @urrentTimeMillisLong long unixEpochMillis, int confidence, @NonNull String logMsg)116     public static void setTimeAndConfidence(
117             @CurrentTimeMillisLong long unixEpochMillis, int confidence, @NonNull String logMsg) {
118         synchronized (SystemClockTime.class) {
119             setTime(sNativeData, unixEpochMillis);
120             sTimeConfidence = confidence;
121             sTimeDebugLog.log(logMsg);
122         }
123     }
124 
125     /**
126      * Sets the system clock confidence. See also {@link #setTimeAndConfidence(long, int, String)}
127      * for an alternative that sets the time and confidence.
128      *
129      * @param confidence the confidence in the system clock time. See {@link TimeConfidence} for
130      *     details.
131      * @param logMsg a log message that can be included in bug reports that explains the update
132      */
setConfidence(@imeConfidence int confidence, @NonNull String logMsg)133     public static void setConfidence(@TimeConfidence int confidence, @NonNull String logMsg) {
134         synchronized (SystemClockTime.class) {
135             sTimeConfidence = confidence;
136             sTimeDebugLog.log(logMsg);
137         }
138     }
139 
140     /**
141      * Returns the system clock time. The same as {@link System#currentTimeMillis()}.
142      */
getCurrentTimeMillis()143     private static @CurrentTimeMillisLong long getCurrentTimeMillis() {
144         return System.currentTimeMillis();
145     }
146 
147     /**
148      * Returns the system clock confidence. See {@link TimeConfidence} for details.
149      */
getTimeConfidence()150     public static @TimeConfidence int getTimeConfidence() {
151         synchronized (SystemClockTime.class) {
152             return sTimeConfidence;
153         }
154     }
155 
156     /**
157      * Adds an entry to the system time debug log that is included in bug reports. This method is
158      * intended to be used to record event that may lead to a time change, e.g. config or mode
159      * changes.
160      */
addDebugLogEntry(@onNull String logMsg)161     public static void addDebugLogEntry(@NonNull String logMsg) {
162         sTimeDebugLog.log(logMsg);
163     }
164 
165     /**
166      * Dumps information about recent time / confidence changes to the supplied writer.
167      */
dump(PrintWriter writer)168     public static void dump(PrintWriter writer) {
169         sTimeDebugLog.dump(writer);
170     }
171 
init()172     private static native long init();
setTime(long nativeData, @CurrentTimeMillisLong long millis)173     private static native int setTime(long nativeData, @CurrentTimeMillisLong long millis);
174 }
175