blob: 0e8d8bc8e411e81c0d35e145289fe65614176feb [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;
20
21import android.app.timezone.RulesUpdaterContract;
22import android.content.Context;
23import android.content.pm.PackageManager;
Neil Fuller5f6750f2017-05-17 04:43:12 +010024import android.os.Environment;
Neil Fullera7d21f82017-12-05 15:09:35 +000025import android.os.FileUtils;
26import android.os.SystemClock;
Neil Fuller68f66662017-03-16 18:32:21 +000027import android.provider.TimeZoneRulesDataContract;
28import android.util.Slog;
29
Neil Fuller5f6750f2017-05-17 04:43:12 +010030import java.io.File;
Neil Fuller35822592017-12-11 14:39:03 +000031import java.io.IOException;
Neil Fuller87b11282017-06-23 16:43:45 +010032import java.io.PrintWriter;
Neil Fullera7d21f82017-12-05 15:09:35 +000033import java.time.Clock;
Neil Fuller5f6750f2017-05-17 04:43:12 +010034
Neil Fuller68f66662017-03-16 18:32:21 +000035/**
36 * Monitors the installed applications associated with time zone updates. If the app packages are
37 * updated it indicates there <em>might</em> be a time zone rules update to apply so a targeted
38 * broadcast intent is used to trigger the time zone updater app.
39 *
40 * <p>The "update triggering" behavior of this component can be disabled via device configuration.
41 *
42 * <p>The package tracker listens for package updates of the time zone "updater app" and "data app".
43 * It also listens for "reliability" triggers. Reliability triggers are there to ensure that the
44 * package tracker handles failures reliably and are "idle maintenance" events or something similar.
45 * Reliability triggers can cause a time zone update check to take place if the current state is
46 * unclear. For example, it can be unclear after boot or after a failure. If there are repeated
47 * failures reliability updates are halted until the next boot.
48 *
49 * <p>This component keeps persistent track of the most recent app packages checked to avoid
50 * unnecessary expense from broadcasting intents (which will cause other app processes to spawn).
51 * The current status is also stored to detect whether the most recently-generated check is
52 * complete successfully. For example, if the device was interrupted while doing a check and never
53 * acknowledged a check then a check will be retried the next time a "reliability trigger" event
54 * happens.
55 */
56// Also made non-final so it can be mocked.
57@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
Neil Fullercd1a1092017-09-13 21:59:59 +010058public class PackageTracker {
Neil Fuller68f66662017-03-16 18:32:21 +000059 private static final String TAG = "timezone.PackageTracker";
60
61 private final PackageManagerHelper mPackageManagerHelper;
62 private final IntentHelper mIntentHelper;
63 private final ConfigHelper mConfigHelper;
64 private final PackageStatusStorage mPackageStatusStorage;
Neil Fullera7d21f82017-12-05 15:09:35 +000065 private final Clock mElapsedRealtimeClock;
Neil Fuller68f66662017-03-16 18:32:21 +000066
67 // False if tracking is disabled.
68 private boolean mTrackingEnabled;
69
70 // These fields may be null if package tracking is disabled.
71 private String mUpdateAppPackageName;
72 private String mDataAppPackageName;
73
74 // The time a triggered check is allowed to take before it is considered overdue.
75 private int mCheckTimeAllowedMillis;
76 // The number of failed checks in a row before reliability checks should stop happening.
77 private long mFailedCheckRetryCount;
78
Neil Fullercd1a1092017-09-13 21:59:59 +010079 /*
80 * The minimum delay between a successive reliability triggers / other operations. Should to be
81 * larger than mCheckTimeAllowedMillis to avoid reliability triggers happening during package
82 * update checks.
83 */
84 private int mDelayBeforeReliabilityCheckMillis;
85
Neil Fuller68f66662017-03-16 18:32:21 +000086 // Reliability check state: If a check was triggered but not acknowledged within
87 // mCheckTimeAllowedMillis then another one can be triggered.
88 private Long mLastTriggerTimestamp = null;
89
90 // Reliability check state: Whether any checks have been triggered at all.
91 private boolean mCheckTriggered;
92
93 // Reliability check state: A count of how many failures have occurred consecutively.
94 private int mCheckFailureCount;
95
96 /** Creates the {@link PackageTracker} for normal use. */
97 static PackageTracker create(Context context) {
Neil Fullera7d21f82017-12-05 15:09:35 +000098 Clock elapsedRealtimeClock = SystemClock.elapsedRealtimeClock();
Neil Fuller68f66662017-03-16 18:32:21 +000099 PackageTrackerHelperImpl helperImpl = new PackageTrackerHelperImpl(context);
Neil Fullera7d21f82017-12-05 15:09:35 +0000100 File storageDir = FileUtils.createDir(Environment.getDataSystemDirectory(), "timezone");
Neil Fuller68f66662017-03-16 18:32:21 +0000101 return new PackageTracker(
Neil Fullera7d21f82017-12-05 15:09:35 +0000102 elapsedRealtimeClock /* elapsedRealtimeClock */,
Neil Fuller68f66662017-03-16 18:32:21 +0000103 helperImpl /* configHelper */,
104 helperImpl /* packageManagerHelper */,
Neil Fuller5f6750f2017-05-17 04:43:12 +0100105 new PackageStatusStorage(storageDir),
Neil Fuller68f66662017-03-16 18:32:21 +0000106 new IntentHelperImpl(context));
107 }
108
109 // A constructor that can be used by tests to supply mocked / faked dependencies.
Neil Fullera7d21f82017-12-05 15:09:35 +0000110 PackageTracker(Clock elapsedRealtimeClock, ConfigHelper configHelper,
Neil Fuller68f66662017-03-16 18:32:21 +0000111 PackageManagerHelper packageManagerHelper, PackageStatusStorage packageStatusStorage,
112 IntentHelper intentHelper) {
Neil Fullera7d21f82017-12-05 15:09:35 +0000113 mElapsedRealtimeClock = elapsedRealtimeClock;
Neil Fuller68f66662017-03-16 18:32:21 +0000114 mConfigHelper = configHelper;
115 mPackageManagerHelper = packageManagerHelper;
116 mPackageStatusStorage = packageStatusStorage;
117 mIntentHelper = intentHelper;
118 }
119
120 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
Neil Fuller35822592017-12-11 14:39:03 +0000121 protected synchronized boolean start() {
Neil Fuller68f66662017-03-16 18:32:21 +0000122 mTrackingEnabled = mConfigHelper.isTrackingEnabled();
123 if (!mTrackingEnabled) {
124 Slog.i(TAG, "Time zone updater / data package tracking explicitly disabled.");
Neil Fuller35822592017-12-11 14:39:03 +0000125 return false;
Neil Fuller68f66662017-03-16 18:32:21 +0000126 }
127
128 mUpdateAppPackageName = mConfigHelper.getUpdateAppPackageName();
129 mDataAppPackageName = mConfigHelper.getDataAppPackageName();
130 mCheckTimeAllowedMillis = mConfigHelper.getCheckTimeAllowedMillis();
131 mFailedCheckRetryCount = mConfigHelper.getFailedCheckRetryCount();
Neil Fullercd1a1092017-09-13 21:59:59 +0100132 mDelayBeforeReliabilityCheckMillis = mCheckTimeAllowedMillis + (60 * 1000);
Neil Fuller68f66662017-03-16 18:32:21 +0000133
134 // Validate the device configuration including the application packages.
135 // The manifest entries in the apps themselves are not validated until use as they can
136 // change and we don't want to prevent the system server starting due to a bad application.
137 throwIfDeviceSettingsOrAppsAreBad();
138
139 // Explicitly start in a reliability state where reliability triggering will do something.
140 mCheckTriggered = false;
141 mCheckFailureCount = 0;
142
Neil Fuller35822592017-12-11 14:39:03 +0000143 // Initialize the storage, as needed.
144 try {
145 mPackageStatusStorage.initialize();
146 } catch (IOException e) {
147 Slog.w(TAG, "PackageTracker storage could not be initialized.", e);
148 return false;
149 }
150
Neil Fuller68f66662017-03-16 18:32:21 +0000151 // Initialize the intent helper.
152 mIntentHelper.initialize(mUpdateAppPackageName, mDataAppPackageName, this);
153
Neil Fullercd1a1092017-09-13 21:59:59 +0100154 // Schedule a reliability trigger so we will have at least one after boot. This will allow
155 // us to catch if a package updated wasn't handled to completion. There's no hurry: it's ok
156 // to delay for a while before doing this even if idle.
157 mIntentHelper.scheduleReliabilityTrigger(mDelayBeforeReliabilityCheckMillis);
Neil Fuller68f66662017-03-16 18:32:21 +0000158
159 Slog.i(TAG, "Time zone updater / data package tracking enabled");
Neil Fuller35822592017-12-11 14:39:03 +0000160 return true;
Neil Fuller68f66662017-03-16 18:32:21 +0000161 }
162
163 /**
164 * Performs checks that confirm the system image has correctly configured package
165 * tracking configuration. Only called if package tracking is enabled. Throws an exception if
166 * the device is configured badly which will prevent the device booting.
167 */
168 private void throwIfDeviceSettingsOrAppsAreBad() {
169 // None of the checks below can be based on application manifest settings, otherwise a bad
170 // update could leave the device in an unbootable state. See validateDataAppManifest() and
171 // validateUpdaterAppManifest() for softer errors.
172
173 throwRuntimeExceptionIfNullOrEmpty(
174 mUpdateAppPackageName, "Update app package name missing.");
175 throwRuntimeExceptionIfNullOrEmpty(mDataAppPackageName, "Data app package name missing.");
176 if (mFailedCheckRetryCount < 1) {
177 throw logAndThrowRuntimeException("mFailedRetryCount=" + mFailedCheckRetryCount, null);
178 }
179 if (mCheckTimeAllowedMillis < 1000) {
180 throw logAndThrowRuntimeException(
181 "mCheckTimeAllowedMillis=" + mCheckTimeAllowedMillis, null);
182 }
183
184 // Validate the updater application package.
Neil Fuller3d7a4142017-07-12 17:18:19 +0100185 try {
186 if (!mPackageManagerHelper.isPrivilegedApp(mUpdateAppPackageName)) {
187 throw logAndThrowRuntimeException(
188 "Update app " + mUpdateAppPackageName + " must be a priv-app.", null);
189 }
190 } catch (PackageManager.NameNotFoundException e) {
191 throw logAndThrowRuntimeException("Could not determine update app package details for "
192 + mUpdateAppPackageName, e);
193 }
Neil Fuller68f66662017-03-16 18:32:21 +0000194 Slog.d(TAG, "Update app " + mUpdateAppPackageName + " is valid.");
195
196 // Validate the data application package.
Neil Fuller3d7a4142017-07-12 17:18:19 +0100197 try {
198 if (!mPackageManagerHelper.isPrivilegedApp(mDataAppPackageName)) {
199 throw logAndThrowRuntimeException(
200 "Data app " + mDataAppPackageName + " must be a priv-app.", null);
201 }
202 } catch (PackageManager.NameNotFoundException e) {
203 throw logAndThrowRuntimeException("Could not determine data app package details for "
204 + mDataAppPackageName, e);
205 }
Neil Fuller68f66662017-03-16 18:32:21 +0000206 Slog.d(TAG, "Data app " + mDataAppPackageName + " is valid.");
207 }
208
209 /**
210 * Inspects the current in-memory state, installed packages and storage state to determine if an
211 * update check is needed and then trigger if it is.
212 *
213 * @param packageChanged true if this method was called because a known packaged definitely
214 * changed, false if the cause is a reliability trigger
215 */
Neil Fuller68f66662017-03-16 18:32:21 +0000216 public synchronized void triggerUpdateIfNeeded(boolean packageChanged) {
217 if (!mTrackingEnabled) {
218 throw new IllegalStateException("Unexpected call. Tracking is disabled.");
219 }
220
221 // Validate the applications' current manifest entries: make sure they are configured as
222 // they should be. These are not fatal and just means that no update is triggered: we don't
223 // want to take down the system server if an OEM or Google have pushed a bad update to
224 // an application.
225 boolean updaterAppManifestValid = validateUpdaterAppManifest();
226 boolean dataAppManifestValid = validateDataAppManifest();
227 if (!updaterAppManifestValid || !dataAppManifestValid) {
228 Slog.e(TAG, "No update triggered due to invalid application manifest entries."
229 + " updaterApp=" + updaterAppManifestValid
230 + ", dataApp=" + dataAppManifestValid);
231
Neil Fullercd1a1092017-09-13 21:59:59 +0100232 // There's no point in doing any reliability triggers if the current packages are bad.
233 mIntentHelper.unscheduleReliabilityTrigger();
Neil Fuller68f66662017-03-16 18:32:21 +0000234 return;
235 }
236
237 if (!packageChanged) {
238 // This call was made because the device is doing a "reliability" check.
239 // 4 possible cases:
240 // 1) No check has previously triggered since restart. We want to trigger in this case.
241 // 2) A check has previously triggered and it is in progress. We want to trigger if
242 // the response is overdue.
243 // 3) A check has previously triggered and it failed. We want to trigger, but only if
244 // we're not in a persistent failure state.
245 // 4) A check has previously triggered and it succeeded.
246 // We don't want to trigger, and want to stop future triggers.
247
248 if (!mCheckTriggered) {
249 // Case 1.
250 Slog.d(TAG, "triggerUpdateIfNeeded: First reliability trigger.");
251 } else if (isCheckInProgress()) {
252 // Case 2.
253 if (!isCheckResponseOverdue()) {
254 // A check is in progress but hasn't been given time to succeed.
255 Slog.d(TAG,
256 "triggerUpdateIfNeeded: checkComplete call is not yet overdue."
257 + " Not triggering.");
Neil Fullercd1a1092017-09-13 21:59:59 +0100258 // Don't do any work now but we do schedule a future reliability trigger.
259 mIntentHelper.scheduleReliabilityTrigger(mDelayBeforeReliabilityCheckMillis);
Neil Fuller68f66662017-03-16 18:32:21 +0000260 return;
261 }
262 } else if (mCheckFailureCount > mFailedCheckRetryCount) {
263 // Case 3. If the system is in some kind of persistent failure state we don't want
264 // to keep checking, so just stop.
265 Slog.i(TAG, "triggerUpdateIfNeeded: number of allowed consecutive check failures"
266 + " exceeded. Stopping reliability triggers until next reboot or package"
267 + " update.");
Neil Fullercd1a1092017-09-13 21:59:59 +0100268 mIntentHelper.unscheduleReliabilityTrigger();
Neil Fuller68f66662017-03-16 18:32:21 +0000269 return;
270 } else if (mCheckFailureCount == 0) {
271 // Case 4.
272 Slog.i(TAG, "triggerUpdateIfNeeded: No reliability check required. Last check was"
273 + " successful.");
Neil Fullercd1a1092017-09-13 21:59:59 +0100274 mIntentHelper.unscheduleReliabilityTrigger();
Neil Fuller68f66662017-03-16 18:32:21 +0000275 return;
276 }
277 }
278
279 // Read the currently installed data / updater package versions.
280 PackageVersions currentInstalledVersions = lookupInstalledPackageVersions();
281 if (currentInstalledVersions == null) {
282 // This should not happen if the device is configured in a valid way.
283 Slog.e(TAG, "triggerUpdateIfNeeded: currentInstalledVersions was null");
Neil Fullercd1a1092017-09-13 21:59:59 +0100284 mIntentHelper.unscheduleReliabilityTrigger();
Neil Fuller68f66662017-03-16 18:32:21 +0000285 return;
286 }
287
288 // Establish the current state using package manager and stored state. Determine if we have
289 // already successfully checked the installed versions.
290 PackageStatus packageStatus = mPackageStatusStorage.getPackageStatus();
291 if (packageStatus == null) {
292 // This can imply corrupt, uninitialized storage state (e.g. first check ever on a
293 // device) or after some kind of reset.
294 Slog.i(TAG, "triggerUpdateIfNeeded: No package status data found. Data check needed.");
295 } else if (!packageStatus.mVersions.equals(currentInstalledVersions)) {
296 // The stored package version information differs from the installed version.
297 // Trigger the check in all cases.
298 Slog.i(TAG, "triggerUpdateIfNeeded: Stored package versions="
299 + packageStatus.mVersions + ", do not match current package versions="
300 + currentInstalledVersions + ". Triggering check.");
301 } else {
302 Slog.i(TAG, "triggerUpdateIfNeeded: Stored package versions match currently"
303 + " installed versions, currentInstalledVersions=" + currentInstalledVersions
304 + ", packageStatus.mCheckStatus=" + packageStatus.mCheckStatus);
305 if (packageStatus.mCheckStatus == PackageStatus.CHECK_COMPLETED_SUCCESS) {
306 // The last check succeeded and nothing has changed. Do nothing and disable
307 // reliability checks.
308 Slog.i(TAG, "triggerUpdateIfNeeded: Prior check succeeded. No need to trigger.");
Neil Fullercd1a1092017-09-13 21:59:59 +0100309 mIntentHelper.unscheduleReliabilityTrigger();
Neil Fuller68f66662017-03-16 18:32:21 +0000310 return;
311 }
312 }
313
314 // Generate a token to send to the updater app.
315 CheckToken checkToken =
316 mPackageStatusStorage.generateCheckToken(currentInstalledVersions);
317 if (checkToken == null) {
318 Slog.w(TAG, "triggerUpdateIfNeeded: Unable to generate check token."
319 + " Not sending check request.");
Neil Fullercd1a1092017-09-13 21:59:59 +0100320 // Trigger again later: perhaps we'll have better luck.
321 mIntentHelper.scheduleReliabilityTrigger(mDelayBeforeReliabilityCheckMillis);
Neil Fuller68f66662017-03-16 18:32:21 +0000322 return;
323 }
324
325 // Trigger the update check.
326 mIntentHelper.sendTriggerUpdateCheck(checkToken);
327 mCheckTriggered = true;
328
329 // Update the reliability check state in case the update fails.
330 setCheckInProgress();
331
Neil Fullercd1a1092017-09-13 21:59:59 +0100332 // Schedule a reliability trigger in case the update check doesn't succeed and there is no
333 // response at all. It will be cancelled if the check is successful in recordCheckResult.
334 mIntentHelper.scheduleReliabilityTrigger(mDelayBeforeReliabilityCheckMillis);
Neil Fuller68f66662017-03-16 18:32:21 +0000335 }
336
337 /**
338 * Used to record the result of a check. Can be called even if active package tracking is
339 * disabled.
340 */
341 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
342 protected synchronized void recordCheckResult(CheckToken checkToken, boolean success) {
343 Slog.i(TAG, "recordOperationResult: checkToken=" + checkToken + " success=" + success);
344
345 // If package tracking is disabled it means no record-keeping is required. However, we do
346 // want to clear out any stored state to make it clear that the current state is unknown and
347 // should tracking become enabled again (perhaps through an OTA) we'd need to perform an
348 // update check.
349 if (!mTrackingEnabled) {
350 // This means an updater has spontaneously modified time zone data without having been
351 // triggered. This can happen if the OEM is handling their own updates, but we don't
352 // need to do any tracking in this case.
353
354 if (checkToken == null) {
355 // This is the expected case if tracking is disabled but an OEM is handling time
356 // zone installs using their own mechanism.
357 Slog.d(TAG, "recordCheckResult: Tracking is disabled and no token has been"
358 + " provided. Resetting tracking state.");
359 } else {
360 // This is unexpected. If tracking is disabled then no check token should have been
361 // generated by the package tracker. An updater should never create its own token.
362 // This could be a bug in the updater.
363 Slog.w(TAG, "recordCheckResult: Tracking is disabled and a token " + checkToken
364 + " has been unexpectedly provided. Resetting tracking state.");
365 }
366 mPackageStatusStorage.resetCheckState();
367 return;
368 }
369
370 if (checkToken == null) {
371 /*
372 * If the checkToken is null it suggests an install / uninstall / acknowledgement has
373 * occurred without a prior trigger (or the client didn't return the token it was given
374 * for some reason, perhaps a bug).
375 *
376 * This shouldn't happen under normal circumstances:
377 *
378 * If package tracking is enabled, we assume it is the package tracker responsible for
379 * triggering updates and a token should have been produced and returned.
380 *
381 * If the OEM is handling time zone updates case package tracking should be disabled.
382 *
383 * This could happen in tests. The device should recover back to a known state by
384 * itself rather than be left in an invalid state.
385 *
386 * We treat this as putting the device into an unknown state and make sure that
387 * reliability triggering is enabled so we should recover.
388 */
389 Slog.i(TAG, "recordCheckResult: Unexpectedly missing checkToken, resetting"
390 + " storage state.");
391 mPackageStatusStorage.resetCheckState();
392
Neil Fullercd1a1092017-09-13 21:59:59 +0100393 // Schedule a reliability trigger and reset the failure count so we know that the
Neil Fuller68f66662017-03-16 18:32:21 +0000394 // next reliability trigger will do something.
Neil Fullercd1a1092017-09-13 21:59:59 +0100395 mIntentHelper.scheduleReliabilityTrigger(mDelayBeforeReliabilityCheckMillis);
Neil Fuller68f66662017-03-16 18:32:21 +0000396 mCheckFailureCount = 0;
397 } else {
398 // This is the expected case when tracking is enabled: a check was triggered and it has
399 // completed.
400 boolean recordedCheckCompleteSuccessfully =
401 mPackageStatusStorage.markChecked(checkToken, success);
402 if (recordedCheckCompleteSuccessfully) {
403 // If we have recorded the result (whatever it was) we know there is no check in
404 // progress.
405 setCheckComplete();
406
407 if (success) {
Neil Fullercd1a1092017-09-13 21:59:59 +0100408 // Since the check was successful, no reliability trigger is required until
Neil Fuller68f66662017-03-16 18:32:21 +0000409 // there is a package change.
Neil Fullercd1a1092017-09-13 21:59:59 +0100410 mIntentHelper.unscheduleReliabilityTrigger();
Neil Fuller68f66662017-03-16 18:32:21 +0000411 mCheckFailureCount = 0;
412 } else {
Neil Fullercd1a1092017-09-13 21:59:59 +0100413 // Enable schedule a reliability trigger to check again in future.
414 mIntentHelper.scheduleReliabilityTrigger(mDelayBeforeReliabilityCheckMillis);
Neil Fuller68f66662017-03-16 18:32:21 +0000415 mCheckFailureCount++;
416 }
417 } else {
418 // The failure to record the check means an optimistic lock failure and suggests
419 // that another check was triggered after the token was generated.
420 Slog.i(TAG, "recordCheckResult: could not update token=" + checkToken
421 + " with success=" + success + ". Optimistic lock failure");
422
Neil Fullercd1a1092017-09-13 21:59:59 +0100423 // Schedule a reliability trigger to potentially try again in future.
424 mIntentHelper.scheduleReliabilityTrigger(mDelayBeforeReliabilityCheckMillis);
Neil Fuller68f66662017-03-16 18:32:21 +0000425 mCheckFailureCount++;
426 }
427 }
428 }
429
430 /** Access to consecutive failure counts for use in tests. */
431 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
432 protected int getCheckFailureCountForTests() {
433 return mCheckFailureCount;
434 }
435
436 private void setCheckInProgress() {
Neil Fullera7d21f82017-12-05 15:09:35 +0000437 mLastTriggerTimestamp = mElapsedRealtimeClock.millis();
Neil Fuller68f66662017-03-16 18:32:21 +0000438 }
439
440 private void setCheckComplete() {
441 mLastTriggerTimestamp = null;
442 }
443
444 private boolean isCheckInProgress() {
445 return mLastTriggerTimestamp != null;
446 }
447
448 private boolean isCheckResponseOverdue() {
449 if (mLastTriggerTimestamp == null) {
450 return false;
451 }
452 // Risk of overflow, but highly unlikely given the implementation and not problematic.
Neil Fullera7d21f82017-12-05 15:09:35 +0000453 return mElapsedRealtimeClock.millis() > mLastTriggerTimestamp + mCheckTimeAllowedMillis;
Neil Fuller68f66662017-03-16 18:32:21 +0000454 }
455
456 private PackageVersions lookupInstalledPackageVersions() {
Dianne Hackborn3accca02013-09-20 09:32:11 -0700457 long updatePackageVersion;
458 long dataPackageVersion;
Neil Fuller68f66662017-03-16 18:32:21 +0000459 try {
460 updatePackageVersion =
461 mPackageManagerHelper.getInstalledPackageVersion(mUpdateAppPackageName);
462 dataPackageVersion =
463 mPackageManagerHelper.getInstalledPackageVersion(mDataAppPackageName);
464 } catch (PackageManager.NameNotFoundException e) {
465 Slog.w(TAG, "lookupInstalledPackageVersions: Unable to resolve installed package"
466 + " versions", e);
467 return null;
468 }
469 return new PackageVersions(updatePackageVersion, dataPackageVersion);
470 }
471
472 private boolean validateDataAppManifest() {
473 // We only want to talk to a provider that exposed by the known data app package
474 // so we look up the providers exposed by that app and check the well-known authority is
475 // there. This prevents the case where *even if* the data app doesn't expose the provider
476 // required, another app cannot expose one to replace it.
477 if (!mPackageManagerHelper.contentProviderRegistered(
478 TimeZoneRulesDataContract.AUTHORITY, mDataAppPackageName)) {
479 // Error! Found the package but it didn't expose the correct provider.
480 Slog.w(TAG, "validateDataAppManifest: Data app " + mDataAppPackageName
481 + " does not expose the required provider with authority="
482 + TimeZoneRulesDataContract.AUTHORITY);
483 return false;
484 }
Neil Fuller68f66662017-03-16 18:32:21 +0000485 return true;
486 }
487
488 private boolean validateUpdaterAppManifest() {
489 try {
490 // The updater app is expected to have the UPDATE_TIME_ZONE_RULES permission.
491 // The updater app is expected to have a receiver for the intent we are going to trigger
492 // and require the TRIGGER_TIME_ZONE_RULES_CHECK.
493 if (!mPackageManagerHelper.usesPermission(
494 mUpdateAppPackageName,
495 RulesUpdaterContract.UPDATE_TIME_ZONE_RULES_PERMISSION)) {
496 Slog.w(TAG, "validateUpdaterAppManifest: Updater app " + mDataAppPackageName
497 + " does not use permission="
498 + RulesUpdaterContract.UPDATE_TIME_ZONE_RULES_PERMISSION);
499 return false;
500 }
501 if (!mPackageManagerHelper.receiverRegistered(
502 RulesUpdaterContract.createUpdaterIntent(mUpdateAppPackageName),
503 RulesUpdaterContract.TRIGGER_TIME_ZONE_RULES_CHECK_PERMISSION)) {
504 return false;
505 }
506
507 return true;
508 } catch (PackageManager.NameNotFoundException e) {
509 Slog.w(TAG, "validateUpdaterAppManifest: Updater app " + mDataAppPackageName
510 + " does not expose the required broadcast receiver.", e);
511 return false;
512 }
513 }
514
515 private static void throwRuntimeExceptionIfNullOrEmpty(String value, String message) {
516 if (value == null || value.trim().isEmpty()) {
517 throw logAndThrowRuntimeException(message, null);
518 }
519 }
520
521 private static RuntimeException logAndThrowRuntimeException(String message, Throwable cause) {
522 Slog.wtf(TAG, message, cause);
523 throw new RuntimeException(message, cause);
524 }
Neil Fuller87b11282017-06-23 16:43:45 +0100525
526 public void dump(PrintWriter fout) {
527 fout.println("PackageTrackerState: " + toString());
528 mPackageStatusStorage.dump(fout);
529 }
530
531 @Override
532 public String toString() {
533 return "PackageTracker{" +
534 "mTrackingEnabled=" + mTrackingEnabled +
535 ", mUpdateAppPackageName='" + mUpdateAppPackageName + '\'' +
536 ", mDataAppPackageName='" + mDataAppPackageName + '\'' +
537 ", mCheckTimeAllowedMillis=" + mCheckTimeAllowedMillis +
Neil Fullercd1a1092017-09-13 21:59:59 +0100538 ", mDelayBeforeReliabilityCheckMillis=" + mDelayBeforeReliabilityCheckMillis +
Neil Fuller87b11282017-06-23 16:43:45 +0100539 ", mFailedCheckRetryCount=" + mFailedCheckRetryCount +
540 ", mLastTriggerTimestamp=" + mLastTriggerTimestamp +
541 ", mCheckTriggered=" + mCheckTriggered +
542 ", mCheckFailureCount=" + mCheckFailureCount +
543 '}';
544 }
Neil Fuller68f66662017-03-16 18:32:21 +0000545}