1 /*
2  * Copyright (C) 2018 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 
17 package com.android.server.timedetector;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.UserIdInt;
23 import android.app.time.ExternalTimeSuggestion;
24 import android.app.time.TimeCapabilitiesAndConfig;
25 import android.app.time.TimeConfiguration;
26 import android.app.time.TimeState;
27 import android.app.time.UnixEpochTime;
28 import android.app.timedetector.ManualTimeSuggestion;
29 import android.app.timedetector.TelephonyTimeSuggestion;
30 import android.util.IndentingPrintWriter;
31 
32 import com.android.internal.util.Preconditions;
33 import com.android.server.timezonedetector.Dumpable;
34 import com.android.server.timezonedetector.StateChangeListener;
35 
36 import java.lang.annotation.ElementType;
37 import java.lang.annotation.Retention;
38 import java.lang.annotation.RetentionPolicy;
39 import java.lang.annotation.Target;
40 
41 /**
42  * The interface for the class that implements the time detection algorithm used by the
43  * {@link TimeDetectorService}.
44  *
45  * <p>Most calls will be handled by a single thread but that is not true for all calls. For example
46  * {@link #dump(IndentingPrintWriter, String[])}) may be called on a different thread so
47  * implementations must handle thread safety.
48  *
49  * @hide
50  */
51 public interface TimeDetectorStrategy extends Dumpable {
52 
53     @IntDef({ ORIGIN_TELEPHONY, ORIGIN_MANUAL, ORIGIN_NETWORK, ORIGIN_GNSS, ORIGIN_EXTERNAL })
54     @Retention(RetentionPolicy.SOURCE)
55     @Target({ ElementType.TYPE_USE, ElementType.TYPE_PARAMETER })
56     @interface Origin {}
57 
58     /** Used when a time value originated from a telephony signal. */
59     @Origin int ORIGIN_TELEPHONY = 1;
60 
61     /** Used when a time value originated from a user / manual settings. */
62     @Origin int ORIGIN_MANUAL = 2;
63 
64     /** Used when a time value originated from a network signal. */
65     @Origin int ORIGIN_NETWORK = 3;
66 
67     /** Used when a time value originated from a gnss signal. */
68     @Origin int ORIGIN_GNSS = 4;
69 
70     /** Used when a time value originated from an externally specified signal. */
71     @Origin int ORIGIN_EXTERNAL = 5;
72 
73     /** Returns a snapshot of the system clock's state. See {@link TimeState} for details. */
74     @NonNull
getTimeState()75     TimeState getTimeState();
76 
77     /**
78      * Sets the system time state. See {@link TimeState} for details. Intended for use during
79      * testing to force the device's state, this bypasses the time detection logic.
80      */
setTimeState(@onNull TimeState timeState)81     void setTimeState(@NonNull TimeState timeState);
82 
83     /**
84      * Signals that a user has confirmed the supplied time. If the {@code confirmationTime},
85      * adjusted for elapsed time since it was created (expected to be with {@link
86      * #getTimeState()}), is very close to the clock's current state, then this can be used to
87      * raise the system's confidence in that time. Returns {@code true} if confirmation was
88      * successful (i.e. the time matched), {@code false} otherwise.
89      */
confirmTime(@onNull UnixEpochTime confirmationTime)90     boolean confirmTime(@NonNull UnixEpochTime confirmationTime);
91 
92     /**
93      * Adds a listener that will be triggered when something changes that could affect the result
94      * of the {@link #getCapabilitiesAndConfig} call for the <em>current user only</em>. This
95      * includes the current user changing. This is exposed so that (indirect) users like SettingsUI
96      * can monitor for changes to data derived from {@link TimeCapabilitiesAndConfig} and update
97      * the UI accordingly.
98      */
addChangeListener(@onNull StateChangeListener listener)99     void addChangeListener(@NonNull StateChangeListener listener);
100 
101     /**
102      * Returns a {@link TimeCapabilitiesAndConfig} object for the specified user.
103      *
104      * <p>The strategy is dependent on device state like current user, settings and device config.
105      * These updates are usually handled asynchronously, so callers should expect some delay between
106      * a change being made directly to services like settings and the strategy becoming aware of
107      * them. Changes made via {@link #updateConfiguration} will be visible immediately.
108      *
109      * @param userId the user ID to retrieve the information for
110      * @param bypassUserPolicyChecks {@code true} for device policy manager use cases where device
111      *   policy restrictions that should apply to actual users can be ignored
112      */
getCapabilitiesAndConfig( @serIdInt int userId, boolean bypassUserPolicyChecks)113     TimeCapabilitiesAndConfig getCapabilitiesAndConfig(
114             @UserIdInt int userId, boolean bypassUserPolicyChecks);
115 
116     /**
117      * Updates the configuration properties that control a device's time behavior.
118      *
119      * <p>This method returns {@code true} if the configuration was changed, {@code false}
120      * otherwise.
121      *
122      * <p>See {@link #getCapabilitiesAndConfig} for guarantees about visibility of updates to
123      * subsequent calls.
124      *
125      * @param userId the current user ID, supplied to make sure that the asynchronous process
126      *   that happens when users switch is completed when the call is made
127      * @param configuration the configuration changes
128      * @param bypassUserPolicyChecks {@code true} for device policy manager use cases where device
129      *   policy restrictions that should apply to actual users can be ignored
130      */
updateConfiguration(@serIdInt int userId, @NonNull TimeConfiguration configuration, boolean bypassUserPolicyChecks)131     boolean updateConfiguration(@UserIdInt int userId,
132             @NonNull TimeConfiguration configuration, boolean bypassUserPolicyChecks);
133 
134     /** Processes the suggested time from telephony sources. */
suggestTelephonyTime(@onNull TelephonyTimeSuggestion suggestion)135     void suggestTelephonyTime(@NonNull TelephonyTimeSuggestion suggestion);
136 
137     /**
138      * Processes the suggested manually entered time. Returns {@code false} if the suggestion was
139      * invalid, or the device configuration prevented the suggestion being used, {@code true} if the
140      * suggestion was accepted. A suggestion that is valid but does not change the time because it
141      * matches the current device time is considered accepted.
142      *
143      * @param bypassUserPolicyChecks {@code true} for device policy manager use cases where device
144      *   policy restrictions that should apply to actual users can be ignored
145      */
suggestManualTime(@serIdInt int userId, @NonNull ManualTimeSuggestion suggestion, boolean bypassUserPolicyChecks)146     boolean suggestManualTime(@UserIdInt int userId, @NonNull ManualTimeSuggestion suggestion,
147             boolean bypassUserPolicyChecks);
148 
149     /**
150      * Processes the suggested network time. The suggestion may not be used to set the device's time
151      * depending on device configuration and user settings, but can replace previous network
152      * suggestions received. See also
153      * {@link #addNetworkTimeUpdateListener(StateChangeListener)} and
154      * {@link #getLatestNetworkSuggestion()}.
155      */
suggestNetworkTime(@onNull NetworkTimeSuggestion suggestion)156     void suggestNetworkTime(@NonNull NetworkTimeSuggestion suggestion);
157 
158     /**
159      * Adds a listener that will be notified when a new network time is available. See {@link
160      * #getLatestNetworkSuggestion()}.
161      */
addNetworkTimeUpdateListener(@onNull StateChangeListener networkSuggestionUpdateListener)162     void addNetworkTimeUpdateListener(@NonNull StateChangeListener networkSuggestionUpdateListener);
163 
164     /**
165      * Returns the latest (accepted) network time suggestion. Returns {@code null} if there isn't
166      * one.
167      */
168     @Nullable
getLatestNetworkSuggestion()169     NetworkTimeSuggestion getLatestNetworkSuggestion();
170 
171     /**
172      * Clears the latest network time suggestion, leaving none. The remaining time signals from
173      * other sources will be reassessed causing the device's time to be updated if config and
174      * settings allow.
175      */
clearLatestNetworkSuggestion()176     void clearLatestNetworkSuggestion();
177 
178     /** Processes the suggested time from gnss sources. */
suggestGnssTime(@onNull GnssTimeSuggestion suggestion)179     void suggestGnssTime(@NonNull GnssTimeSuggestion suggestion);
180 
181     /** Processes the suggested time from external sources. */
suggestExternalTime(@onNull ExternalTimeSuggestion suggestion)182     void suggestExternalTime(@NonNull ExternalTimeSuggestion suggestion);
183 
184     // Utility methods below are to be moved to a better home when one becomes more obvious.
185 
186     /**
187      * Converts one of the {@code ORIGIN_} constants to a human readable string suitable for config
188      * and debug usage. Throws an {@link IllegalArgumentException} if the value is unrecognized.
189      */
190     @NonNull
originToString(@rigin int origin)191     static String originToString(@Origin int origin) {
192         switch (origin) {
193             case ORIGIN_MANUAL:
194                 return "manual";
195             case ORIGIN_NETWORK:
196                 return "network";
197             case ORIGIN_TELEPHONY:
198                 return "telephony";
199             case ORIGIN_GNSS:
200                 return "gnss";
201             case ORIGIN_EXTERNAL:
202                 return "external";
203             default:
204                 throw new IllegalArgumentException("origin=" + origin);
205         }
206     }
207 
208     /**
209      * Converts a human readable config string to one of the {@code ORIGIN_} constants.
210      * Throws an {@link IllegalArgumentException} if the value is unrecognized or {@code null}.
211      */
stringToOrigin(String originString)212     static @Origin int stringToOrigin(String originString) {
213         Preconditions.checkArgument(originString != null);
214 
215         switch (originString) {
216             case "manual":
217                 return ORIGIN_MANUAL;
218             case "network":
219                 return ORIGIN_NETWORK;
220             case "telephony":
221                 return ORIGIN_TELEPHONY;
222             case "gnss":
223                 return ORIGIN_GNSS;
224             case "external":
225                 return ORIGIN_EXTERNAL;
226             default:
227                 throw new IllegalArgumentException("originString=" + originString);
228         }
229     }
230 }
231