168f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller/* 268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller * Copyright (C) 2017 The Android Open Source Project 368f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller * 468f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller * Licensed under the Apache License, Version 2.0 (the "License"); 568f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller * you may not use this file except in compliance with the License. 668f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller * You may obtain a copy of the License at 768f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller * 868f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller * http://www.apache.org/licenses/LICENSE-2.0 968f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller * 1068f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller * Unless required by applicable law or agreed to in writing, software 1168f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller * distributed under the License is distributed on an "AS IS" BASIS, 1268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1368f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller * See the License for the specific language governing permissions and 1468f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller * limitations under the License. 1568f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller */ 1668f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 1768f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fullerpackage com.android.server.timezone; 1868f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 1968f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fullerimport com.android.internal.annotations.VisibleForTesting; 20d857f676744af55c79c4871c881bf9598f6b21e9Neil Fullerimport com.android.server.EventLogTags; 2168f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fullerimport com.android.server.SystemService; 22a6a71d0cd57d9f01605d0177032cd6bd1f4555f7Neil Fullerimport com.android.timezone.distro.DistroException; 23a6a71d0cd57d9f01605d0177032cd6bd1f4555f7Neil Fullerimport com.android.timezone.distro.DistroVersion; 24a6a71d0cd57d9f01605d0177032cd6bd1f4555f7Neil Fullerimport com.android.timezone.distro.StagedDistroOperation; 2554525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fullerimport com.android.timezone.distro.TimeZoneDistro; 265ca8b5bf77acb2e184ff374e9e028cfc2f168eaeNeil Fullerimport com.android.timezone.distro.installer.TimeZoneDistroInstaller; 2768f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 2868f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fullerimport android.app.timezone.Callback; 2968f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fullerimport android.app.timezone.DistroFormatVersion; 3068f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fullerimport android.app.timezone.DistroRulesVersion; 3168f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fullerimport android.app.timezone.ICallback; 3268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fullerimport android.app.timezone.IRulesManager; 3368f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fullerimport android.app.timezone.RulesManager; 3468f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fullerimport android.app.timezone.RulesState; 3568f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fullerimport android.content.Context; 3668f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fullerimport android.os.ParcelFileDescriptor; 3768f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fullerimport android.os.RemoteException; 3868f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fullerimport android.util.Slog; 3968f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 4068f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fullerimport java.io.File; 4187b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fullerimport java.io.FileDescriptor; 4254525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fullerimport java.io.FileInputStream; 4368f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fullerimport java.io.IOException; 4454525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fullerimport java.io.InputStream; 4587b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fullerimport java.io.PrintWriter; 4668f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fullerimport java.util.Arrays; 4768f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fullerimport java.util.concurrent.Executor; 4868f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fullerimport java.util.concurrent.atomic.AtomicBoolean; 4987b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fullerimport libcore.icu.ICU; 50c90361404a1560d60756e4199af04d25ef688e2cNeil Fullerimport libcore.util.TimeZoneFinder; 5187b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fullerimport libcore.util.ZoneInfoDB; 5287b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller 5387b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fullerimport static android.app.timezone.RulesState.DISTRO_STATUS_INSTALLED; 5487b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fullerimport static android.app.timezone.RulesState.DISTRO_STATUS_NONE; 5587b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fullerimport static android.app.timezone.RulesState.DISTRO_STATUS_UNKNOWN; 5687b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fullerimport static android.app.timezone.RulesState.STAGED_OPERATION_INSTALL; 5787b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fullerimport static android.app.timezone.RulesState.STAGED_OPERATION_NONE; 5887b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fullerimport static android.app.timezone.RulesState.STAGED_OPERATION_UNINSTALL; 5987b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fullerimport static android.app.timezone.RulesState.STAGED_OPERATION_UNKNOWN; 6068f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 6168f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fullerpublic final class RulesManagerService extends IRulesManager.Stub { 6268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 6368f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller private static final String TAG = "timezone.RulesManagerService"; 6468f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 6568f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller /** The distro format supported by this device. */ 6668f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) 6768f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller static final DistroFormatVersion DISTRO_FORMAT_VERSION_SUPPORTED = 6868f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller new DistroFormatVersion( 6968f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller DistroVersion.CURRENT_FORMAT_MAJOR_VERSION, 7068f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller DistroVersion.CURRENT_FORMAT_MINOR_VERSION); 7168f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 7268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller public static class Lifecycle extends SystemService { 7368f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller public Lifecycle(Context context) { 7468f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller super(context); 7568f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 7668f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 7768f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller @Override 7868f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller public void onStart() { 79cd1a109b872f58f5baa0ce8438bf3ddd69eec9fcNeil Fuller RulesManagerService service = RulesManagerService.create(getContext()); 80cd1a109b872f58f5baa0ce8438bf3ddd69eec9fcNeil Fuller service.start(); 81cd1a109b872f58f5baa0ce8438bf3ddd69eec9fcNeil Fuller 82cd1a109b872f58f5baa0ce8438bf3ddd69eec9fcNeil Fuller // Publish the binder service so it can be accessed from other (appropriately 83cd1a109b872f58f5baa0ce8438bf3ddd69eec9fcNeil Fuller // permissioned) processes. 84cd1a109b872f58f5baa0ce8438bf3ddd69eec9fcNeil Fuller publishBinderService(Context.TIME_ZONE_RULES_MANAGER_SERVICE, service); 8568f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 86cd1a109b872f58f5baa0ce8438bf3ddd69eec9fcNeil Fuller // Publish the service instance locally so we can use it directly from within the system 87cd1a109b872f58f5baa0ce8438bf3ddd69eec9fcNeil Fuller // server from TimeZoneUpdateIdler. 88cd1a109b872f58f5baa0ce8438bf3ddd69eec9fcNeil Fuller publishLocalService(RulesManagerService.class, service); 8968f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 9068f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 9168f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 9268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) 9368f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller static final String REQUIRED_UPDATER_PERMISSION = 9468f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller android.Manifest.permission.UPDATE_TIME_ZONE_RULES; 95b214bc44f1942b957f60dad75517e07cede77f18Neil Fuller @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) 96b214bc44f1942b957f60dad75517e07cede77f18Neil Fuller static final String REQUIRED_QUERY_PERMISSION = 97b214bc44f1942b957f60dad75517e07cede77f18Neil Fuller android.Manifest.permission.QUERY_TIME_ZONE_RULES; 9868f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller private static final File SYSTEM_TZ_DATA_FILE = new File("/system/usr/share/zoneinfo/tzdata"); 9968f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller private static final File TZ_DATA_DIR = new File("/data/misc/zoneinfo"); 10068f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 10168f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller private final AtomicBoolean mOperationInProgress = new AtomicBoolean(false); 10268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller private final PermissionHelper mPermissionHelper; 10368f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller private final PackageTracker mPackageTracker; 10468f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller private final Executor mExecutor; 105b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller private final RulesManagerIntentHelper mIntentHelper; 10668f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller private final TimeZoneDistroInstaller mInstaller; 10768f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 10868f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller private static RulesManagerService create(Context context) { 10968f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller RulesManagerServiceHelperImpl helper = new RulesManagerServiceHelperImpl(context); 11068f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller return new RulesManagerService( 11168f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller helper /* permissionHelper */, 11268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller helper /* executor */, 113b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller helper /* intentHelper */, 11468f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller PackageTracker.create(context), 11568f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller new TimeZoneDistroInstaller(TAG, SYSTEM_TZ_DATA_FILE, TZ_DATA_DIR)); 11668f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 11768f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 11868f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller // A constructor that can be used by tests to supply mocked / faked dependencies. 119b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) 120b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller RulesManagerService(PermissionHelper permissionHelper, Executor executor, 121b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller RulesManagerIntentHelper intentHelper, PackageTracker packageTracker, 12268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller TimeZoneDistroInstaller timeZoneDistroInstaller) { 12368f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller mPermissionHelper = permissionHelper; 12468f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller mExecutor = executor; 125b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller mIntentHelper = intentHelper; 12668f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller mPackageTracker = packageTracker; 12768f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller mInstaller = timeZoneDistroInstaller; 12868f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 12968f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 13068f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller public void start() { 1313582259c72476c55b60f49da1c7f1338b6683249Neil Fuller // Return value deliberately ignored: no action required on failure to start. 13268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller mPackageTracker.start(); 13368f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 13468f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 13568f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller @Override // Binder call 13668f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller public RulesState getRulesState() { 137b214bc44f1942b957f60dad75517e07cede77f18Neil Fuller mPermissionHelper.enforceCallerHasPermission(REQUIRED_QUERY_PERMISSION); 13868f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 13987b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller return getRulesStateInternal(); 14087b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller } 14187b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller 14287b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller /** Like {@link #getRulesState()} without the permission check. */ 14387b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller private RulesState getRulesStateInternal() { 14468f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller synchronized(this) { 14568f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller String systemRulesVersion; 14668f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller try { 14768f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller systemRulesVersion = mInstaller.getSystemRulesVersion(); 14868f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } catch (IOException e) { 14968f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller Slog.w(TAG, "Failed to read system rules", e); 15068f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller return null; 15168f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 15268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 153ad3e1331f3311b0351856e29001610d6ff39f082Neil Fuller // Determine the installed distro state. This should be possible regardless of whether 154ad3e1331f3311b0351856e29001610d6ff39f082Neil Fuller // there's an operation in progress. 155ad3e1331f3311b0351856e29001610d6ff39f082Neil Fuller DistroVersion installedDistroVersion; 156ad3e1331f3311b0351856e29001610d6ff39f082Neil Fuller int distroStatus = DISTRO_STATUS_UNKNOWN; 157ad3e1331f3311b0351856e29001610d6ff39f082Neil Fuller DistroRulesVersion installedDistroRulesVersion = null; 158ad3e1331f3311b0351856e29001610d6ff39f082Neil Fuller try { 159ad3e1331f3311b0351856e29001610d6ff39f082Neil Fuller installedDistroVersion = mInstaller.getInstalledDistroVersion(); 160ad3e1331f3311b0351856e29001610d6ff39f082Neil Fuller if (installedDistroVersion == null) { 161ad3e1331f3311b0351856e29001610d6ff39f082Neil Fuller distroStatus = DISTRO_STATUS_NONE; 162ad3e1331f3311b0351856e29001610d6ff39f082Neil Fuller installedDistroRulesVersion = null; 163ad3e1331f3311b0351856e29001610d6ff39f082Neil Fuller } else { 164ad3e1331f3311b0351856e29001610d6ff39f082Neil Fuller distroStatus = DISTRO_STATUS_INSTALLED; 165ad3e1331f3311b0351856e29001610d6ff39f082Neil Fuller installedDistroRulesVersion = new DistroRulesVersion( 166ad3e1331f3311b0351856e29001610d6ff39f082Neil Fuller installedDistroVersion.rulesVersion, 167ad3e1331f3311b0351856e29001610d6ff39f082Neil Fuller installedDistroVersion.revision); 168ad3e1331f3311b0351856e29001610d6ff39f082Neil Fuller } 169ad3e1331f3311b0351856e29001610d6ff39f082Neil Fuller } catch (DistroException | IOException e) { 170ad3e1331f3311b0351856e29001610d6ff39f082Neil Fuller Slog.w(TAG, "Failed to read installed distro.", e); 171ad3e1331f3311b0351856e29001610d6ff39f082Neil Fuller } 172ad3e1331f3311b0351856e29001610d6ff39f082Neil Fuller 17368f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller boolean operationInProgress = this.mOperationInProgress.get(); 17468f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 17568f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller // Determine the staged operation status, if possible. 17668f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller DistroRulesVersion stagedDistroRulesVersion = null; 17787b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller int stagedOperationStatus = STAGED_OPERATION_UNKNOWN; 17868f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller if (!operationInProgress) { 17968f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller StagedDistroOperation stagedDistroOperation; 18068f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller try { 18168f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller stagedDistroOperation = mInstaller.getStagedDistroOperation(); 18268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller if (stagedDistroOperation == null) { 18387b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller stagedOperationStatus = STAGED_OPERATION_NONE; 18468f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } else if (stagedDistroOperation.isUninstall) { 18587b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller stagedOperationStatus = STAGED_OPERATION_UNINSTALL; 18668f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } else { 18768f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller // Must be an install. 18887b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller stagedOperationStatus = STAGED_OPERATION_INSTALL; 18968f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller DistroVersion stagedDistroVersion = stagedDistroOperation.distroVersion; 19068f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller stagedDistroRulesVersion = new DistroRulesVersion( 19168f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller stagedDistroVersion.rulesVersion, 19268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller stagedDistroVersion.revision); 19368f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 19468f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } catch (DistroException | IOException e) { 19568f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller Slog.w(TAG, "Failed to read staged distro.", e); 19668f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 19768f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 19868f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller return new RulesState(systemRulesVersion, DISTRO_FORMAT_VERSION_SUPPORTED, 19968f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller operationInProgress, stagedOperationStatus, stagedDistroRulesVersion, 20068f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller distroStatus, installedDistroRulesVersion); 20168f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 20268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 20368f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 20468f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller @Override 20554525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller public int requestInstall(ParcelFileDescriptor distroParcelFileDescriptor, 20654525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller byte[] checkTokenBytes, ICallback callback) { 20768f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 20854525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller boolean closeParcelFileDescriptorOnExit = true; 20954525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller try { 21054525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller mPermissionHelper.enforceCallerHasPermission(REQUIRED_UPDATER_PERMISSION); 21154525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller 21254525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller CheckToken checkToken = null; 21354525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller if (checkTokenBytes != null) { 21454525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller checkToken = createCheckTokenOrThrow(checkTokenBytes); 21568f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 216d857f676744af55c79c4871c881bf9598f6b21e9Neil Fuller EventLogTags.writeTimezoneRequestInstall(toStringOrNull(checkToken)); 21768f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 21854525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller synchronized (this) { 21954525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller if (distroParcelFileDescriptor == null) { 22054525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller throw new NullPointerException("distroParcelFileDescriptor == null"); 22154525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller } 22254525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller if (callback == null) { 22354525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller throw new NullPointerException("observer == null"); 22454525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller } 22554525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller if (mOperationInProgress.get()) { 22654525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller return RulesManager.ERROR_OPERATION_IN_PROGRESS; 22754525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller } 22854525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller mOperationInProgress.set(true); 22954525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller 23054525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller // Execute the install asynchronously. 23154525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller mExecutor.execute( 23254525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller new InstallRunnable(distroParcelFileDescriptor, checkToken, callback)); 23354525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller 23454525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller // The InstallRunnable now owns the ParcelFileDescriptor, so it will close it after 23554525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller // it executes (and we do not have to). 23654525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller closeParcelFileDescriptorOnExit = false; 23768f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 23854525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller return RulesManager.SUCCESS; 23954525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller } 24054525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller } finally { 24154525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller // We should close() the local ParcelFileDescriptor we were passed if it hasn't been 24254525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller // passed to another thread to handle. 24354525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller if (distroParcelFileDescriptor != null && closeParcelFileDescriptorOnExit) { 24454525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller try { 24554525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller distroParcelFileDescriptor.close(); 24654525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller } catch (IOException e) { 24754525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller Slog.w(TAG, "Failed to close distroParcelFileDescriptor", e); 24854525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller } 24954525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller } 25068f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 25168f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 25268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 25368f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller private class InstallRunnable implements Runnable { 25468f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 25554525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller private final ParcelFileDescriptor mDistroParcelFileDescriptor; 25668f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller private final CheckToken mCheckToken; 25768f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller private final ICallback mCallback; 25868f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 25954525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller InstallRunnable(ParcelFileDescriptor distroParcelFileDescriptor, CheckToken checkToken, 26054525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller ICallback callback) { 26154525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller mDistroParcelFileDescriptor = distroParcelFileDescriptor; 26268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller mCheckToken = checkToken; 26368f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller mCallback = callback; 26468f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 26568f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 26668f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller @Override 26768f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller public void run() { 268d857f676744af55c79c4871c881bf9598f6b21e9Neil Fuller EventLogTags.writeTimezoneInstallStarted(toStringOrNull(mCheckToken)); 269d857f676744af55c79c4871c881bf9598f6b21e9Neil Fuller 27054525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller boolean success = false; 27168f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller // Adopt the ParcelFileDescriptor into this try-with-resources so it is closed 27268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller // when we are done. 27354525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller try (ParcelFileDescriptor pfd = mDistroParcelFileDescriptor) { 27454525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller // The ParcelFileDescriptor owns the underlying FileDescriptor and we'll close 27554525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller // it at the end of the try-with-resources. 27654525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller final boolean isFdOwner = false; 27754525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller InputStream is = new FileInputStream(pfd.getFileDescriptor(), isFdOwner); 27854525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller 27954525bf939ded4429aa3b7dd46954ed20bfa9320Neil Fuller TimeZoneDistro distro = new TimeZoneDistro(is); 280fe3b1182c5e98018dca6a1093bd5983b9620b5a1Neil Fuller int installerResult = mInstaller.stageInstallWithErrorCode(distro); 281b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller 282b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller // Notify interested parties that something is staged. 283b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller sendInstallNotificationIntentIfRequired(installerResult); 284b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller 28568f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller int resultCode = mapInstallerResultToApiCode(installerResult); 286d857f676744af55c79c4871c881bf9598f6b21e9Neil Fuller EventLogTags.writeTimezoneInstallComplete(toStringOrNull(mCheckToken), resultCode); 28768f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller sendFinishedStatus(mCallback, resultCode); 28868f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 28968f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller // All the installer failure modes are currently non-recoverable and won't be 29068f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller // improved by trying again. Therefore success = true. 29168f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller success = true; 29268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } catch (Exception e) { 29368f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller Slog.w(TAG, "Failed to install distro.", e); 294d857f676744af55c79c4871c881bf9598f6b21e9Neil Fuller EventLogTags.writeTimezoneInstallComplete( 295d857f676744af55c79c4871c881bf9598f6b21e9Neil Fuller toStringOrNull(mCheckToken), Callback.ERROR_UNKNOWN_FAILURE); 29668f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller sendFinishedStatus(mCallback, Callback.ERROR_UNKNOWN_FAILURE); 29768f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } finally { 29868f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller // Notify the package tracker that the operation is now complete. 29968f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller mPackageTracker.recordCheckResult(mCheckToken, success); 30068f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 30168f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller mOperationInProgress.set(false); 30268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 30368f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 30468f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 305b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller private void sendInstallNotificationIntentIfRequired(int installerResult) { 306b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller if (installerResult == TimeZoneDistroInstaller.INSTALL_SUCCESS) { 307b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller mIntentHelper.sendTimeZoneOperationStaged(); 308b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller } 309b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller } 310b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller 31168f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller private int mapInstallerResultToApiCode(int installerResult) { 31268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller switch (installerResult) { 31368f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller case TimeZoneDistroInstaller.INSTALL_SUCCESS: 31468f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller return Callback.SUCCESS; 31568f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller case TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE: 31668f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller return Callback.ERROR_INSTALL_BAD_DISTRO_STRUCTURE; 31768f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller case TimeZoneDistroInstaller.INSTALL_FAIL_RULES_TOO_OLD: 31868f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller return Callback.ERROR_INSTALL_RULES_TOO_OLD; 31968f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller case TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_FORMAT_VERSION: 32068f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller return Callback.ERROR_INSTALL_BAD_DISTRO_FORMAT_VERSION; 32168f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller case TimeZoneDistroInstaller.INSTALL_FAIL_VALIDATION_ERROR: 32268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller return Callback.ERROR_INSTALL_VALIDATION_ERROR; 32368f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller default: 32468f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller return Callback.ERROR_UNKNOWN_FAILURE; 32568f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 32668f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 32768f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 32868f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 32968f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller @Override 33068f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller public int requestUninstall(byte[] checkTokenBytes, ICallback callback) { 33168f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller mPermissionHelper.enforceCallerHasPermission(REQUIRED_UPDATER_PERMISSION); 33268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 33368f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller CheckToken checkToken = null; 33468f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller if (checkTokenBytes != null) { 33568f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller checkToken = createCheckTokenOrThrow(checkTokenBytes); 33668f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 337d857f676744af55c79c4871c881bf9598f6b21e9Neil Fuller EventLogTags.writeTimezoneRequestUninstall(toStringOrNull(checkToken)); 33868f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller synchronized(this) { 33968f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller if (callback == null) { 34068f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller throw new NullPointerException("callback == null"); 34168f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 34268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 34368f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller if (mOperationInProgress.get()) { 34468f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller return RulesManager.ERROR_OPERATION_IN_PROGRESS; 34568f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 34668f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller mOperationInProgress.set(true); 34768f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 34868f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller // Execute the uninstall asynchronously. 34968f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller mExecutor.execute(new UninstallRunnable(checkToken, callback)); 35068f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 35168f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller return RulesManager.SUCCESS; 35268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 35368f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 35468f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 35568f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller private class UninstallRunnable implements Runnable { 35668f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 35768f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller private final CheckToken mCheckToken; 35868f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller private final ICallback mCallback; 35968f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 360a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller UninstallRunnable(CheckToken checkToken, ICallback callback) { 36168f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller mCheckToken = checkToken; 36268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller mCallback = callback; 36368f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 36468f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 36568f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller @Override 36668f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller public void run() { 367d857f676744af55c79c4871c881bf9598f6b21e9Neil Fuller EventLogTags.writeTimezoneUninstallStarted(toStringOrNull(mCheckToken)); 3688e27c9226b82f41279ee6c108d2b06bb6f1cef5eNeil Fuller boolean packageTrackerStatus = false; 36968f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller try { 3708e27c9226b82f41279ee6c108d2b06bb6f1cef5eNeil Fuller int uninstallResult = mInstaller.stageUninstall(); 371b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller 372b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller // Notify interested parties that something is staged. 373b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller sendUninstallNotificationIntentIfRequired(uninstallResult); 374b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller 3758e27c9226b82f41279ee6c108d2b06bb6f1cef5eNeil Fuller packageTrackerStatus = (uninstallResult == TimeZoneDistroInstaller.UNINSTALL_SUCCESS 3768e27c9226b82f41279ee6c108d2b06bb6f1cef5eNeil Fuller || uninstallResult == TimeZoneDistroInstaller.UNINSTALL_NOTHING_INSTALLED); 3778e27c9226b82f41279ee6c108d2b06bb6f1cef5eNeil Fuller 3788e27c9226b82f41279ee6c108d2b06bb6f1cef5eNeil Fuller // Right now we just have Callback.SUCCESS / Callback.ERROR_UNKNOWN_FAILURE for 3798e27c9226b82f41279ee6c108d2b06bb6f1cef5eNeil Fuller // uninstall. All clients should be checking against SUCCESS. More granular failures 3808e27c9226b82f41279ee6c108d2b06bb6f1cef5eNeil Fuller // may be added in future. 3818e27c9226b82f41279ee6c108d2b06bb6f1cef5eNeil Fuller int callbackResultCode = 3828e27c9226b82f41279ee6c108d2b06bb6f1cef5eNeil Fuller packageTrackerStatus ? Callback.SUCCESS : Callback.ERROR_UNKNOWN_FAILURE; 383d857f676744af55c79c4871c881bf9598f6b21e9Neil Fuller EventLogTags.writeTimezoneUninstallComplete( 3848e27c9226b82f41279ee6c108d2b06bb6f1cef5eNeil Fuller toStringOrNull(mCheckToken), callbackResultCode); 3858e27c9226b82f41279ee6c108d2b06bb6f1cef5eNeil Fuller sendFinishedStatus(mCallback, callbackResultCode); 38668f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } catch (Exception e) { 387d857f676744af55c79c4871c881bf9598f6b21e9Neil Fuller EventLogTags.writeTimezoneUninstallComplete( 388d857f676744af55c79c4871c881bf9598f6b21e9Neil Fuller toStringOrNull(mCheckToken), Callback.ERROR_UNKNOWN_FAILURE); 38968f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller Slog.w(TAG, "Failed to uninstall distro.", e); 39068f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller sendFinishedStatus(mCallback, Callback.ERROR_UNKNOWN_FAILURE); 39168f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } finally { 39268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller // Notify the package tracker that the operation is now complete. 3938e27c9226b82f41279ee6c108d2b06bb6f1cef5eNeil Fuller mPackageTracker.recordCheckResult(mCheckToken, packageTrackerStatus); 39468f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 39568f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller mOperationInProgress.set(false); 39668f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 39768f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 398b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller 399b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller private void sendUninstallNotificationIntentIfRequired(int uninstallResult) { 400b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller switch (uninstallResult) { 401b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller case TimeZoneDistroInstaller.UNINSTALL_SUCCESS: 402b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller mIntentHelper.sendTimeZoneOperationStaged(); 403b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller break; 404b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller case TimeZoneDistroInstaller.UNINSTALL_NOTHING_INSTALLED: 405b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller mIntentHelper.sendTimeZoneOperationUnstaged(); 406b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller break; 407b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller case TimeZoneDistroInstaller.UNINSTALL_FAIL: 408b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller default: 409b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller // No-op - unknown or nothing to notify about. 410b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller } 411b144227742ada7fd693684a5bd2d53abd8e7c499Neil Fuller } 41268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 41368f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 41468f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller private void sendFinishedStatus(ICallback callback, int resultCode) { 41568f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller try { 41668f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller callback.onFinished(resultCode); 41768f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } catch (RemoteException e) { 41868f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller Slog.e(TAG, "Unable to notify observer of result", e); 41968f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 42068f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 42168f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 42268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller @Override 42368f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller public void requestNothing(byte[] checkTokenBytes, boolean success) { 42468f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller mPermissionHelper.enforceCallerHasPermission(REQUIRED_UPDATER_PERMISSION); 42568f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller CheckToken checkToken = null; 42668f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller if (checkTokenBytes != null) { 42768f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller checkToken = createCheckTokenOrThrow(checkTokenBytes); 42868f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 429d857f676744af55c79c4871c881bf9598f6b21e9Neil Fuller EventLogTags.writeTimezoneRequestNothing(toStringOrNull(checkToken)); 43068f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller mPackageTracker.recordCheckResult(checkToken, success); 431d857f676744af55c79c4871c881bf9598f6b21e9Neil Fuller EventLogTags.writeTimezoneNothingComplete(toStringOrNull(checkToken)); 43268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 43368f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller 43487b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller @Override 43587b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 43687b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller if (!mPermissionHelper.checkDumpPermission(TAG, pw)) { 43787b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller return; 43887b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller } 43987b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller 44087b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller RulesState rulesState = getRulesStateInternal(); 44187b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller if (args != null && args.length == 2) { 44287b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller // Formatting options used for automated tests. The format is less free-form than 44387b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller // the -format options, which are intended to be easier to parse. 44487b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller if ("-format_state".equals(args[0]) && args[1] != null) { 44587b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller for (char c : args[1].toCharArray()) { 44687b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller switch (c) { 447a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller case 'p': { 448a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller // Report operation in progress 449a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller String value = "Unknown"; 450a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller if (rulesState != null) { 451a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller value = Boolean.toString(rulesState.isOperationInProgress()); 452a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller } 453a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller pw.println("Operation in progress: " + value); 45487b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller break; 455a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller } 456a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller case 's': { 457a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller // Report system image rules version 458a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller String value = "Unknown"; 459a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller if (rulesState != null) { 460a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller value = rulesState.getSystemRulesVersion(); 461a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller } 462a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller pw.println("System rules version: " + value); 46387b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller break; 464a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller } 465a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller case 'c': { 466a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller // Report current installation state 467a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller String value = "Unknown"; 468a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller if (rulesState != null) { 469a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller value = distroStatusToString(rulesState.getDistroStatus()); 470a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller } 471a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller pw.println("Current install state: " + value); 47287b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller break; 473a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller } 474a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller case 'i': { 475a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller // Report currently installed version 476a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller String value = "Unknown"; 477a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller if (rulesState != null) { 478a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller DistroRulesVersion installedRulesVersion = 479a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller rulesState.getInstalledDistroRulesVersion(); 480a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller if (installedRulesVersion == null) { 481a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller value = "<None>"; 482a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller } else { 483a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller value = installedRulesVersion.toDumpString(); 484a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller } 48587b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller } 486a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller pw.println("Installed rules version: " + value); 48787b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller break; 488a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller } 489a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller case 'o': { 490a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller // Report staged operation type 491a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller String value = "Unknown"; 492a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller if (rulesState != null) { 493a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller int stagedOperationType = rulesState.getStagedOperationType(); 494a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller value = stagedOperationToString(stagedOperationType); 495a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller } 496a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller pw.println("Staged operation: " + value); 49787b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller break; 498a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller } 499a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller case 't': { 50087b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller // Report staged version (i.e. the one that will be installed next boot 50187b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller // if the staged operation is an install). 502a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller String value = "Unknown"; 503a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller if (rulesState != null) { 504a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller DistroRulesVersion stagedDistroRulesVersion = 505a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller rulesState.getStagedDistroRulesVersion(); 506a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller if (stagedDistroRulesVersion == null) { 507a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller value = "<None>"; 508a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller } else { 509a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller value = stagedDistroRulesVersion.toDumpString(); 510a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller } 51187b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller } 512a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller pw.println("Staged rules version: " + value); 51387b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller break; 514a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller } 515a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller case 'a': { 51687b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller // Report the active rules version (i.e. the rules in use by the current 51787b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller // process). 518c90361404a1560d60756e4199af04d25ef688e2cNeil Fuller pw.println("Active rules version (ICU, ZoneInfoDB, TimeZoneFinder): " 51987b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller + ICU.getTZDataVersion() + "," 520c90361404a1560d60756e4199af04d25ef688e2cNeil Fuller + ZoneInfoDB.getInstance().getVersion() + "," 521c90361404a1560d60756e4199af04d25ef688e2cNeil Fuller + TimeZoneFinder.getInstance().getIanaVersion()); 52287b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller break; 523a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller } 524a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller default: { 52587b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller pw.println("Unknown option: " + c); 526a47c3637f1af3481a094cdef3e20b6f2990589caNeil Fuller } 52787b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller } 52887b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller } 52987b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller return; 53087b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller } 53187b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller } 53287b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller 53387b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller pw.println("RulesManagerService state: " + toString()); 534c90361404a1560d60756e4199af04d25ef688e2cNeil Fuller pw.println("Active rules version (ICU, ZoneInfoDB, TimeZoneFinder): " 535c90361404a1560d60756e4199af04d25ef688e2cNeil Fuller + ICU.getTZDataVersion() + "," 536c90361404a1560d60756e4199af04d25ef688e2cNeil Fuller + ZoneInfoDB.getInstance().getVersion() + "," 537c90361404a1560d60756e4199af04d25ef688e2cNeil Fuller + TimeZoneFinder.getInstance().getIanaVersion()); 538d857f676744af55c79c4871c881bf9598f6b21e9Neil Fuller pw.println("Distro state: " + rulesState.toString()); 53987b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller mPackageTracker.dump(pw); 54087b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller } 54187b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller 542cd1a109b872f58f5baa0ce8438bf3ddd69eec9fcNeil Fuller /** 543cd1a109b872f58f5baa0ce8438bf3ddd69eec9fcNeil Fuller * Called when the device is considered idle. 544cd1a109b872f58f5baa0ce8438bf3ddd69eec9fcNeil Fuller */ 545cd1a109b872f58f5baa0ce8438bf3ddd69eec9fcNeil Fuller void notifyIdle() { 546cd1a109b872f58f5baa0ce8438bf3ddd69eec9fcNeil Fuller // No package has changed: we are just triggering because the device is idle and there 547cd1a109b872f58f5baa0ce8438bf3ddd69eec9fcNeil Fuller // *might* be work to do. 548cd1a109b872f58f5baa0ce8438bf3ddd69eec9fcNeil Fuller final boolean packageChanged = false; 549cd1a109b872f58f5baa0ce8438bf3ddd69eec9fcNeil Fuller mPackageTracker.triggerUpdateIfNeeded(packageChanged); 550cd1a109b872f58f5baa0ce8438bf3ddd69eec9fcNeil Fuller } 551cd1a109b872f58f5baa0ce8438bf3ddd69eec9fcNeil Fuller 55287b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller @Override 55387b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller public String toString() { 55487b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller return "RulesManagerService{" + 55587b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller "mOperationInProgress=" + mOperationInProgress + 55687b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller '}'; 55787b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller } 55887b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller 55968f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller private static CheckToken createCheckTokenOrThrow(byte[] checkTokenBytes) { 56068f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller CheckToken checkToken; 56168f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller try { 56268f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller checkToken = CheckToken.fromByteArray(checkTokenBytes); 56368f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } catch (IOException e) { 56468f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller throw new IllegalArgumentException("Unable to read token bytes " 56568f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller + Arrays.toString(checkTokenBytes), e); 56668f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 56768f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller return checkToken; 56868f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller } 56987b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller 57087b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller private static String distroStatusToString(int distroStatus) { 57187b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller switch(distroStatus) { 57287b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller case DISTRO_STATUS_NONE: 57387b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller return "None"; 57487b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller case DISTRO_STATUS_INSTALLED: 57587b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller return "Installed"; 57687b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller case DISTRO_STATUS_UNKNOWN: 57787b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller default: 57887b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller return "Unknown"; 57987b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller } 58087b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller } 58187b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller 58287b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller private static String stagedOperationToString(int stagedOperationType) { 58387b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller switch(stagedOperationType) { 58487b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller case STAGED_OPERATION_NONE: 58587b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller return "None"; 58687b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller case STAGED_OPERATION_UNINSTALL: 58787b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller return "Uninstall"; 58887b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller case STAGED_OPERATION_INSTALL: 58987b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller return "Install"; 59087b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller case STAGED_OPERATION_UNKNOWN: 59187b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller default: 59287b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller return "Unknown"; 59387b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller } 59487b1128ddc44afeafb946a32d63abef68d8b3dc1Neil Fuller } 595d857f676744af55c79c4871c881bf9598f6b21e9Neil Fuller 596d857f676744af55c79c4871c881bf9598f6b21e9Neil Fuller private static String toStringOrNull(Object obj) { 597d857f676744af55c79c4871c881bf9598f6b21e9Neil Fuller return obj == null ? null : obj.toString(); 598d857f676744af55c79c4871c881bf9598f6b21e9Neil Fuller } 59968f666693a465eb8a66d9252b7b7ac035b9f0b7bNeil Fuller} 600