blob: 50f27ed67a3651b18191ce532918bfc7bcb03fcf [file] [log] [blame]
Neil Fuller68f66662017-03-16 18:32:21 +00001/*
2 * Copyright (C) 2017 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
17package com.android.server.timezone;
18
19import com.android.internal.annotations.VisibleForTesting;
Neil Fullerd857f672017-07-20 11:00:35 +010020import com.android.server.EventLogTags;
Neil Fuller68f66662017-03-16 18:32:21 +000021import com.android.server.SystemService;
Neil Fullera6a71d02017-06-13 15:12:17 +010022import com.android.timezone.distro.DistroException;
23import com.android.timezone.distro.DistroVersion;
24import com.android.timezone.distro.StagedDistroOperation;
Neil Fuller54525bf2017-06-22 14:10:29 +010025import com.android.timezone.distro.TimeZoneDistro;
Neil Fuller5ca8b5b2017-06-29 12:39:49 +010026import com.android.timezone.distro.installer.TimeZoneDistroInstaller;
Neil Fuller68f66662017-03-16 18:32:21 +000027
28import android.app.timezone.Callback;
29import android.app.timezone.DistroFormatVersion;
30import android.app.timezone.DistroRulesVersion;
31import android.app.timezone.ICallback;
32import android.app.timezone.IRulesManager;
33import android.app.timezone.RulesManager;
34import android.app.timezone.RulesState;
35import android.content.Context;
36import android.os.ParcelFileDescriptor;
37import android.os.RemoteException;
38import android.util.Slog;
39
40import java.io.File;
Neil Fuller87b11282017-06-23 16:43:45 +010041import java.io.FileDescriptor;
Neil Fuller54525bf2017-06-22 14:10:29 +010042import java.io.FileInputStream;
Neil Fuller68f66662017-03-16 18:32:21 +000043import java.io.IOException;
Neil Fuller54525bf2017-06-22 14:10:29 +010044import java.io.InputStream;
Neil Fuller87b11282017-06-23 16:43:45 +010045import java.io.PrintWriter;
Neil Fuller68f66662017-03-16 18:32:21 +000046import java.util.Arrays;
47import java.util.concurrent.Executor;
48import java.util.concurrent.atomic.AtomicBoolean;
Neil Fuller87b11282017-06-23 16:43:45 +010049import libcore.icu.ICU;
50import libcore.util.ZoneInfoDB;
51
52import static android.app.timezone.RulesState.DISTRO_STATUS_INSTALLED;
53import static android.app.timezone.RulesState.DISTRO_STATUS_NONE;
54import static android.app.timezone.RulesState.DISTRO_STATUS_UNKNOWN;
55import static android.app.timezone.RulesState.STAGED_OPERATION_INSTALL;
56import static android.app.timezone.RulesState.STAGED_OPERATION_NONE;
57import static android.app.timezone.RulesState.STAGED_OPERATION_UNINSTALL;
58import static android.app.timezone.RulesState.STAGED_OPERATION_UNKNOWN;
Neil Fuller68f66662017-03-16 18:32:21 +000059
Neil Fuller68f66662017-03-16 18:32:21 +000060public final class RulesManagerService extends IRulesManager.Stub {
61
62 private static final String TAG = "timezone.RulesManagerService";
63
64 /** The distro format supported by this device. */
65 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
66 static final DistroFormatVersion DISTRO_FORMAT_VERSION_SUPPORTED =
67 new DistroFormatVersion(
68 DistroVersion.CURRENT_FORMAT_MAJOR_VERSION,
69 DistroVersion.CURRENT_FORMAT_MINOR_VERSION);
70
71 public static class Lifecycle extends SystemService {
72 private RulesManagerService mService;
73
74 public Lifecycle(Context context) {
75 super(context);
76 }
77
78 @Override
79 public void onStart() {
80 mService = RulesManagerService.create(getContext());
81 mService.start();
82
83 publishBinderService(Context.TIME_ZONE_RULES_MANAGER_SERVICE, mService);
84 }
85 }
86
87 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
88 static final String REQUIRED_UPDATER_PERMISSION =
89 android.Manifest.permission.UPDATE_TIME_ZONE_RULES;
90 private static final File SYSTEM_TZ_DATA_FILE = new File("/system/usr/share/zoneinfo/tzdata");
91 private static final File TZ_DATA_DIR = new File("/data/misc/zoneinfo");
92
93 private final AtomicBoolean mOperationInProgress = new AtomicBoolean(false);
94 private final PermissionHelper mPermissionHelper;
95 private final PackageTracker mPackageTracker;
96 private final Executor mExecutor;
97 private final TimeZoneDistroInstaller mInstaller;
Neil Fuller68f66662017-03-16 18:32:21 +000098
99 private static RulesManagerService create(Context context) {
100 RulesManagerServiceHelperImpl helper = new RulesManagerServiceHelperImpl(context);
101 return new RulesManagerService(
102 helper /* permissionHelper */,
103 helper /* executor */,
Neil Fuller68f66662017-03-16 18:32:21 +0000104 PackageTracker.create(context),
105 new TimeZoneDistroInstaller(TAG, SYSTEM_TZ_DATA_FILE, TZ_DATA_DIR));
106 }
107
108 // A constructor that can be used by tests to supply mocked / faked dependencies.
109 RulesManagerService(PermissionHelper permissionHelper,
Neil Fuller54525bf2017-06-22 14:10:29 +0100110 Executor executor, PackageTracker packageTracker,
Neil Fuller68f66662017-03-16 18:32:21 +0000111 TimeZoneDistroInstaller timeZoneDistroInstaller) {
112 mPermissionHelper = permissionHelper;
113 mExecutor = executor;
Neil Fuller68f66662017-03-16 18:32:21 +0000114 mPackageTracker = packageTracker;
115 mInstaller = timeZoneDistroInstaller;
116 }
117
118 public void start() {
119 mPackageTracker.start();
120 }
121
122 @Override // Binder call
123 public RulesState getRulesState() {
124 mPermissionHelper.enforceCallerHasPermission(REQUIRED_UPDATER_PERMISSION);
125
Neil Fuller87b11282017-06-23 16:43:45 +0100126 return getRulesStateInternal();
127 }
128
129 /** Like {@link #getRulesState()} without the permission check. */
130 private RulesState getRulesStateInternal() {
Neil Fuller68f66662017-03-16 18:32:21 +0000131 synchronized(this) {
132 String systemRulesVersion;
133 try {
134 systemRulesVersion = mInstaller.getSystemRulesVersion();
135 } catch (IOException e) {
136 Slog.w(TAG, "Failed to read system rules", e);
137 return null;
138 }
139
140 boolean operationInProgress = this.mOperationInProgress.get();
141
142 // Determine the staged operation status, if possible.
143 DistroRulesVersion stagedDistroRulesVersion = null;
Neil Fuller87b11282017-06-23 16:43:45 +0100144 int stagedOperationStatus = STAGED_OPERATION_UNKNOWN;
Neil Fuller68f66662017-03-16 18:32:21 +0000145 if (!operationInProgress) {
146 StagedDistroOperation stagedDistroOperation;
147 try {
148 stagedDistroOperation = mInstaller.getStagedDistroOperation();
149 if (stagedDistroOperation == null) {
Neil Fuller87b11282017-06-23 16:43:45 +0100150 stagedOperationStatus = STAGED_OPERATION_NONE;
Neil Fuller68f66662017-03-16 18:32:21 +0000151 } else if (stagedDistroOperation.isUninstall) {
Neil Fuller87b11282017-06-23 16:43:45 +0100152 stagedOperationStatus = STAGED_OPERATION_UNINSTALL;
Neil Fuller68f66662017-03-16 18:32:21 +0000153 } else {
154 // Must be an install.
Neil Fuller87b11282017-06-23 16:43:45 +0100155 stagedOperationStatus = STAGED_OPERATION_INSTALL;
Neil Fuller68f66662017-03-16 18:32:21 +0000156 DistroVersion stagedDistroVersion = stagedDistroOperation.distroVersion;
157 stagedDistroRulesVersion = new DistroRulesVersion(
158 stagedDistroVersion.rulesVersion,
159 stagedDistroVersion.revision);
160 }
161 } catch (DistroException | IOException e) {
162 Slog.w(TAG, "Failed to read staged distro.", e);
163 }
164 }
165
166 // Determine the installed distro state, if possible.
167 DistroVersion installedDistroVersion;
Neil Fuller87b11282017-06-23 16:43:45 +0100168 int distroStatus = DISTRO_STATUS_UNKNOWN;
Neil Fuller68f66662017-03-16 18:32:21 +0000169 DistroRulesVersion installedDistroRulesVersion = null;
170 if (!operationInProgress) {
171 try {
172 installedDistroVersion = mInstaller.getInstalledDistroVersion();
173 if (installedDistroVersion == null) {
Neil Fuller87b11282017-06-23 16:43:45 +0100174 distroStatus = DISTRO_STATUS_NONE;
Neil Fuller68f66662017-03-16 18:32:21 +0000175 installedDistroRulesVersion = null;
176 } else {
Neil Fuller87b11282017-06-23 16:43:45 +0100177 distroStatus = DISTRO_STATUS_INSTALLED;
Neil Fuller68f66662017-03-16 18:32:21 +0000178 installedDistroRulesVersion = new DistroRulesVersion(
179 installedDistroVersion.rulesVersion,
180 installedDistroVersion.revision);
181 }
182 } catch (DistroException | IOException e) {
183 Slog.w(TAG, "Failed to read installed distro.", e);
184 }
185 }
186 return new RulesState(systemRulesVersion, DISTRO_FORMAT_VERSION_SUPPORTED,
187 operationInProgress, stagedOperationStatus, stagedDistroRulesVersion,
188 distroStatus, installedDistroRulesVersion);
189 }
190 }
191
192 @Override
Neil Fuller54525bf2017-06-22 14:10:29 +0100193 public int requestInstall(ParcelFileDescriptor distroParcelFileDescriptor,
194 byte[] checkTokenBytes, ICallback callback) {
Neil Fuller68f66662017-03-16 18:32:21 +0000195
Neil Fuller54525bf2017-06-22 14:10:29 +0100196 boolean closeParcelFileDescriptorOnExit = true;
197 try {
198 mPermissionHelper.enforceCallerHasPermission(REQUIRED_UPDATER_PERMISSION);
Neil Fuller68f66662017-03-16 18:32:21 +0000199
Neil Fuller54525bf2017-06-22 14:10:29 +0100200 CheckToken checkToken = null;
201 if (checkTokenBytes != null) {
202 checkToken = createCheckTokenOrThrow(checkTokenBytes);
203 }
Neil Fullerd857f672017-07-20 11:00:35 +0100204 EventLogTags.writeTimezoneRequestInstall(toStringOrNull(checkToken));
Neil Fuller68f66662017-03-16 18:32:21 +0000205
Neil Fuller54525bf2017-06-22 14:10:29 +0100206 synchronized (this) {
207 if (distroParcelFileDescriptor == null) {
208 throw new NullPointerException("distroParcelFileDescriptor == null");
209 }
210 if (callback == null) {
211 throw new NullPointerException("observer == null");
212 }
213 if (mOperationInProgress.get()) {
214 return RulesManager.ERROR_OPERATION_IN_PROGRESS;
215 }
216 mOperationInProgress.set(true);
217
218 // Execute the install asynchronously.
219 mExecutor.execute(
220 new InstallRunnable(distroParcelFileDescriptor, checkToken, callback));
221
222 // The InstallRunnable now owns the ParcelFileDescriptor, so it will close it after
223 // it executes (and we do not have to).
224 closeParcelFileDescriptorOnExit = false;
225
226 return RulesManager.SUCCESS;
227 }
228 } finally {
229 // We should close() the local ParcelFileDescriptor we were passed if it hasn't been
230 // passed to another thread to handle.
231 if (distroParcelFileDescriptor != null && closeParcelFileDescriptorOnExit) {
232 try {
233 distroParcelFileDescriptor.close();
234 } catch (IOException e) {
235 Slog.w(TAG, "Failed to close distroParcelFileDescriptor", e);
236 }
237 }
Neil Fuller68f66662017-03-16 18:32:21 +0000238 }
239 }
240
241 private class InstallRunnable implements Runnable {
242
Neil Fuller54525bf2017-06-22 14:10:29 +0100243 private final ParcelFileDescriptor mDistroParcelFileDescriptor;
Neil Fuller68f66662017-03-16 18:32:21 +0000244 private final CheckToken mCheckToken;
245 private final ICallback mCallback;
246
Neil Fuller54525bf2017-06-22 14:10:29 +0100247 InstallRunnable(ParcelFileDescriptor distroParcelFileDescriptor, CheckToken checkToken,
248 ICallback callback) {
249 mDistroParcelFileDescriptor = distroParcelFileDescriptor;
Neil Fuller68f66662017-03-16 18:32:21 +0000250 mCheckToken = checkToken;
251 mCallback = callback;
252 }
253
254 @Override
255 public void run() {
Neil Fullerd857f672017-07-20 11:00:35 +0100256 EventLogTags.writeTimezoneInstallStarted(toStringOrNull(mCheckToken));
257
Neil Fuller54525bf2017-06-22 14:10:29 +0100258 boolean success = false;
Neil Fuller68f66662017-03-16 18:32:21 +0000259 // Adopt the ParcelFileDescriptor into this try-with-resources so it is closed
260 // when we are done.
Neil Fuller54525bf2017-06-22 14:10:29 +0100261 try (ParcelFileDescriptor pfd = mDistroParcelFileDescriptor) {
262 // The ParcelFileDescriptor owns the underlying FileDescriptor and we'll close
263 // it at the end of the try-with-resources.
264 final boolean isFdOwner = false;
265 InputStream is = new FileInputStream(pfd.getFileDescriptor(), isFdOwner);
266
267 TimeZoneDistro distro = new TimeZoneDistro(is);
Neil Fullerfe3b1182017-06-19 12:56:08 +0100268 int installerResult = mInstaller.stageInstallWithErrorCode(distro);
Neil Fuller68f66662017-03-16 18:32:21 +0000269 int resultCode = mapInstallerResultToApiCode(installerResult);
Neil Fullerd857f672017-07-20 11:00:35 +0100270 EventLogTags.writeTimezoneInstallComplete(toStringOrNull(mCheckToken), resultCode);
Neil Fuller68f66662017-03-16 18:32:21 +0000271 sendFinishedStatus(mCallback, resultCode);
272
273 // All the installer failure modes are currently non-recoverable and won't be
274 // improved by trying again. Therefore success = true.
275 success = true;
276 } catch (Exception e) {
277 Slog.w(TAG, "Failed to install distro.", e);
Neil Fullerd857f672017-07-20 11:00:35 +0100278 EventLogTags.writeTimezoneInstallComplete(
279 toStringOrNull(mCheckToken), Callback.ERROR_UNKNOWN_FAILURE);
Neil Fuller68f66662017-03-16 18:32:21 +0000280 sendFinishedStatus(mCallback, Callback.ERROR_UNKNOWN_FAILURE);
281 } finally {
282 // Notify the package tracker that the operation is now complete.
283 mPackageTracker.recordCheckResult(mCheckToken, success);
284
285 mOperationInProgress.set(false);
286 }
287 }
288
289 private int mapInstallerResultToApiCode(int installerResult) {
290 switch (installerResult) {
291 case TimeZoneDistroInstaller.INSTALL_SUCCESS:
292 return Callback.SUCCESS;
293 case TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE:
294 return Callback.ERROR_INSTALL_BAD_DISTRO_STRUCTURE;
295 case TimeZoneDistroInstaller.INSTALL_FAIL_RULES_TOO_OLD:
296 return Callback.ERROR_INSTALL_RULES_TOO_OLD;
297 case TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_FORMAT_VERSION:
298 return Callback.ERROR_INSTALL_BAD_DISTRO_FORMAT_VERSION;
299 case TimeZoneDistroInstaller.INSTALL_FAIL_VALIDATION_ERROR:
300 return Callback.ERROR_INSTALL_VALIDATION_ERROR;
301 default:
302 return Callback.ERROR_UNKNOWN_FAILURE;
303 }
304 }
305 }
306
307 @Override
308 public int requestUninstall(byte[] checkTokenBytes, ICallback callback) {
309 mPermissionHelper.enforceCallerHasPermission(REQUIRED_UPDATER_PERMISSION);
310
311 CheckToken checkToken = null;
312 if (checkTokenBytes != null) {
313 checkToken = createCheckTokenOrThrow(checkTokenBytes);
314 }
Neil Fullerd857f672017-07-20 11:00:35 +0100315 EventLogTags.writeTimezoneRequestUninstall(toStringOrNull(checkToken));
Neil Fuller68f66662017-03-16 18:32:21 +0000316 synchronized(this) {
317 if (callback == null) {
318 throw new NullPointerException("callback == null");
319 }
320
321 if (mOperationInProgress.get()) {
322 return RulesManager.ERROR_OPERATION_IN_PROGRESS;
323 }
324 mOperationInProgress.set(true);
325
326 // Execute the uninstall asynchronously.
327 mExecutor.execute(new UninstallRunnable(checkToken, callback));
328
329 return RulesManager.SUCCESS;
330 }
331 }
332
333 private class UninstallRunnable implements Runnable {
334
335 private final CheckToken mCheckToken;
336 private final ICallback mCallback;
337
Neil Fullera47c3632017-07-26 13:56:25 +0100338 UninstallRunnable(CheckToken checkToken, ICallback callback) {
Neil Fuller68f66662017-03-16 18:32:21 +0000339 mCheckToken = checkToken;
340 mCallback = callback;
341 }
342
343 @Override
344 public void run() {
Neil Fullerd857f672017-07-20 11:00:35 +0100345 EventLogTags.writeTimezoneUninstallStarted(toStringOrNull(mCheckToken));
Neil Fuller68f66662017-03-16 18:32:21 +0000346 boolean success = false;
347 try {
348 success = mInstaller.stageUninstall();
349 // Right now we just have success (0) / failure (1). All clients should be checking
350 // against SUCCESS. More granular failures may be added in future.
351 int resultCode = success ? Callback.SUCCESS
352 : Callback.ERROR_UNKNOWN_FAILURE;
Neil Fullerd857f672017-07-20 11:00:35 +0100353 EventLogTags.writeTimezoneUninstallComplete(
354 toStringOrNull(mCheckToken), resultCode);
Neil Fuller68f66662017-03-16 18:32:21 +0000355 sendFinishedStatus(mCallback, resultCode);
356 } catch (Exception e) {
Neil Fullerd857f672017-07-20 11:00:35 +0100357 EventLogTags.writeTimezoneUninstallComplete(
358 toStringOrNull(mCheckToken), Callback.ERROR_UNKNOWN_FAILURE);
Neil Fuller68f66662017-03-16 18:32:21 +0000359 Slog.w(TAG, "Failed to uninstall distro.", e);
360 sendFinishedStatus(mCallback, Callback.ERROR_UNKNOWN_FAILURE);
361 } finally {
362 // Notify the package tracker that the operation is now complete.
363 mPackageTracker.recordCheckResult(mCheckToken, success);
364
365 mOperationInProgress.set(false);
366 }
367 }
368 }
369
370 private void sendFinishedStatus(ICallback callback, int resultCode) {
371 try {
372 callback.onFinished(resultCode);
373 } catch (RemoteException e) {
374 Slog.e(TAG, "Unable to notify observer of result", e);
375 }
376 }
377
378 @Override
379 public void requestNothing(byte[] checkTokenBytes, boolean success) {
380 mPermissionHelper.enforceCallerHasPermission(REQUIRED_UPDATER_PERMISSION);
381 CheckToken checkToken = null;
382 if (checkTokenBytes != null) {
383 checkToken = createCheckTokenOrThrow(checkTokenBytes);
384 }
Neil Fullerd857f672017-07-20 11:00:35 +0100385 EventLogTags.writeTimezoneRequestNothing(toStringOrNull(checkToken));
Neil Fuller68f66662017-03-16 18:32:21 +0000386 mPackageTracker.recordCheckResult(checkToken, success);
Neil Fullerd857f672017-07-20 11:00:35 +0100387 EventLogTags.writeTimezoneNothingComplete(toStringOrNull(checkToken));
Neil Fuller68f66662017-03-16 18:32:21 +0000388 }
389
Neil Fuller87b11282017-06-23 16:43:45 +0100390 @Override
391 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
392 if (!mPermissionHelper.checkDumpPermission(TAG, pw)) {
393 return;
394 }
395
396 RulesState rulesState = getRulesStateInternal();
397 if (args != null && args.length == 2) {
398 // Formatting options used for automated tests. The format is less free-form than
399 // the -format options, which are intended to be easier to parse.
400 if ("-format_state".equals(args[0]) && args[1] != null) {
401 for (char c : args[1].toCharArray()) {
402 switch (c) {
Neil Fullera47c3632017-07-26 13:56:25 +0100403 case 'p': {
404 // Report operation in progress
405 String value = "Unknown";
406 if (rulesState != null) {
407 value = Boolean.toString(rulesState.isOperationInProgress());
Neil Fuller87b11282017-06-23 16:43:45 +0100408 }
Neil Fullera47c3632017-07-26 13:56:25 +0100409 pw.println("Operation in progress: " + value);
Neil Fuller87b11282017-06-23 16:43:45 +0100410 break;
Neil Fullera47c3632017-07-26 13:56:25 +0100411 }
412 case 's': {
413 // Report system image rules version
414 String value = "Unknown";
415 if (rulesState != null) {
416 value = rulesState.getSystemRulesVersion();
417 }
418 pw.println("System rules version: " + value);
Neil Fuller87b11282017-06-23 16:43:45 +0100419 break;
Neil Fullera47c3632017-07-26 13:56:25 +0100420 }
421 case 'c': {
422 // Report current installation state
423 String value = "Unknown";
424 if (rulesState != null) {
425 value = distroStatusToString(rulesState.getDistroStatus());
426 }
427 pw.println("Current install state: " + value);
428 break;
429 }
430 case 'i': {
431 // Report currently installed version
432 String value = "Unknown";
433 if (rulesState != null) {
434 DistroRulesVersion installedRulesVersion =
435 rulesState.getInstalledDistroRulesVersion();
436 if (installedRulesVersion == null) {
437 value = "<None>";
438 } else {
439 value = installedRulesVersion.toDumpString();
440 }
441 }
442 pw.println("Installed rules version: " + value);
443 break;
444 }
445 case 'o': {
446 // Report staged operation type
447 String value = "Unknown";
448 if (rulesState != null) {
449 int stagedOperationType = rulesState.getStagedOperationType();
450 value = stagedOperationToString(stagedOperationType);
451 }
452 pw.println("Staged operation: " + value);
453 break;
454 }
455 case 't': {
Neil Fuller87b11282017-06-23 16:43:45 +0100456 // Report staged version (i.e. the one that will be installed next boot
457 // if the staged operation is an install).
Neil Fullera47c3632017-07-26 13:56:25 +0100458 String value = "Unknown";
459 if (rulesState != null) {
460 DistroRulesVersion stagedDistroRulesVersion =
461 rulesState.getStagedDistroRulesVersion();
462 if (stagedDistroRulesVersion == null) {
463 value = "<None>";
464 } else {
465 value = stagedDistroRulesVersion.toDumpString();
466 }
Neil Fuller87b11282017-06-23 16:43:45 +0100467 }
Neil Fullera47c3632017-07-26 13:56:25 +0100468 pw.println("Staged rules version: " + value);
Neil Fuller87b11282017-06-23 16:43:45 +0100469 break;
Neil Fullera47c3632017-07-26 13:56:25 +0100470 }
471 case 'a': {
Neil Fuller87b11282017-06-23 16:43:45 +0100472 // Report the active rules version (i.e. the rules in use by the current
473 // process).
474 pw.println("Active rules version (ICU, libcore): "
475 + ICU.getTZDataVersion() + ","
476 + ZoneInfoDB.getInstance().getVersion());
477 break;
Neil Fullera47c3632017-07-26 13:56:25 +0100478 }
479 default: {
Neil Fuller87b11282017-06-23 16:43:45 +0100480 pw.println("Unknown option: " + c);
Neil Fullera47c3632017-07-26 13:56:25 +0100481 }
Neil Fuller87b11282017-06-23 16:43:45 +0100482 }
483 }
484 return;
485 }
486 }
487
488 pw.println("RulesManagerService state: " + toString());
489 pw.println("Active rules version (ICU, libcore): " + ICU.getTZDataVersion() + ","
490 + ZoneInfoDB.getInstance().getVersion());
Neil Fullerd857f672017-07-20 11:00:35 +0100491 pw.println("Distro state: " + rulesState.toString());
Neil Fuller87b11282017-06-23 16:43:45 +0100492 mPackageTracker.dump(pw);
493 }
494
495 @Override
496 public String toString() {
497 return "RulesManagerService{" +
498 "mOperationInProgress=" + mOperationInProgress +
499 '}';
500 }
501
Neil Fuller68f66662017-03-16 18:32:21 +0000502 private static CheckToken createCheckTokenOrThrow(byte[] checkTokenBytes) {
503 CheckToken checkToken;
504 try {
505 checkToken = CheckToken.fromByteArray(checkTokenBytes);
506 } catch (IOException e) {
507 throw new IllegalArgumentException("Unable to read token bytes "
508 + Arrays.toString(checkTokenBytes), e);
509 }
510 return checkToken;
511 }
Neil Fuller87b11282017-06-23 16:43:45 +0100512
513 private static String distroStatusToString(int distroStatus) {
514 switch(distroStatus) {
515 case DISTRO_STATUS_NONE:
516 return "None";
517 case DISTRO_STATUS_INSTALLED:
518 return "Installed";
519 case DISTRO_STATUS_UNKNOWN:
520 default:
521 return "Unknown";
522 }
523 }
524
525 private static String stagedOperationToString(int stagedOperationType) {
526 switch(stagedOperationType) {
527 case STAGED_OPERATION_NONE:
528 return "None";
529 case STAGED_OPERATION_UNINSTALL:
530 return "Uninstall";
531 case STAGED_OPERATION_INSTALL:
532 return "Install";
533 case STAGED_OPERATION_UNKNOWN:
534 default:
535 return "Unknown";
536 }
537 }
Neil Fullerd857f672017-07-20 11:00:35 +0100538
539 private static String toStringOrNull(Object obj) {
540 return obj == null ? null : obj.toString();
541 }
Neil Fuller68f66662017-03-16 18:32:21 +0000542}