1 /*
2  * Copyright (C) 2021 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.timedetector;
17 
18 import static android.app.timedetector.TimeDetector.SHELL_COMMAND_CLEAR_NETWORK_TIME;
19 import static android.app.timedetector.TimeDetector.SHELL_COMMAND_CLEAR_SYSTEM_CLOCK_NETWORK_TIME;
20 import static android.app.timedetector.TimeDetector.SHELL_COMMAND_CONFIRM_TIME;
21 import static android.app.timedetector.TimeDetector.SHELL_COMMAND_GET_NETWORK_TIME;
22 import static android.app.timedetector.TimeDetector.SHELL_COMMAND_GET_TIME_STATE;
23 import static android.app.timedetector.TimeDetector.SHELL_COMMAND_IS_AUTO_DETECTION_ENABLED;
24 import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SERVICE_NAME;
25 import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SET_AUTO_DETECTION_ENABLED;
26 import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SET_SYSTEM_CLOCK_NETWORK_TIME;
27 import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SET_TIME_STATE;
28 import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SUGGEST_EXTERNAL_TIME;
29 import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SUGGEST_GNSS_TIME;
30 import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SUGGEST_MANUAL_TIME;
31 import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SUGGEST_NETWORK_TIME;
32 import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SUGGEST_TELEPHONY_TIME;
33 import static android.provider.DeviceConfig.NAMESPACE_SYSTEM_TIME;
34 
35 import static com.android.server.timedetector.ServerFlags.KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE;
36 import static com.android.server.timedetector.ServerFlags.KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE;
37 
38 import android.app.time.ExternalTimeSuggestion;
39 import android.app.time.TimeConfiguration;
40 import android.app.time.TimeState;
41 import android.app.time.UnixEpochTime;
42 import android.app.timedetector.ManualTimeSuggestion;
43 import android.app.timedetector.TelephonyTimeSuggestion;
44 import android.os.ShellCommand;
45 import android.os.UserHandle;
46 
47 import java.io.PrintWriter;
48 import java.util.function.Consumer;
49 import java.util.function.Supplier;
50 
51 /** Implements the shell command interface for {@link TimeDetectorService}. */
52 class TimeDetectorShellCommand extends ShellCommand {
53 
54     private final TimeDetectorService mInterface;
55 
TimeDetectorShellCommand(TimeDetectorService timeDetectorService)56     TimeDetectorShellCommand(TimeDetectorService timeDetectorService) {
57         mInterface = timeDetectorService;
58     }
59 
60     @Override
onCommand(String cmd)61     public int onCommand(String cmd) {
62         if (cmd == null) {
63             return handleDefaultCommands(cmd);
64         }
65 
66         switch (cmd) {
67             case SHELL_COMMAND_IS_AUTO_DETECTION_ENABLED:
68                 return runIsAutoDetectionEnabled();
69             case SHELL_COMMAND_SET_AUTO_DETECTION_ENABLED:
70                 return runSetAutoDetectionEnabled();
71             case SHELL_COMMAND_SUGGEST_MANUAL_TIME:
72                 return runSuggestManualTime();
73             case SHELL_COMMAND_SUGGEST_TELEPHONY_TIME:
74                 return runSuggestTelephonyTime();
75             case SHELL_COMMAND_SUGGEST_NETWORK_TIME:
76                 return runSuggestNetworkTime();
77             case SHELL_COMMAND_GET_NETWORK_TIME:
78                 return runGetLatestNetworkTime();
79             case SHELL_COMMAND_CLEAR_NETWORK_TIME:
80                 return runClearLatestNetworkTime();
81             case SHELL_COMMAND_SUGGEST_GNSS_TIME:
82                 return runSuggestGnssTime();
83             case SHELL_COMMAND_SUGGEST_EXTERNAL_TIME:
84                 return runSuggestExternalTime();
85             case SHELL_COMMAND_GET_TIME_STATE:
86                 return runGetTimeState();
87             case SHELL_COMMAND_SET_TIME_STATE:
88                 return runSetTimeState();
89             case SHELL_COMMAND_CONFIRM_TIME:
90                 return runConfirmTime();
91             case SHELL_COMMAND_CLEAR_SYSTEM_CLOCK_NETWORK_TIME:
92                 return runClearSystemClockNetworkTime();
93             case SHELL_COMMAND_SET_SYSTEM_CLOCK_NETWORK_TIME:
94                 return runSetSystemClockNetworkTime();
95             default: {
96                 return handleDefaultCommands(cmd);
97             }
98         }
99     }
100 
runIsAutoDetectionEnabled()101     private int runIsAutoDetectionEnabled() {
102         final PrintWriter pw = getOutPrintWriter();
103         boolean enabled = mInterface.getCapabilitiesAndConfig()
104                 .getConfiguration()
105                 .isAutoDetectionEnabled();
106         pw.println(enabled);
107         return 0;
108     }
109 
runSetAutoDetectionEnabled()110     private int runSetAutoDetectionEnabled() {
111         boolean enabled = Boolean.parseBoolean(getNextArgRequired());
112         int userId = UserHandle.USER_CURRENT;
113         TimeConfiguration configuration = new TimeConfiguration.Builder()
114                 .setAutoDetectionEnabled(enabled)
115                 .build();
116         return mInterface.updateConfiguration(userId, configuration) ? 0 : 1;
117     }
118 
runSuggestManualTime()119     private int runSuggestManualTime() {
120         return runSuggestTime(
121                 () -> ManualTimeSuggestion.parseCommandLineArg(this),
122                 mInterface::suggestManualTime);
123     }
124 
runSuggestTelephonyTime()125     private int runSuggestTelephonyTime() {
126         return runSuggestTime(
127                 () -> TelephonyTimeSuggestion.parseCommandLineArg(this),
128                 mInterface::suggestTelephonyTime);
129     }
130 
runSuggestNetworkTime()131     private int runSuggestNetworkTime() {
132         return runSuggestTime(
133                 () -> NetworkTimeSuggestion.parseCommandLineArg(this),
134                 mInterface::suggestNetworkTime);
135     }
136 
runGetLatestNetworkTime()137     private int runGetLatestNetworkTime() {
138         NetworkTimeSuggestion networkTimeSuggestion = mInterface.getLatestNetworkSuggestion();
139         final PrintWriter pw = getOutPrintWriter();
140         pw.println(networkTimeSuggestion);
141         return 0;
142     }
143 
runClearLatestNetworkTime()144     private int runClearLatestNetworkTime() {
145         mInterface.clearLatestNetworkTime();
146         return 0;
147     }
148 
runSuggestGnssTime()149     private int runSuggestGnssTime() {
150         return runSuggestTime(
151                 () -> GnssTimeSuggestion.parseCommandLineArg(this),
152                 mInterface::suggestGnssTime);
153     }
154 
runSuggestExternalTime()155     private int runSuggestExternalTime() {
156         return runSuggestTime(
157                 () -> ExternalTimeSuggestion.parseCommandLineArg(this),
158                 mInterface::suggestExternalTime);
159     }
160 
runSuggestTime(Supplier<T> suggestionParser, Consumer<T> invoker)161     private <T> int runSuggestTime(Supplier<T> suggestionParser, Consumer<T> invoker) {
162         final PrintWriter pw = getOutPrintWriter();
163         try {
164             T suggestion = suggestionParser.get();
165             if (suggestion == null) {
166                 pw.println("Error: suggestion not specified");
167                 return 1;
168             }
169             invoker.accept(suggestion);
170             pw.println("Suggestion " + suggestion + " injected.");
171             return 0;
172         } catch (RuntimeException e) {
173             pw.println(e);
174             return 1;
175         }
176     }
177 
runGetTimeState()178     private int runGetTimeState() {
179         TimeState timeState = mInterface.getTimeState();
180         getOutPrintWriter().println(timeState);
181         return 0;
182     }
183 
runSetTimeState()184     private int runSetTimeState() {
185         TimeState timeState = TimeState.parseCommandLineArgs(this);
186         mInterface.setTimeState(timeState);
187         return 0;
188     }
189 
runConfirmTime()190     private int runConfirmTime() {
191         UnixEpochTime unixEpochTime = UnixEpochTime.parseCommandLineArgs(this);
192         getOutPrintWriter().println(mInterface.confirmTime(unixEpochTime));
193         return 0;
194     }
195 
runClearSystemClockNetworkTime()196     private int runClearSystemClockNetworkTime() {
197         mInterface.clearNetworkTimeForSystemClockForTests();
198         return 0;
199     }
200 
runSetSystemClockNetworkTime()201     private int runSetSystemClockNetworkTime() {
202         NetworkTimeSuggestion networkTimeSuggestion =
203                 NetworkTimeSuggestion.parseCommandLineArg(this);
204         mInterface.setNetworkTimeForSystemClockForTests(
205                 networkTimeSuggestion.getUnixEpochTime(),
206                 networkTimeSuggestion.getUncertaintyMillis());
207         return 0;
208     }
209 
210     @Override
onHelp()211     public void onHelp() {
212         final PrintWriter pw = getOutPrintWriter();
213         pw.printf("Time Detector (%s) commands:\n", SHELL_COMMAND_SERVICE_NAME);
214         pw.printf("  help\n");
215         pw.printf("    Print this help text.\n");
216         pw.printf("  %s\n", SHELL_COMMAND_IS_AUTO_DETECTION_ENABLED);
217         pw.printf("    Prints true/false according to the automatic time detection setting.\n");
218         pw.printf("  %s true|false\n", SHELL_COMMAND_SET_AUTO_DETECTION_ENABLED);
219         pw.printf("    Sets the automatic time detection setting.\n");
220         pw.println();
221         pw.printf("  %s <manual suggestion opts>\n", SHELL_COMMAND_SUGGEST_MANUAL_TIME);
222         pw.printf("    Suggests a time as if via the \"manual\" origin.\n");
223         pw.printf("  %s <telephony suggestion opts>\n", SHELL_COMMAND_SUGGEST_TELEPHONY_TIME);
224         pw.printf("    Suggests a time as if via the \"telephony\" origin.\n");
225         pw.printf("  %s <network suggestion opts>\n", SHELL_COMMAND_SUGGEST_NETWORK_TIME);
226         pw.printf("    Suggests a time as if via the \"network\" origin.\n");
227         pw.printf("  %s <gnss suggestion opts>\n", SHELL_COMMAND_SUGGEST_GNSS_TIME);
228         pw.printf("    Suggests a time as if via the \"gnss\" origin.\n");
229         pw.printf("  %s <external suggestion opts>\n", SHELL_COMMAND_SUGGEST_EXTERNAL_TIME);
230         pw.printf("    Suggests a time as if via the \"external\" origin.\n");
231         pw.printf("  %s\n", SHELL_COMMAND_GET_TIME_STATE);
232         pw.printf("    Returns the current time setting state.\n");
233         pw.printf("  %s <time state options>\n", SHELL_COMMAND_SET_TIME_STATE);
234         pw.printf("    Sets the current time state for tests.\n");
235         pw.printf("  %s <unix epoch time options>\n", SHELL_COMMAND_CONFIRM_TIME);
236         pw.printf("    Tries to confirms the time, raising the confidence.\n");
237         pw.printf("  %s\n", SHELL_COMMAND_GET_NETWORK_TIME);
238         pw.printf("    Prints the network time information held by the detector.\n");
239         pw.printf("  %s\n", SHELL_COMMAND_CLEAR_NETWORK_TIME);
240         pw.printf("    Clears the network time information held by the detector.\n");
241         // TODO(b/222295093) Remove these "system_clock" commands when
242         //  SystemClock.currentNetworkTimeClock() is guaranteed to use the latest network
243         //  suggestion. Then, commands above can be used instead.
244         pw.printf("  %s <network suggestion opts>\n",
245                 SHELL_COMMAND_SET_SYSTEM_CLOCK_NETWORK_TIME);
246         pw.printf("    Sets the network time information used for"
247                 + " SystemClock.currentNetworkTimeClock().\n");
248         pw.printf("  %s\n", SHELL_COMMAND_CLEAR_SYSTEM_CLOCK_NETWORK_TIME);
249         pw.printf("    Clears the network time information used for"
250                 + " SystemClock.currentNetworkTimeClock().\n");
251         pw.println();
252         ManualTimeSuggestion.printCommandLineOpts(pw);
253         pw.println();
254         TelephonyTimeSuggestion.printCommandLineOpts(pw);
255         pw.println();
256         NetworkTimeSuggestion.printCommandLineOpts(pw);
257         pw.println();
258         GnssTimeSuggestion.printCommandLineOpts(pw);
259         pw.println();
260         ExternalTimeSuggestion.printCommandLineOpts(pw);
261         pw.println();
262         TimeState.printCommandLineOpts(pw);
263         pw.println();
264         UnixEpochTime.printCommandLineOpts(pw);
265         pw.println();
266         pw.printf("This service is also affected by the following device_config flags in the"
267                 + " %s namespace:\n", NAMESPACE_SYSTEM_TIME);
268         pw.printf("  %s\n", KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE);
269         pw.printf("    The lower bound used to validate time suggestions when they are received."
270                 + "\n");
271         pw.printf("    Specified in milliseconds since the start of the Unix epoch.\n");
272         pw.printf("  %s\n", KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE);
273         pw.printf("    A comma separated list of origins. See TimeDetectorStrategy for details.\n");
274         pw.println();
275         pw.printf("See \"adb shell cmd device_config\" for more information on setting flags.\n");
276         pw.println();
277     }
278 }
279