summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreeHugger Robot <treehugger-gerrit@google.com>2017-08-12 05:30:30 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2017-08-12 05:30:30 +0000
commit8193291ca36146af752dbd87e6fcab5274fd9b3d (patch)
treee2cc4afa98e15839777f095d09d07efdc12a77f6
parenta031b0d6a127a4db89e60397737b6f53dcb13a8b (diff)
parent3f0122b50feb749cabc7c54f0e3653df7b4a4223 (diff)
downloadbase-8193291ca36146af752dbd87e6fcab5274fd9b3d.tar.gz
Merge changes from topic 'b/64606807' into oc-dr1-dev
* changes: Revert "Add (disabled) time zone update system server impl" Revert "Time zone update API classes"
-rw-r--r--Android.mk2
-rw-r--r--core/java/android/app/SystemServiceRegistry.java8
-rw-r--r--core/java/android/app/timezone/Callback.java76
-rw-r--r--core/java/android/app/timezone/DistroFormatVersion.java120
-rw-r--r--core/java/android/app/timezone/DistroRulesVersion.java128
-rw-r--r--core/java/android/app/timezone/ICallback.aidl27
-rw-r--r--core/java/android/app/timezone/IRulesManager.aidl84
-rw-r--r--core/java/android/app/timezone/RulesManager.java212
-rw-r--r--core/java/android/app/timezone/RulesState.aidl17
-rw-r--r--core/java/android/app/timezone/RulesState.java319
-rw-r--r--core/java/android/app/timezone/RulesUpdaterContract.java87
-rw-r--r--core/java/android/app/timezone/Utils.java67
-rw-r--r--core/java/android/content/Context.java17
-rw-r--r--core/res/AndroidManifest.xml16
-rw-r--r--core/res/res/values/config.xml43
-rw-r--r--core/res/res/values/symbols.xml6
-rw-r--r--core/tests/coretests/src/android/app/timezone/DistroFormatVersionTest.java83
-rw-r--r--core/tests/coretests/src/android/app/timezone/DistroRulesVersionTest.java83
-rw-r--r--core/tests/coretests/src/android/app/timezone/RulesStateTest.java187
-rw-r--r--core/tests/coretests/src/android/app/timezone/RulesUpdaterContractTest.java83
-rw-r--r--services/core/java/com/android/server/timezone/CheckToken.java98
-rw-r--r--services/core/java/com/android/server/timezone/ClockHelper.java25
-rw-r--r--services/core/java/com/android/server/timezone/ConfigHelper.java34
-rw-r--r--services/core/java/com/android/server/timezone/FileDescriptorHelper.java30
-rw-r--r--services/core/java/com/android/server/timezone/IntentHelper.java37
-rw-r--r--services/core/java/com/android/server/timezone/IntentHelperImpl.java116
-rw-r--r--services/core/java/com/android/server/timezone/PackageManagerHelper.java41
-rw-r--r--services/core/java/com/android/server/timezone/PackageStatus.java89
-rw-r--r--services/core/java/com/android/server/timezone/PackageStatusStorage.java336
-rw-r--r--services/core/java/com/android/server/timezone/PackageTracker.java504
-rw-r--r--services/core/java/com/android/server/timezone/PackageTrackerHelperImpl.java154
-rw-r--r--services/core/java/com/android/server/timezone/PackageVersions.java63
-rw-r--r--services/core/java/com/android/server/timezone/PermissionHelper.java25
-rw-r--r--services/core/java/com/android/server/timezone/RulesManagerService.java348
-rw-r--r--services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java59
-rw-r--r--services/java/com/android/server/SystemServer.java9
-rw-r--r--services/tests/servicestests/src/com/android/server/timezone/CheckTokenTest.java75
-rw-r--r--services/tests/servicestests/src/com/android/server/timezone/PackageStatusStorageTest.java229
-rw-r--r--services/tests/servicestests/src/com/android/server/timezone/PackageStatusTest.java53
-rw-r--r--services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java1471
-rw-r--r--services/tests/servicestests/src/com/android/server/timezone/PackageVersionsTest.java47
-rw-r--r--services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java924
42 files changed, 4 insertions, 6428 deletions
diff --git a/Android.mk b/Android.mk
index 59aa699a9914..3fcfea94d666 100644
--- a/Android.mk
+++ b/Android.mk
@@ -114,8 +114,6 @@ LOCAL_SRC_FILES += \
core/java/android/app/backup/IRestoreObserver.aidl \
core/java/android/app/backup/IRestoreSession.aidl \
core/java/android/app/backup/ISelectBackupTransportCallback.aidl \
- core/java/android/app/timezone/ICallback.aidl \
- core/java/android/app/timezone/IRulesManager.aidl \
core/java/android/app/usage/ICacheQuotaService.aidl \
core/java/android/app/usage/IStorageStatsManager.aidl \
core/java/android/app/usage/IUsageStatsManager.aidl \
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 9a019b8e72fe..25e9224e266d 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -22,7 +22,6 @@ import android.app.admin.DevicePolicyManager;
import android.app.admin.IDevicePolicyManager;
import android.app.job.IJobScheduler;
import android.app.job.JobScheduler;
-import android.app.timezone.RulesManager;
import android.app.trust.TrustManager;
import android.app.usage.IStorageStatsManager;
import android.app.usage.IUsageStatsManager;
@@ -872,13 +871,6 @@ final class SystemServiceRegistry {
return new VrManager(IVrManager.Stub.asInterface(b));
}
});
-
- registerService(Context.TIME_ZONE_RULES_MANAGER_SERVICE, RulesManager.class,
- new CachedServiceFetcher<RulesManager>() {
- @Override
- public RulesManager createService(ContextImpl ctx) {
- return new RulesManager(ctx.getOuterContext());
- }});
}
/**
diff --git a/core/java/android/app/timezone/Callback.java b/core/java/android/app/timezone/Callback.java
deleted file mode 100644
index b51e5bad0f69..000000000000
--- a/core/java/android/app/timezone/Callback.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.timezone;
-
-import android.annotation.IntDef;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Callback interface for receiving information about an async time zone operation.
- * The methods will be called on your application's main thread.
- *
- * @hide
- */
-// TODO(nfuller): Expose necessary APIs for OEMs with @SystemApi. http://b/31008728
-public abstract class Callback {
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({SUCCESS, ERROR_UNKNOWN_FAILURE, ERROR_INSTALL_BAD_DISTRO_STRUCTURE,
- ERROR_INSTALL_BAD_DISTRO_FORMAT_VERSION, ERROR_INSTALL_RULES_TOO_OLD,
- ERROR_INSTALL_VALIDATION_ERROR})
- public @interface AsyncResultCode {}
-
- /**
- * Indicates that an operation succeeded.
- */
- public static final int SUCCESS = 0;
-
- /**
- * Indicates an install / uninstall did not fully succeed for an unknown reason.
- */
- public static final int ERROR_UNKNOWN_FAILURE = 1;
-
- /**
- * Indicates an install failed because of a structural issue with the provided distro,
- * e.g. it wasn't in the right format or the contents were structured incorrectly.
- */
- public static final int ERROR_INSTALL_BAD_DISTRO_STRUCTURE = 2;
-
- /**
- * Indicates an install failed because of a versioning issue with the provided distro,
- * e.g. it was created for a different version of Android.
- */
- public static final int ERROR_INSTALL_BAD_DISTRO_FORMAT_VERSION = 3;
-
- /**
- * Indicates an install failed because the rules provided are too old for the device,
- * e.g. the Android device shipped with a newer rules version.
- */
- public static final int ERROR_INSTALL_RULES_TOO_OLD = 4;
-
- /**
- * Indicates an install failed because the distro contents failed validation.
- */
- public static final int ERROR_INSTALL_VALIDATION_ERROR = 5;
-
- /**
- * Reports the result of an async time zone operation.
- */
- public abstract void onFinished(@AsyncResultCode int status);
-}
diff --git a/core/java/android/app/timezone/DistroFormatVersion.java b/core/java/android/app/timezone/DistroFormatVersion.java
deleted file mode 100644
index e879e8f8adbc..000000000000
--- a/core/java/android/app/timezone/DistroFormatVersion.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.timezone;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Versioning information about a distro's format or a device's supported format.
- *
- * <p>The following properties are included:
- * <dl>
- * <dt>majorVersion</dt>
- * <dd>the major distro format version. Major versions differences are not compatible - e.g.
- * 2 is not compatible with 1 or 3.</dd>
- * <dt>minorVersion</dt>
- * <dd>the minor distro format version. Minor versions should be backwards compatible iff the
- * major versions match exactly, i.e. version 2.2 will be compatible with 2.1 devices but not
- * 2.3 devices.</dd>
- * </dl>
- *
- * @hide
- */
-// TODO(nfuller): Expose necessary APIs for OEMs with @SystemApi. http://b/31008728
-public final class DistroFormatVersion implements Parcelable {
-
- private final int mMajorVersion;
- private final int mMinorVersion;
-
- public DistroFormatVersion(int majorVersion, int minorVersion) {
- mMajorVersion = Utils.validateVersion("major", majorVersion);
- mMinorVersion = Utils.validateVersion("minor", minorVersion);
- }
-
- public static final Creator<DistroFormatVersion> CREATOR = new Creator<DistroFormatVersion>() {
- public DistroFormatVersion createFromParcel(Parcel in) {
- int majorVersion = in.readInt();
- int minorVersion = in.readInt();
- return new DistroFormatVersion(majorVersion, minorVersion);
- }
-
- public DistroFormatVersion[] newArray(int size) {
- return new DistroFormatVersion[size];
- }
- };
-
- public int getMajorVersion() {
- return mMajorVersion;
- }
-
- public int getMinorVersion() {
- return mMinorVersion;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(mMajorVersion);
- out.writeInt(mMinorVersion);
- }
-
- /**
- * If this object describes a device's supported version and the parameter describes a distro's
- * version, this method returns whether the device would accept the distro.
- */
- public boolean supports(DistroFormatVersion distroFormatVersion) {
- return mMajorVersion == distroFormatVersion.mMajorVersion
- && mMinorVersion <= distroFormatVersion.mMinorVersion;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- DistroFormatVersion that = (DistroFormatVersion) o;
-
- if (mMajorVersion != that.mMajorVersion) {
- return false;
- }
- return mMinorVersion == that.mMinorVersion;
- }
-
- @Override
- public int hashCode() {
- int result = mMajorVersion;
- result = 31 * result + mMinorVersion;
- return result;
- }
-
- @Override
- public String toString() {
- return "DistroFormatVersion{"
- + "mMajorVersion=" + mMajorVersion
- + ", mMinorVersion=" + mMinorVersion
- + '}';
- }
-}
diff --git a/core/java/android/app/timezone/DistroRulesVersion.java b/core/java/android/app/timezone/DistroRulesVersion.java
deleted file mode 100644
index 5503ce1cf973..000000000000
--- a/core/java/android/app/timezone/DistroRulesVersion.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.timezone;
-
-import static android.app.timezone.Utils.validateRulesVersion;
-import static android.app.timezone.Utils.validateVersion;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Versioning information about a set of time zone rules.
- *
- * <p>The following properties are included:
- * <dl>
- * <dt>rulesVersion</dt>
- * <dd>the IANA rules version. e.g. "2017a"</dd>
- * <dt>revision</dt>
- * <dd>the revision for the rules. Allows there to be several revisions for a given IANA rules
- * release. Numerically higher is newer.</dd>
- * </dl>
- *
- * @hide
- */
-// TODO(nfuller): Expose necessary APIs for OEMs with @SystemApi. http://b/31008728
-public final class DistroRulesVersion implements Parcelable {
-
- private final String mRulesVersion;
- private final int mRevision;
-
- public DistroRulesVersion(String rulesVersion, int revision) {
- mRulesVersion = validateRulesVersion("rulesVersion", rulesVersion);
- mRevision = validateVersion("revision", revision);
- }
-
- public static final Creator<DistroRulesVersion> CREATOR = new Creator<DistroRulesVersion>() {
- public DistroRulesVersion createFromParcel(Parcel in) {
- String rulesVersion = in.readString();
- int revision = in.readInt();
- return new DistroRulesVersion(rulesVersion, revision);
- }
-
- public DistroRulesVersion[] newArray(int size) {
- return new DistroRulesVersion[size];
- }
- };
-
- public String getRulesVersion() {
- return mRulesVersion;
- }
-
- public int getRevision() {
- return mRevision;
- }
-
- /**
- * Returns true if this DistroRulesVersion is older than the one supplied. It returns false if
- * it is the same or newer. This method compares the {@code rulesVersion} and the
- * {@code revision}.
- */
- public boolean isOlderThan(DistroRulesVersion distroRulesVersion) {
- int rulesComparison = mRulesVersion.compareTo(distroRulesVersion.mRulesVersion);
- if (rulesComparison < 0) {
- return true;
- }
- if (rulesComparison > 0) {
- return false;
- }
- return mRevision < distroRulesVersion.mRevision;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(mRulesVersion);
- out.writeInt(mRevision);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- DistroRulesVersion that = (DistroRulesVersion) o;
-
- if (mRevision != that.mRevision) {
- return false;
- }
- return mRulesVersion.equals(that.mRulesVersion);
- }
-
- @Override
- public int hashCode() {
- int result = mRulesVersion.hashCode();
- result = 31 * result + mRevision;
- return result;
- }
-
- @Override
- public String toString() {
- return "DistroRulesVersion{"
- + "mRulesVersion='" + mRulesVersion + '\''
- + ", mRevision='" + mRevision + '\''
- + '}';
- }
-}
diff --git a/core/java/android/app/timezone/ICallback.aidl b/core/java/android/app/timezone/ICallback.aidl
deleted file mode 100644
index 519ef1a86350..000000000000
--- a/core/java/android/app/timezone/ICallback.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.timezone;
-
-/**
- * Callback interface for a timezone updater to receive information about the success or failure of
- * an installation/uninstallation attempt.
- *
- * {@hide}
- */
-oneway interface ICallback {
- void onFinished(int error);
-} \ No newline at end of file
diff --git a/core/java/android/app/timezone/IRulesManager.aidl b/core/java/android/app/timezone/IRulesManager.aidl
deleted file mode 100644
index 40f3fd22ac6b..000000000000
--- a/core/java/android/app/timezone/IRulesManager.aidl
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.timezone;
-
-import android.app.timezone.ICallback;
-import android.app.timezone.RulesState;
-import android.os.ParcelFileDescriptor;
-
- /**
- * Interface to the TimeZone Rules Manager Service.
- *
- * <p>This interface is only intended for system apps to call. They should use the
- * {@link android.app.timezone.RulesManager} class rather than going through this
- * Binder interface directly. See {@link android.app.timezone.RulesManager} for more complete
- * documentation.
- *
- * {@hide}
- */
-interface IRulesManager {
-
- /**
- * Returns information about the current time zone rules state such as the IANA version of
- * the system and any currently installed distro. This method is intended to allow clients to
- * determine if the current state can be improved; for example by passing the information to a
- * server that may provide a new distro for download.
- */
- RulesState getRulesState();
-
- /**
- * Requests installation of the supplied distro. The distro must have been checked for integrity
- * by the caller or have been received via a trusted mechanism.
- *
- * @param distroFileDescriptor the file descriptor for the distro
- * @param checkToken an optional token provided if the install was triggered in response to a
- * {@link RulesUpdaterContract#ACTION_TRIGGER_RULES_UPDATE_CHECK} intent
- * @param callback the {@link ICallback} to receive callbacks related to the
- * installation
- * @return zero if the installation will be attempted; nonzero on error
- */
- int requestInstall(in ParcelFileDescriptor distroFileDescriptor, in byte[] checkToken,
- ICallback callback);
-
- /**
- * Requests uninstallation of the currently installed distro (leaving the device with no
- * distro installed).
- *
- * @param checkToken an optional token provided if the uninstall was triggered in response to a
- * {@link RulesUpdaterContract#ACTION_TRIGGER_RULES_UPDATE_CHECK} intent
- * @param callback the {@link ICallback} to receive callbacks related to the
- * uninstall
- * @return zero if the uninstallation will be attempted; nonzero on error
- */
- int requestUninstall(in byte[] checkToken, ICallback callback);
-
- /**
- * Requests the system does not modify the currently installed time zone distro, if any. This
- * method records the fact that a time zone check operation triggered by the system is now
- * complete and there was nothing to do. The token passed should be the one presented when the
- * check was triggered.
- *
- * <p>Note: Passing {@code success == false} may result in more checks being triggered. Clients
- * should be careful not to pass false if the failure is unlikely to resolve by itself.
- *
- * @param checkToken an optional token provided if the install was triggered in response to a
- * {@link RulesUpdaterContract#ACTION_TRIGGER_RULES_UPDATE_CHECK} intent
- * @param success true if the check was successful, false if it was not successful but may
- * succeed if it is retried
- */
- void requestNothing(in byte[] token, boolean success);
-}
diff --git a/core/java/android/app/timezone/RulesManager.java b/core/java/android/app/timezone/RulesManager.java
deleted file mode 100644
index 649d894ca685..000000000000
--- a/core/java/android/app/timezone/RulesManager.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.timezone;
-
-import android.annotation.IntDef;
-import android.content.Context;
-import android.os.Handler;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.util.Log;
-
-import java.io.IOException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Arrays;
-
-/**
- * The interface through which a time zone update application interacts with the Android system
- * to handle time zone rule updates.
- *
- * <p>This interface is intended for use with the default APK-based time zone rules update
- * application but it can also be used by OEMs if that mechanism is turned off using configuration.
- * All callers must possess the {@link android.Manifest.permission#UPDATE_TIME_ZONE_RULES} system
- * permission.
- *
- * <p>When using the default mechanism, when properly configured the Android system will send a
- * {@link RulesUpdaterContract#ACTION_TRIGGER_RULES_UPDATE_CHECK} intent with a
- * {@link RulesUpdaterContract#EXTRA_CHECK_TOKEN} extra to the time zone rules updater application
- * when it detects that it or the OEM's APK containing time zone rules data has been modified. The
- * updater application is then responsible for calling one of
- * {@link #requestInstall(ParcelFileDescriptor, byte[], Callback)},
- * {@link #requestUninstall(byte[], Callback)} or
- * {@link #requestNothing(byte[], boolean)}, indicating, respectively, whether a new time zone rules
- * distro should be installed, the current distro should be uninstalled, or there is nothing to do
- * (or that the correct operation could not be determined due to an error). In each case the updater
- * must pass the {@link RulesUpdaterContract#EXTRA_CHECK_TOKEN} value it received from the intent
- * back so the system in the {@code checkToken} parameter.
- *
- * <p>If OEMs want to handle their own time zone rules updates, perhaps via a server-side component
- * rather than an APK, then they should disable the default triggering mechanism in config and are
- * responsible for triggering their own update checks / installs / uninstalls. In this case the
- * "check token" parameter can be left null and there is never any need to call
- * {@link #requestNothing(byte[], boolean)}.
- *
- * <p>OEMs should not mix the default mechanism and their own as this could lead to conflicts and
- * unnecessary checks being triggered.
- *
- * <p>Applications obtain this using {@link android.app.Activity#getSystemService(String)} with
- * {@link Context#TIME_ZONE_RULES_MANAGER_SERVICE}.
- * @hide
- */
-// TODO(nfuller): Expose necessary APIs for OEMs with @SystemApi. http://b/31008728
-public final class RulesManager {
- private static final String TAG = "timezone.RulesManager";
- private static final boolean DEBUG = false;
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({SUCCESS, ERROR_UNKNOWN_FAILURE, ERROR_OPERATION_IN_PROGRESS})
- public @interface ResultCode {}
-
- /**
- * Indicates that an operation succeeded.
- */
- public static final int SUCCESS = 0;
-
- /**
- * Indicates that an install/uninstall cannot be initiated because there is one already in
- * progress.
- */
- public static final int ERROR_OPERATION_IN_PROGRESS = 1;
-
- /**
- * Indicates an install / uninstall did not fully succeed for an unknown reason.
- */
- public static final int ERROR_UNKNOWN_FAILURE = 2;
-
- private final Context mContext;
- private final IRulesManager mIRulesManager;
-
- public RulesManager(Context context) {
- mContext = context;
- mIRulesManager = IRulesManager.Stub.asInterface(
- ServiceManager.getService(Context.TIME_ZONE_RULES_MANAGER_SERVICE));
- }
-
- /**
- * Returns information about the current time zone rules state such as the IANA version of
- * the system and any currently installed distro. This method is intended to allow clients to
- * determine if the current state can be improved; for example by passing the information to a
- * server that may provide a new distro for download.
- */
- public RulesState getRulesState() {
- try {
- logDebug("sIRulesManager.getRulesState()");
- RulesState rulesState = mIRulesManager.getRulesState();
- logDebug("sIRulesManager.getRulesState() returned " + rulesState);
- return rulesState;
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Requests installation of the supplied distro. The distro must have been checked for integrity
- * by the caller or have been received via a trusted mechanism.
- *
- * @param distroFileDescriptor the file descriptor for the distro
- * @param checkToken an optional token provided if the install was triggered in response to a
- * {@link RulesUpdaterContract#ACTION_TRIGGER_RULES_UPDATE_CHECK} intent
- * @param callback the {@link Callback} to receive callbacks related to the installation
- * @return {@link #SUCCESS} if the installation will be attempted
- */
- @ResultCode
- public int requestInstall(
- ParcelFileDescriptor distroFileDescriptor, byte[] checkToken, Callback callback)
- throws IOException {
-
- ICallback iCallback = new CallbackWrapper(mContext, callback);
- try {
- logDebug("sIRulesManager.requestInstall()");
- return mIRulesManager.requestInstall(distroFileDescriptor, checkToken, iCallback);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Requests uninstallation of the currently installed distro (leaving the device with no
- * distro installed).
- *
- * @param checkToken an optional token provided if the uninstall was triggered in response to a
- * {@link RulesUpdaterContract#ACTION_TRIGGER_RULES_UPDATE_CHECK} intent
- * @param callback the {@link Callback} to receive callbacks related to the uninstall
- * @return {@link #SUCCESS} if the uninstallation will be attempted
- */
- @ResultCode
- public int requestUninstall(byte[] checkToken, Callback callback) {
- ICallback iCallback = new CallbackWrapper(mContext, callback);
- try {
- logDebug("sIRulesManager.requestUninstall()");
- return mIRulesManager.requestUninstall(checkToken, iCallback);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /*
- * We wrap incoming binder calls with a private class implementation that
- * redirects them into main-thread actions. This serializes the backup
- * progress callbacks nicely within the usual main-thread lifecycle pattern.
- */
- private class CallbackWrapper extends ICallback.Stub {
- final Handler mHandler;
- final Callback mCallback;
-
- CallbackWrapper(Context context, Callback callback) {
- mCallback = callback;
- mHandler = new Handler(context.getMainLooper());
- }
-
- // Binder calls into this object just enqueue on the main-thread handler
- @Override
- public void onFinished(int status) {
- logDebug("mCallback.onFinished(status), status=" + status);
- mHandler.post(() -> mCallback.onFinished(status));
- }
- }
-
- /**
- * Requests the system does not modify the currently installed time zone distro, if any. This
- * method records the fact that a time zone check operation triggered by the system is now
- * complete and there was nothing to do. The token passed should be the one presented when the
- * check was triggered.
- *
- * <p>Note: Passing {@code success == false} may result in more checks being triggered. Clients
- * should be careful not to pass false if the failure is unlikely to resolve by itself.
- *
- * @param checkToken an optional token provided if the install was triggered in response to a
- * {@link RulesUpdaterContract#ACTION_TRIGGER_RULES_UPDATE_CHECK} intent
- * @param succeeded true if the check was successful, false if it was not successful but may
- * succeed if it is retried
- */
- public void requestNothing(byte[] checkToken, boolean succeeded) {
- try {
- logDebug("sIRulesManager.requestNothing() with token=" + Arrays.toString(checkToken));
- mIRulesManager.requestNothing(checkToken, succeeded);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- static void logDebug(String msg) {
- if (DEBUG) {
- Log.v(TAG, msg);
- }
- }
-}
diff --git a/core/java/android/app/timezone/RulesState.aidl b/core/java/android/app/timezone/RulesState.aidl
deleted file mode 100644
index f789120eb724..000000000000
--- a/core/java/android/app/timezone/RulesState.aidl
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-parcelable RulesState; \ No newline at end of file
diff --git a/core/java/android/app/timezone/RulesState.java b/core/java/android/app/timezone/RulesState.java
deleted file mode 100644
index 33f4e8060b3e..000000000000
--- a/core/java/android/app/timezone/RulesState.java
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.timezone;
-
-import static android.app.timezone.Utils.validateConditionalNull;
-import static android.app.timezone.Utils.validateNotNull;
-import static android.app.timezone.Utils.validateRulesVersion;
-
-import android.annotation.IntDef;
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Description of the state of time zone rules on a device.
- *
- * <p>The following properties are included:
- * <dl>
- * <dt>systemRulesVersion</dt>
- * <dd>the IANA rules version that shipped with the OS. Always present. e.g. "2017a".</dd>
- * <dt>distroFormatVersionSupported</dt>
- * <dd>the distro format version supported by this device. Always present.</dd>
- * <dt>operationInProgress</dt>
- * <dd>{@code true} if there is an install / uninstall operation currently happening.</dd>
- * <dt>stagedOperationType</dt>
- * <dd>one of {@link #STAGED_OPERATION_UNKNOWN}, {@link #STAGED_OPERATION_NONE},
- * {@link #STAGED_OPERATION_UNINSTALL} and {@link #STAGED_OPERATION_INSTALL} indicating whether
- * there is a currently staged time zone distro operation. {@link #STAGED_OPERATION_UNKNOWN} is
- * used when {@link #isOperationInProgress()} is {@code true}. Staged operations currently
- * require a reboot to become active.</dd>
- * <dt>stagedDistroRulesVersion</dt>
- * <dd>[present if distroStagedState == STAGED_STATE_INSTALL], the rules version of the distro
- * currently staged for installation.</dd>
- * <dt>distroStatus</dt>
- * <dd>{@link #DISTRO_STATUS_INSTALLED} if there is a time zone distro installed and active,
- * {@link #DISTRO_STATUS_NONE} if there is no active installed distro.
- * {@link #DISTRO_STATUS_UNKNOWN} is used when {@link #isOperationInProgress()} is {@code true}.
- * </dd>
- * <dt>installedDistroRulesVersion</dt>
- * <dd>[present if distroStatus == {@link #DISTRO_STATUS_INSTALLED}], the rules version of the
- * installed and active distro.</dd>
- * </dl>
- *
- * @hide
- */
-// TODO(nfuller): Expose necessary APIs for OEMs with @SystemApi. http://b/31008728
-public final class RulesState implements Parcelable {
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({
- STAGED_OPERATION_UNKNOWN,
- STAGED_OPERATION_NONE,
- STAGED_OPERATION_UNINSTALL,
- STAGED_OPERATION_INSTALL })
- private @interface StagedOperationType {}
-
- /** Staged state could not be determined. */
- public static final int STAGED_OPERATION_UNKNOWN = 0;
- /** Nothing is staged. */
- public static final int STAGED_OPERATION_NONE = 1;
- /** An uninstall is staged. */
- public static final int STAGED_OPERATION_UNINSTALL = 2;
- /** An install is staged. */
- public static final int STAGED_OPERATION_INSTALL = 3;
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({
- DISTRO_STATUS_UNKNOWN,
- DISTRO_STATUS_NONE,
- DISTRO_STATUS_INSTALLED })
- private @interface DistroStatus {}
-
- /** The current distro status could not be determined. */
- public static final int DISTRO_STATUS_UNKNOWN = 0;
- /** There is no active installed time zone distro. */
- public static final int DISTRO_STATUS_NONE = 1;
- /** The is an active, installed time zone distro. */
- public static final int DISTRO_STATUS_INSTALLED = 2;
-
- private static final byte BYTE_FALSE = 0;
- private static final byte BYTE_TRUE = 1;
-
- private final String mSystemRulesVersion;
- private final DistroFormatVersion mDistroFormatVersionSupported;
- private final boolean mOperationInProgress;
- @StagedOperationType private final int mStagedOperationType;
- @Nullable private final DistroRulesVersion mStagedDistroRulesVersion;
- @DistroStatus private final int mDistroStatus;
- @Nullable private final DistroRulesVersion mInstalledDistroRulesVersion;
-
- public RulesState(String systemRulesVersion, DistroFormatVersion distroFormatVersionSupported,
- boolean operationInProgress,
- @StagedOperationType int stagedOperationType,
- @Nullable DistroRulesVersion stagedDistroRulesVersion,
- @DistroStatus int distroStatus,
- @Nullable DistroRulesVersion installedDistroRulesVersion) {
- this.mSystemRulesVersion = validateRulesVersion("systemRulesVersion", systemRulesVersion);
- this.mDistroFormatVersionSupported =
- validateNotNull("distroFormatVersionSupported", distroFormatVersionSupported);
- this.mOperationInProgress = operationInProgress;
-
- if (operationInProgress && stagedOperationType != STAGED_OPERATION_UNKNOWN) {
- throw new IllegalArgumentException(
- "stagedOperationType != STAGED_OPERATION_UNKNOWN");
- }
- this.mStagedOperationType = validateStagedOperation(stagedOperationType);
- this.mStagedDistroRulesVersion = validateConditionalNull(
- mStagedOperationType == STAGED_OPERATION_INSTALL /* requireNotNull */,
- "stagedDistroRulesVersion", stagedDistroRulesVersion);
-
- if (operationInProgress && distroStatus != DISTRO_STATUS_UNKNOWN) {
- throw new IllegalArgumentException("distroInstalled != DISTRO_STATUS_UNKNOWN");
- }
- this.mDistroStatus = validateDistroStatus(distroStatus);
- this.mInstalledDistroRulesVersion = validateConditionalNull(
- mDistroStatus == DISTRO_STATUS_INSTALLED/* requireNotNull */,
- "installedDistroRulesVersion", installedDistroRulesVersion);
- }
-
- public String getSystemRulesVersion() {
- return mSystemRulesVersion;
- }
-
- public boolean isOperationInProgress() {
- return mOperationInProgress;
- }
-
- public @StagedOperationType int getStagedOperationType() {
- return mStagedOperationType;
- }
-
- /**
- * Returns the staged rules version when {@link #getStagedOperationType()} is
- * {@link #STAGED_OPERATION_INSTALL}.
- */
- public @Nullable DistroRulesVersion getStagedDistroRulesVersion() {
- return mStagedDistroRulesVersion;
- }
-
- public @DistroStatus int getDistroStatus() {
- return mDistroStatus;
- }
-
- /**
- * Returns the installed rules version when {@link #getDistroStatus()} is
- * {@link #DISTRO_STATUS_INSTALLED}.
- */
- public @Nullable DistroRulesVersion getInstalledDistroRulesVersion() {
- return mInstalledDistroRulesVersion;
- }
-
- /**
- * Returns true if a distro in the specified format is supported on this device.
- */
- public boolean isDistroFormatVersionSupported(DistroFormatVersion distroFormatVersion) {
- return mDistroFormatVersionSupported.supports(distroFormatVersion);
- }
-
- /**
- * Returns true if the distro IANA rules version supplied is newer or the same as the version in
- * the system image data files.
- */
- public boolean isSystemVersionOlderThan(DistroRulesVersion distroRulesVersion) {
- return mSystemRulesVersion.compareTo(distroRulesVersion.getRulesVersion()) < 0;
- }
-
- public boolean isDistroInstalled() {
- return mDistroStatus == DISTRO_STATUS_INSTALLED;
- }
-
- /**
- * Returns true if the rules version supplied is newer than the one currently installed. If
- * there is no installed distro this method throws IllegalStateException.
- */
- public boolean isInstalledDistroOlderThan(DistroRulesVersion distroRulesVersion) {
- if (mOperationInProgress) {
- throw new IllegalStateException("Distro state not known: operation in progress.");
- }
- if (!isDistroInstalled()) {
- throw new IllegalStateException("No distro installed.");
- }
- return mInstalledDistroRulesVersion.isOlderThan(distroRulesVersion);
- }
-
- public static final Parcelable.Creator<RulesState> CREATOR =
- new Parcelable.Creator<RulesState>() {
- public RulesState createFromParcel(Parcel in) {
- return RulesState.createFromParcel(in);
- }
-
- public RulesState[] newArray(int size) {
- return new RulesState[size];
- }
- };
-
- private static RulesState createFromParcel(Parcel in) {
- String systemRulesVersion = in.readString();
- DistroFormatVersion distroFormatVersionSupported = in.readParcelable(null);
- boolean operationInProgress = in.readByte() == BYTE_TRUE;
- int distroStagedState = in.readByte();
- DistroRulesVersion stagedDistroRulesVersion = in.readParcelable(null);
- int installedDistroStatus = in.readByte();
- DistroRulesVersion installedDistroRulesVersion = in.readParcelable(null);
- return new RulesState(systemRulesVersion, distroFormatVersionSupported, operationInProgress,
- distroStagedState, stagedDistroRulesVersion,
- installedDistroStatus, installedDistroRulesVersion);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(mSystemRulesVersion);
- out.writeParcelable(mDistroFormatVersionSupported, 0);
- out.writeByte(mOperationInProgress ? BYTE_TRUE : BYTE_FALSE);
- out.writeByte((byte) mStagedOperationType);
- out.writeParcelable(mStagedDistroRulesVersion, 0);
- out.writeByte((byte) mDistroStatus);
- out.writeParcelable(mInstalledDistroRulesVersion, 0);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- RulesState that = (RulesState) o;
-
- if (mOperationInProgress != that.mOperationInProgress) {
- return false;
- }
- if (mStagedOperationType != that.mStagedOperationType) {
- return false;
- }
- if (mDistroStatus != that.mDistroStatus) {
- return false;
- }
- if (!mSystemRulesVersion.equals(that.mSystemRulesVersion)) {
- return false;
- }
- if (!mDistroFormatVersionSupported.equals(that.mDistroFormatVersionSupported)) {
- return false;
- }
- if (mStagedDistroRulesVersion != null ? !mStagedDistroRulesVersion
- .equals(that.mStagedDistroRulesVersion) : that.mStagedDistroRulesVersion != null) {
- return false;
- }
- return mInstalledDistroRulesVersion != null ? mInstalledDistroRulesVersion
- .equals(that.mInstalledDistroRulesVersion)
- : that.mInstalledDistroRulesVersion == null;
- }
-
- @Override
- public int hashCode() {
- int result = mSystemRulesVersion.hashCode();
- result = 31 * result + mDistroFormatVersionSupported.hashCode();
- result = 31 * result + (mOperationInProgress ? 1 : 0);
- result = 31 * result + mStagedOperationType;
- result = 31 * result + (mStagedDistroRulesVersion != null ? mStagedDistroRulesVersion
- .hashCode()
- : 0);
- result = 31 * result + mDistroStatus;
- result = 31 * result + (mInstalledDistroRulesVersion != null ? mInstalledDistroRulesVersion
- .hashCode() : 0);
- return result;
- }
-
- @Override
- public String toString() {
- return "RulesState{"
- + "mSystemRulesVersion='" + mSystemRulesVersion + '\''
- + ", mDistroFormatVersionSupported=" + mDistroFormatVersionSupported
- + ", mOperationInProgress=" + mOperationInProgress
- + ", mStagedOperationType=" + mStagedOperationType
- + ", mStagedDistroRulesVersion=" + mStagedDistroRulesVersion
- + ", mDistroStatus=" + mDistroStatus
- + ", mInstalledDistroRulesVersion=" + mInstalledDistroRulesVersion
- + '}';
- }
-
- private static int validateStagedOperation(int stagedOperationType) {
- if (stagedOperationType < STAGED_OPERATION_UNKNOWN
- || stagedOperationType > STAGED_OPERATION_INSTALL) {
- throw new IllegalArgumentException("Unknown operation type=" + stagedOperationType);
- }
- return stagedOperationType;
- }
-
- private static int validateDistroStatus(int distroStatus) {
- if (distroStatus < DISTRO_STATUS_UNKNOWN || distroStatus > DISTRO_STATUS_INSTALLED) {
- throw new IllegalArgumentException("Unknown distro status=" + distroStatus);
- }
- return distroStatus;
- }
-}
diff --git a/core/java/android/app/timezone/RulesUpdaterContract.java b/core/java/android/app/timezone/RulesUpdaterContract.java
deleted file mode 100644
index 4e7781866aae..000000000000
--- a/core/java/android/app/timezone/RulesUpdaterContract.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.timezone;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.ParcelFileDescriptor;
-
-/**
- * Constants related to the contract between the Android system and the privileged time zone updater
- * application.
- *
- * @hide
- */
-// TODO(nfuller): Expose necessary APIs for OEMs with @SystemApi. http://b/31008728
-public final class RulesUpdaterContract {
-
- /**
- * The system permission possessed by the Android system that allows it to trigger time zone
- * update checks. The updater should be configured to require this permission when registering
- * for {@link #ACTION_TRIGGER_RULES_UPDATE_CHECK} intents.
- */
- public static final String TRIGGER_TIME_ZONE_RULES_CHECK_PERMISSION =
- android.Manifest.permission.TRIGGER_TIME_ZONE_RULES_CHECK;
-
- /**
- * The system permission possessed by the time zone rules updater app that allows it to update
- * device time zone rules. The Android system requires this permission for calls made to
- * {@link RulesManager}.
- */
- public static final String UPDATE_TIME_ZONE_RULES_PERMISSION =
- android.Manifest.permission.UPDATE_TIME_ZONE_RULES;
-
- /**
- * The action of the intent that the Android system will broadcast. The intent will be targeted
- * at the configured updater application's package meaning the term "broadcast" only loosely
- * applies.
- */
- public static final String ACTION_TRIGGER_RULES_UPDATE_CHECK =
- "android.intent.action.timezone.TRIGGER_RULES_UPDATE_CHECK";
-
- /**
- * The extra containing the {@code byte[]} that should be passed to
- * {@link RulesManager#requestInstall(ParcelFileDescriptor, byte[], Callback)},
- * {@link RulesManager#requestUninstall(byte[], Callback)} and
- * {@link RulesManager#requestNothing(byte[], boolean)} methods when the
- * {@link #ACTION_TRIGGER_RULES_UPDATE_CHECK} intent has been processed.
- */
- public static final String EXTRA_CHECK_TOKEN =
- "android.intent.extra.timezone.CHECK_TOKEN";
-
- /**
- * Creates an intent that would trigger a time zone rules update check.
- */
- public static Intent createUpdaterIntent(String updaterPackageName) {
- Intent intent = new Intent(RulesUpdaterContract.ACTION_TRIGGER_RULES_UPDATE_CHECK);
- intent.setPackage(updaterPackageName);
- intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
- return intent;
- }
-
- /**
- * Broadcasts an {@link #ACTION_TRIGGER_RULES_UPDATE_CHECK} intent with the
- * {@link #EXTRA_CHECK_TOKEN} that triggers an update check, including the required receiver
- * permission.
- */
- public static void sendBroadcast(Context context, String updaterAppPackageName,
- byte[] checkTokenBytes) {
- Intent intent = createUpdaterIntent(updaterAppPackageName);
- intent.putExtra(EXTRA_CHECK_TOKEN, checkTokenBytes);
- context.sendBroadcast(intent, RulesUpdaterContract.UPDATE_TIME_ZONE_RULES_PERMISSION);
- }
-}
diff --git a/core/java/android/app/timezone/Utils.java b/core/java/android/app/timezone/Utils.java
deleted file mode 100644
index 8dd3fb71aa0e..000000000000
--- a/core/java/android/app/timezone/Utils.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.app.timezone;
-
-/**
- * Shared code for android.app.timezone classes.
- */
-final class Utils {
- private Utils() {}
-
- static int validateVersion(String type, int version) {
- if (version < 0 || version > 999) {
- throw new IllegalArgumentException("Invalid " + type + " version=" + version);
- }
- return version;
- }
-
- static String validateRulesVersion(String type, String rulesVersion) {
- validateNotNull(type, rulesVersion);
-
- if (rulesVersion.isEmpty()) {
- throw new IllegalArgumentException(type + " must not be empty");
- }
- return rulesVersion;
- }
-
- /** Validates that {@code object} is not null. Always returns {@code object}. */
- static <T> T validateNotNull(String type, T object) {
- if (object == null) {
- throw new NullPointerException(type + " == null");
- }
- return object;
- }
-
- /**
- * If {@code requireNotNull} is {@code true} calls {@link #validateNotNull(String, Object)},
- * and {@link #validateNull(String, Object)} otherwise. Returns {@code object}.
- */
- static <T> T validateConditionalNull(boolean requireNotNull, String type, T object) {
- if (requireNotNull) {
- return validateNotNull(type, object);
- } else {
- return validateNull(type, object);
- }
- }
-
- /** Validates that {@code object} is null. Always returns null. */
- static <T> T validateNull(String type, T object) {
- if (object != null) {
- throw new IllegalArgumentException(type + " != null");
- }
- return null;
- }
-}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 7d2f8d18783e..916fb7c59b11 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -34,6 +34,7 @@ import android.annotation.TestApi;
import android.annotation.UserIdInt;
import android.app.IApplicationThread;
import android.app.IServiceConnection;
+import android.app.Notification;
import android.app.VrManager;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -2711,8 +2712,8 @@ public abstract class Context {
/**
* Similar to {@link #startService(Intent)}, but with an implicit promise that the
- * Service will call {@link android.app.Service#startForeground(int, android.app.Notification)
- * startForeground(int, android.app.Notification)} once it begins running. The service is given
+ * Service will call {@link android.app.Service#startForeground(int, Notification)
+ * startForeground(int, Notification)} once it begins running. The service is given
* an amount of time comparable to the ANR interval to do this, otherwise the system
* will automatically stop the service and declare the app ANR.
*
@@ -2733,7 +2734,7 @@ public abstract class Context {
* or the service can not be found.
*
* @see #stopService
- * @see android.app.Service#startForeground(int, android.app.Notification)
+ * @see android.app.Service#startForeground(int, Notification)
*/
@Nullable
public abstract ComponentName startForegroundService(Intent service);
@@ -2921,7 +2922,6 @@ public abstract class Context {
STORAGE_SERVICE,
STORAGE_STATS_SERVICE,
WALLPAPER_SERVICE,
- TIME_ZONE_RULES_MANAGER_SERVICE,
VIBRATOR_SERVICE,
//@hide: STATUS_BAR_SERVICE,
CONNECTIVITY_SERVICE,
@@ -4026,15 +4026,6 @@ public abstract class Context {
public static final String VR_SERVICE = "vrmanager";
/**
- * Use with {@link #getSystemService} to retrieve an
- * {@link android.app.timezone.ITimeZoneRulesManager}.
- * @hide
- *
- * @see #getSystemService
- */
- public static final String TIME_ZONE_RULES_MANAGER_SERVICE = "timezone";
-
- /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 9a908ae038f6..7c2f233a3e45 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2219,22 +2219,6 @@
<permission android:name="android.permission.UPDATE_CONFIG"
android:protectionLevel="signature|privileged" />
- <!-- Allows a time zone rule updater application to request
- the system installs / uninstalls timezone rules.
- <p>An application requesting this permission is responsible for
- verifying the source and integrity of the update before passing
- it off to the installer components.
- @hide -->
- <permission android:name="android.permission.UPDATE_TIME_ZONE_RULES"
- android:protectionLevel="signature|privileged" />
-
- <!-- Must be required by a time zone rule updater application,
- to ensure that only the system can trigger it.
- @hide -->
- <permission android:name="android.permission.TRIGGER_TIME_ZONE_RULES_CHECK"
- android:protectionLevel="signature" />
- <uses-permission android:name="android.permission.TRIGGER_TIME_ZONE_RULES_CHECK"/>
-
<!-- Allows the system to reset throttling in shortcut manager.
@hide -->
<permission android:name="android.permission.RESET_SHORTCUT_MANAGER_THROTTLING"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f00943438ac7..d1b3fec451db 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1282,49 +1282,6 @@
<!-- True if WallpaperService is enabled -->
<bool name="config_enableWallpaperService">true</bool>
- <!-- Enables the TimeZoneRuleManager service. This is the master switch for the updateable time
- zone update mechanism. -->
- <bool name="config_enableUpdateableTimeZoneRules">false</bool>
-
- <!-- Enables APK-based time zone update triggering. Set this to false when updates are triggered
- via external events and not by APK updates. For example, if an updater checks with a server
- on a regular schedule.
- [This is only used if config_enableUpdateableTimeZoneRules is true.] -->
- <bool name="config_timeZoneRulesUpdateTrackingEnabled">false</bool>
-
- <!-- The package of the time zone rules updater application. Expected to be the same
- for all Android devices that support APK-based time zone rule updates.
- A package-targeted android.intent.action.timezone.TRIGGER_RULES_UPDATE_CHECK intent
- will be sent to the updater app if the system server detects an update to the updater or
- data app packages.
- The package referenced here must have the android.permission.UPDATE_TIME_ZONE_RULES
- permission.
- [This is only used if config_enableUpdateableTimeZoneRules and
- config_timeZoneRulesUpdateTrackingEnabled are true.] -->
- <string name="config_timeZoneRulesUpdaterPackage" translateable="false"></string>
-
- <!-- The package of the time zone rules data application. Expected to be configured
- by OEMs to reference their own priv-app APK package.
- A package-targeted android.intent.action.timezone.TRIGGER_RULES_UPDATE_CHECK intent
- will be sent to the updater app if the system server detects an update to the updater or
- data app packages.
- [This is only used if config_enableUpdateableTimeZoneRules and
- config_timeZoneRulesUpdateTrackingEnabled are true.] -->
- <string name="config_timeZoneRulesDataPackage" translateable="false"></string>
-
- <!-- The allowed time in milliseconds between an update check intent being broadcast and the
- response being considered overdue. Reliability triggers will not fire in this time.
- [This is only used if config_enableUpdateableTimeZoneRules and
- config_timeZoneRulesUpdateTrackingEnabled are true.] -->
- <!-- 5 minutes -->
- <integer name="config_timeZoneRulesCheckTimeMillisAllowed">300000</integer>
-
- <!-- The number of times a time zone update check is allowed to fail before the system will stop
- reacting to reliability triggers.
- [This is only used if config_enableUpdateableTimeZoneRules and
- config_timeZoneRulesUpdateTrackingEnabled are true.] -->
- <integer name="config_timeZoneRulesCheckRetryCount">5</integer>
-
<!-- Whether to enable network location overlay which allows network
location provider to be replaced by an app at run-time. When disabled,
only the config_networkLocationProviderPackageName package will be
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 316e2024e07e..975737b71220 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -284,12 +284,6 @@
<java-symbol type="bool" name="split_action_bar_is_narrow" />
<java-symbol type="bool" name="config_useVolumeKeySounds" />
<java-symbol type="bool" name="config_enableWallpaperService" />
- <java-symbol type="bool" name="config_enableUpdateableTimeZoneRules" />
- <java-symbol type="bool" name="config_timeZoneRulesUpdateTrackingEnabled" />
- <java-symbol type="string" name="config_timeZoneRulesUpdaterPackage" />
- <java-symbol type="string" name="config_timeZoneRulesDataPackage" />
- <java-symbol type="integer" name="config_timeZoneRulesCheckTimeMillisAllowed" />
- <java-symbol type="integer" name="config_timeZoneRulesCheckRetryCount" />
<java-symbol type="bool" name="config_sendAudioBecomingNoisy" />
<java-symbol type="bool" name="config_enableScreenshotChord" />
<java-symbol type="bool" name="config_bluetooth_default_profiles" />
diff --git a/core/tests/coretests/src/android/app/timezone/DistroFormatVersionTest.java b/core/tests/coretests/src/android/app/timezone/DistroFormatVersionTest.java
deleted file mode 100644
index 9bbcd3d2d2e9..000000000000
--- a/core/tests/coretests/src/android/app/timezone/DistroFormatVersionTest.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.timezone;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.os.Parcel;
-
-import org.junit.Test;
-
-/**
- * Tests for {@link DistroFormatVersion}.
- */
-// TODO(nfuller) Move to CTS once this class is part of the SystemApi. http://b/31008728
-public class DistroFormatVersionTest {
-
- @Test
- public void equalsAndHashCode() {
- DistroFormatVersion one = new DistroFormatVersion(1, 2);
- assertEqualsContract(one, one);
-
- DistroFormatVersion two = new DistroFormatVersion(1, 2);
- assertEqualsContract(one, two);
-
- DistroFormatVersion three = new DistroFormatVersion(2, 1);
- assertFalse(one.equals(three));
- }
-
- @Test
- public void parcelable() {
- DistroFormatVersion version = new DistroFormatVersion(2, 3);
-
- Parcel parcel = Parcel.obtain();
- version.writeToParcel(parcel, 0 /* flags */);
- parcel.setDataPosition(0);
-
- DistroFormatVersion newVersion = DistroFormatVersion.CREATOR.createFromParcel(parcel);
-
- assertEquals(version, newVersion);
- }
-
- @Test
- public void supportsVersion() {
- DistroFormatVersion deviceVersion = new DistroFormatVersion(2, 2);
- assertTrue(deviceVersion.supports(deviceVersion));
-
- DistroFormatVersion sameVersion = new DistroFormatVersion(2, 2);
- assertTrue(deviceVersion.supports(sameVersion));
-
- // Minor versions are backwards compatible.
- DistroFormatVersion sameMajorNewerMinor = new DistroFormatVersion(2, 3);
- assertTrue(deviceVersion.supports(sameMajorNewerMinor));
- DistroFormatVersion sameMajorOlderMinor = new DistroFormatVersion(2, 1);
- assertFalse(deviceVersion.supports(sameMajorOlderMinor));
-
- // Major versions are not backwards compatible.
- DistroFormatVersion newerMajor = new DistroFormatVersion(1, 2);
- assertFalse(deviceVersion.supports(newerMajor));
- DistroFormatVersion olderMajor = new DistroFormatVersion(3, 2);
- assertFalse(deviceVersion.supports(olderMajor));
- }
-
- private static void assertEqualsContract(DistroFormatVersion one, DistroFormatVersion two) {
- assertEquals(one, two);
- assertEquals(one.hashCode(), two.hashCode());
- }
-}
diff --git a/core/tests/coretests/src/android/app/timezone/DistroRulesVersionTest.java b/core/tests/coretests/src/android/app/timezone/DistroRulesVersionTest.java
deleted file mode 100644
index 2fbc9a1f8e7a..000000000000
--- a/core/tests/coretests/src/android/app/timezone/DistroRulesVersionTest.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.timezone;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.os.Parcel;
-
-import org.junit.Test;
-
-/**
- * Tests for {@link DistroRulesVersion}.
- */
-// TODO(nfuller) Move to CTS once this class is part of the SystemApi. http://b/31008728
-public class DistroRulesVersionTest {
-
- @Test
- public void equalsAndHashCode() {
- DistroRulesVersion one = new DistroRulesVersion("2016a", 2);
- assertEqualsContract(one, one);
-
- DistroRulesVersion two = new DistroRulesVersion("2016a", 2);
- assertEqualsContract(one, two);
-
- DistroRulesVersion three = new DistroRulesVersion("2016b", 1);
- assertFalse(one.equals(three));
- }
-
- @Test
- public void parcelable() {
- DistroRulesVersion version = new DistroRulesVersion("2016a", 2);
-
- Parcel parcel = Parcel.obtain();
- version.writeToParcel(parcel, 0 /* flags */);
- parcel.setDataPosition(0);
-
- DistroRulesVersion newVersion = DistroRulesVersion.CREATOR.createFromParcel(parcel);
-
- assertEquals(version, newVersion);
- }
-
- @Test
- public void isOlderThan() {
- DistroRulesVersion deviceVersion = new DistroRulesVersion("2016b", 2);
- assertFalse(deviceVersion.isOlderThan(deviceVersion));
-
- DistroRulesVersion sameVersion = new DistroRulesVersion("2016b", 2);
- assertFalse(deviceVersion.isOlderThan(sameVersion));
-
- DistroRulesVersion sameRulesNewerRevision = new DistroRulesVersion("2016b", 3);
- assertTrue(deviceVersion.isOlderThan(sameRulesNewerRevision));
-
- DistroRulesVersion sameRulesOlderRevision = new DistroRulesVersion("2016b", 1);
- assertFalse(deviceVersion.isOlderThan(sameRulesOlderRevision));
-
- DistroRulesVersion newerRules = new DistroRulesVersion("2016c", 2);
- assertTrue(deviceVersion.isOlderThan(newerRules));
-
- DistroRulesVersion olderRules = new DistroRulesVersion("2016a", 2);
- assertFalse(deviceVersion.isOlderThan(olderRules));
- }
-
- private static void assertEqualsContract(DistroRulesVersion one, DistroRulesVersion two) {
- assertEquals(one, two);
- assertEquals(one.hashCode(), two.hashCode());
- }
-}
diff --git a/core/tests/coretests/src/android/app/timezone/RulesStateTest.java b/core/tests/coretests/src/android/app/timezone/RulesStateTest.java
deleted file mode 100644
index a9357c9175ab..000000000000
--- a/core/tests/coretests/src/android/app/timezone/RulesStateTest.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.timezone;
-
-import static junit.framework.Assert.fail;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.os.Parcel;
-
-import org.junit.Test;
-
-/**
- * Tests for {@link RulesState}.
- */
-// TODO(nfuller) Move to CTS once this class is part of the SystemApi. http://b/31008728
-public class RulesStateTest {
-
- @Test
- public void equalsAndHashCode() {
- RulesState one = new RulesState(
- "2016a", formatVersion(1, 2), false /* operationInProgress */,
- RulesState.STAGED_OPERATION_INSTALL, rulesVersion("2016a", 3),
- RulesState.DISTRO_STATUS_INSTALLED, rulesVersion("2016b", 2));
- assertEqualsContract(one, one);
-
- RulesState two = new RulesState(
- "2016a", formatVersion(1, 2), false /* operationInProgress */,
- RulesState.STAGED_OPERATION_INSTALL, rulesVersion("2016a", 3),
- RulesState.DISTRO_STATUS_INSTALLED, rulesVersion("2016b", 2));
- assertEqualsContract(one, two);
-
- RulesState differentSystemRules = new RulesState(
- "2016b", formatVersion(1, 2), false /* operationInProgress */,
- RulesState.STAGED_OPERATION_INSTALL, rulesVersion("2016a", 3),
- RulesState.DISTRO_STATUS_INSTALLED, rulesVersion("2016b", 2));
- assertFalse(one.equals(differentSystemRules));
-
- RulesState differentFormatVersion = new RulesState(
- "2016a", formatVersion(1, 1), false /* operationInProgress */,
- RulesState.STAGED_OPERATION_INSTALL, rulesVersion("2016a", 3),
- RulesState.DISTRO_STATUS_INSTALLED, rulesVersion("2016b", 2));
- assertFalse(one.equals(differentFormatVersion));
-
- RulesState differentOperationInProgress = new RulesState(
- "2016a", formatVersion(1, 1), true /* operationInProgress */,
- RulesState.STAGED_OPERATION_UNKNOWN, null /* stagedDistroRulesVersion */,
- RulesState.DISTRO_STATUS_UNKNOWN, null /* installedDistroRulesVersion */);
- assertFalse(one.equals(differentOperationInProgress));
-
- RulesState differentStagedOperation = new RulesState(
- "2016a", formatVersion(1, 1), false /* operationInProgress */,
- RulesState.STAGED_OPERATION_UNINSTALL, null /* stagedDistroRulesVersion */,
- RulesState.DISTRO_STATUS_INSTALLED, rulesVersion("2016b", 2));
- assertFalse(one.equals(differentStagedOperation));
-
- RulesState differentStagedInstallVersion = new RulesState(
- "2016a", formatVersion(1, 1), false /* operationInProgress */,
- RulesState.STAGED_OPERATION_INSTALL, rulesVersion("2016a", 4),
- RulesState.DISTRO_STATUS_INSTALLED, rulesVersion("2016b", 2));
- assertFalse(one.equals(differentStagedInstallVersion));
-
- RulesState differentInstalled = new RulesState(
- "2016a", formatVersion(1, 1), false /* operationInProgress */,
- RulesState.STAGED_OPERATION_INSTALL, rulesVersion("2016a", 3),
- RulesState.DISTRO_STATUS_NONE, null /* installedDistroRulesVersion */);
- assertFalse(one.equals(differentInstalled));
-
- RulesState differentInstalledVersion = new RulesState(
- "2016a", formatVersion(1, 1), false /* operationInProgress */,
- RulesState.STAGED_OPERATION_INSTALL, rulesVersion("2016a", 3),
- RulesState.DISTRO_STATUS_INSTALLED, rulesVersion("2016b", 3));
- assertFalse(one.equals(differentInstalledVersion));
- }
-
- @Test
- public void parcelable() {
- RulesState rulesState1 = new RulesState(
- "2016a", formatVersion(1, 1), false /* operationInProgress */,
- RulesState.STAGED_OPERATION_INSTALL, rulesVersion("2016b", 2),
- RulesState.DISTRO_STATUS_INSTALLED, rulesVersion("2016b", 3));
- checkParcelableRoundTrip(rulesState1);
-
- RulesState rulesStateWithNulls = new RulesState(
- "2016a", formatVersion(1, 1), false /* operationInProgress */,
- RulesState.STAGED_OPERATION_NONE, null /* stagedDistroRulesVersion */,
- RulesState.DISTRO_STATUS_NONE, null /* installedDistroRulesVersion */);
- checkParcelableRoundTrip(rulesStateWithNulls);
-
- RulesState rulesStateWithUnknowns = new RulesState(
- "2016a", formatVersion(1, 1), true /* operationInProgress */,
- RulesState.STAGED_OPERATION_UNKNOWN, null /* stagedDistroRulesVersion */,
- RulesState.DISTRO_STATUS_UNKNOWN, null /* installedDistroRulesVersion */);
- checkParcelableRoundTrip(rulesStateWithNulls);
- }
-
- private static void checkParcelableRoundTrip(RulesState rulesState) {
- Parcel parcel = Parcel.obtain();
- rulesState.writeToParcel(parcel, 0 /* flags */);
- parcel.setDataPosition(0);
-
- RulesState newVersion = RulesState.CREATOR.createFromParcel(parcel);
-
- assertEquals(rulesState, newVersion);
- }
-
- @Test
- public void isSystemVersionOlderThan() {
- RulesState rulesState = new RulesState(
- "2016b", formatVersion(1, 1), false /* operationInProgress */,
- RulesState.STAGED_OPERATION_NONE, null /* stagedDistroRulesVersion */,
- RulesState.DISTRO_STATUS_INSTALLED, rulesVersion("2016b", 3));
- assertFalse(rulesState.isSystemVersionOlderThan(rulesVersion("2016a", 1)));
- assertFalse(rulesState.isSystemVersionOlderThan(rulesVersion("2016b", 1)));
- assertTrue(rulesState.isSystemVersionOlderThan(rulesVersion("2016c", 1)));
- }
-
- @Test
- public void isInstalledDistroOlderThan() {
- RulesState operationInProgress = new RulesState(
- "2016b", formatVersion(1, 1), true /* operationInProgress */,
- RulesState.STAGED_OPERATION_UNKNOWN, null /* stagedDistroRulesVersion */,
- RulesState.STAGED_OPERATION_UNKNOWN, null /* installedDistroRulesVersion */);
- try {
- operationInProgress.isInstalledDistroOlderThan(rulesVersion("2016b", 1));
- fail();
- } catch (IllegalStateException expected) {
- }
-
- RulesState nothingInstalled = new RulesState(
- "2016b", formatVersion(1, 1), false /* operationInProgress */,
- RulesState.STAGED_OPERATION_NONE, null /* stagedDistroRulesVersion */,
- RulesState.DISTRO_STATUS_NONE, null /* installedDistroRulesVersion */);
- try {
- nothingInstalled.isInstalledDistroOlderThan(rulesVersion("2016b", 1));
- fail();
- } catch (IllegalStateException expected) {
- }
-
- DistroRulesVersion installedVersion = rulesVersion("2016b", 3);
- RulesState rulesStateWithInstalledVersion = new RulesState(
- "2016b", formatVersion(1, 1), false /* operationInProgress */,
- RulesState.STAGED_OPERATION_NONE, null /* stagedDistroRulesVersion */,
- RulesState.DISTRO_STATUS_INSTALLED, installedVersion);
-
- DistroRulesVersion olderRules = rulesVersion("2016a", 1);
- assertEquals(installedVersion.isOlderThan(olderRules),
- rulesStateWithInstalledVersion.isInstalledDistroOlderThan(olderRules));
-
- DistroRulesVersion sameRules = rulesVersion("2016b", 1);
- assertEquals(installedVersion.isOlderThan(sameRules),
- rulesStateWithInstalledVersion.isInstalledDistroOlderThan(sameRules));
-
- DistroRulesVersion newerRules = rulesVersion("2016c", 1);
- assertEquals(installedVersion.isOlderThan(newerRules),
- rulesStateWithInstalledVersion.isInstalledDistroOlderThan(newerRules));
- }
-
- private static void assertEqualsContract(RulesState one, RulesState two) {
- assertEquals(one, two);
- assertEquals(one.hashCode(), two.hashCode());
- }
-
- private static DistroRulesVersion rulesVersion(String rulesVersion, int revision) {
- return new DistroRulesVersion(rulesVersion, revision);
- }
-
- private static DistroFormatVersion formatVersion(int majorVersion, int minorVersion) {
- return new DistroFormatVersion(majorVersion, minorVersion);
- }
-}
diff --git a/core/tests/coretests/src/android/app/timezone/RulesUpdaterContractTest.java b/core/tests/coretests/src/android/app/timezone/RulesUpdaterContractTest.java
deleted file mode 100644
index e7a839c3e9fb..000000000000
--- a/core/tests/coretests/src/android/app/timezone/RulesUpdaterContractTest.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.timezone;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.hamcrest.MockitoHamcrest.argThat;
-
-import android.content.Context;
-import android.content.Intent;
-
-import org.hamcrest.BaseMatcher;
-import org.hamcrest.Description;
-import org.hamcrest.Matcher;
-import org.junit.Test;
-
-/**
- * Tests for {@link RulesUpdaterContract}.
- */
-// TODO(nfuller) Move to CTS once this class is part of the SystemApi. http://b/31008728
-public class RulesUpdaterContractTest {
-
- @Test
- public void createUpdaterIntent() throws Exception {
- String packageName = "foobar";
- Intent intent = RulesUpdaterContract.createUpdaterIntent(packageName);
-
- assertEquals(RulesUpdaterContract.ACTION_TRIGGER_RULES_UPDATE_CHECK, intent.getAction());
- assertEquals(packageName, intent.getPackage());
- assertEquals(Intent.FLAG_INCLUDE_STOPPED_PACKAGES, intent.getFlags());
- }
-
- @Test
- public void sendBroadcast() throws Exception {
- String packageName = "foobar";
- byte[] tokenBytes = new byte[] { 1, 2, 3, 4, 5 };
-
- Intent expectedIntent = RulesUpdaterContract.createUpdaterIntent(packageName);
- expectedIntent.putExtra(RulesUpdaterContract.EXTRA_CHECK_TOKEN, tokenBytes);
-
- Context mockContext = mock(Context.class);
-
- RulesUpdaterContract.sendBroadcast(mockContext, packageName, tokenBytes);
-
- verify(mockContext).sendBroadcast(
- filterEquals(expectedIntent),
- eq(RulesUpdaterContract.UPDATE_TIME_ZONE_RULES_PERMISSION));
- }
-
- /**
- * Registers a mockito parameter matcher that uses {@link Intent#filterEquals(Intent)}. to
- * check the parameter against the intent supplied.
- */
- private static Intent filterEquals(final Intent expected) {
- final Matcher<Intent> m = new BaseMatcher<Intent>() {
- @Override
- public boolean matches(Object actual) {
- return actual != null && expected.filterEquals((Intent) actual);
- }
- @Override
- public void describeTo(Description description) {
- description.appendText(expected.toString());
- }
- };
- return argThat(m);
- }
-}
diff --git a/services/core/java/com/android/server/timezone/CheckToken.java b/services/core/java/com/android/server/timezone/CheckToken.java
deleted file mode 100644
index 51283608c66e..000000000000
--- a/services/core/java/com/android/server/timezone/CheckToken.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.timezone;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.util.Arrays;
-
-/**
- * A deserialized version of the byte[] sent to the time zone update application to identify a
- * triggered time zone update check. It encodes the optimistic lock ID used to detect
- * concurrent checks and the minimal package versions that will have been checked.
- */
-final class CheckToken {
-
- final int mOptimisticLockId;
- final PackageVersions mPackageVersions;
-
- CheckToken(int optimisticLockId, PackageVersions packageVersions) {
- this.mOptimisticLockId = optimisticLockId;
-
- if (packageVersions == null) {
- throw new NullPointerException("packageVersions == null");
- }
- this.mPackageVersions = packageVersions;
- }
-
- byte[] toByteArray() {
- ByteArrayOutputStream baos = new ByteArrayOutputStream(12 /* (3 * sizeof(int)) */);
- try (DataOutputStream dos = new DataOutputStream(baos)) {
- dos.writeInt(mOptimisticLockId);
- dos.writeInt(mPackageVersions.mUpdateAppVersion);
- dos.writeInt(mPackageVersions.mDataAppVersion);
- } catch (IOException e) {
- throw new RuntimeException("Unable to write into a ByteArrayOutputStream", e);
- }
- return baos.toByteArray();
- }
-
- static CheckToken fromByteArray(byte[] tokenBytes) throws IOException {
- ByteArrayInputStream bais = new ByteArrayInputStream(tokenBytes);
- try (DataInputStream dis = new DataInputStream(bais)) {
- int versionId = dis.readInt();
- int updateAppVersion = dis.readInt();
- int dataAppVersion = dis.readInt();
- return new CheckToken(versionId, new PackageVersions(updateAppVersion, dataAppVersion));
- }
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- CheckToken checkToken = (CheckToken) o;
-
- if (mOptimisticLockId != checkToken.mOptimisticLockId) {
- return false;
- }
- return mPackageVersions.equals(checkToken.mPackageVersions);
- }
-
- @Override
- public int hashCode() {
- int result = mOptimisticLockId;
- result = 31 * result + mPackageVersions.hashCode();
- return result;
- }
-
- @Override
- public String toString() {
- return "Token{" +
- "mOptimisticLockId=" + mOptimisticLockId +
- ", mPackageVersions=" + mPackageVersions +
- '}';
- }
-}
diff --git a/services/core/java/com/android/server/timezone/ClockHelper.java b/services/core/java/com/android/server/timezone/ClockHelper.java
deleted file mode 100644
index 353728a15e7c..000000000000
--- a/services/core/java/com/android/server/timezone/ClockHelper.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.timezone;
-
-/**
- * An easy-to-mock interface for obtaining a monotonically increasing time value in milliseconds.
- */
-interface ClockHelper {
-
- long currentTimestamp();
-}
diff --git a/services/core/java/com/android/server/timezone/ConfigHelper.java b/services/core/java/com/android/server/timezone/ConfigHelper.java
deleted file mode 100644
index f9984fa1af5e..000000000000
--- a/services/core/java/com/android/server/timezone/ConfigHelper.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.timezone;
-
-/**
- * An easy-to-mock interface around device config for use by {@link PackageTracker}; it is not
- * possible to test various states with the real one because config is fixed in the system image.
- */
-interface ConfigHelper {
-
- boolean isTrackingEnabled();
-
- String getUpdateAppPackageName();
-
- String getDataAppPackageName();
-
- int getCheckTimeAllowedMillis();
-
- int getFailedCheckRetryCount();
-}
diff --git a/services/core/java/com/android/server/timezone/FileDescriptorHelper.java b/services/core/java/com/android/server/timezone/FileDescriptorHelper.java
deleted file mode 100644
index c3b1101000b5..000000000000
--- a/services/core/java/com/android/server/timezone/FileDescriptorHelper.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.timezone;
-
-import android.os.ParcelFileDescriptor;
-
-import java.io.IOException;
-
-/**
- * An easy-to-mock interface around use of {@link ParcelFileDescriptor} for use by
- * {@link RulesManagerService}.
- */
-interface FileDescriptorHelper {
-
- byte[] readFully(ParcelFileDescriptor parcelFileDescriptor) throws IOException;
-}
diff --git a/services/core/java/com/android/server/timezone/IntentHelper.java b/services/core/java/com/android/server/timezone/IntentHelper.java
deleted file mode 100644
index 0cb90657480e..000000000000
--- a/services/core/java/com/android/server/timezone/IntentHelper.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.timezone;
-
-/**
- * An easy-to-mock interface around intent sending / receiving for use by {@link PackageTracker};
- * it is not possible to test various cases with the real one because of the need to simulate
- * receiving and broadcasting intents.
- */
-interface IntentHelper {
-
- void initialize(String updateAppPackageName, String dataAppPackageName, Listener listener);
-
- void sendTriggerUpdateCheck(CheckToken checkToken);
-
- void enableReliabilityTriggering();
-
- void disableReliabilityTriggering();
-
- interface Listener {
- void triggerUpdateIfNeeded(boolean packageUpdated);
- }
-}
diff --git a/services/core/java/com/android/server/timezone/IntentHelperImpl.java b/services/core/java/com/android/server/timezone/IntentHelperImpl.java
deleted file mode 100644
index 3ffbb2d61fd5..000000000000
--- a/services/core/java/com/android/server/timezone/IntentHelperImpl.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.timezone;
-
-import android.app.timezone.RulesUpdaterContract;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.PatternMatcher;
-import android.util.Slog;
-
-import java.util.regex.Pattern;
-
-/**
- * The bona fide implementation of {@link IntentHelper}.
- */
-final class IntentHelperImpl implements IntentHelper {
-
- private final static String TAG = "timezone.IntentHelperImpl";
-
- private final Context mContext;
- private String mUpdaterAppPackageName;
-
- private boolean mReliabilityReceiverEnabled;
- private Receiver mReliabilityReceiver;
-
- IntentHelperImpl(Context context) {
- mContext = context;
- }
-
- @Override
- public void initialize(
- String updaterAppPackageName, String dataAppPackageName, Listener listener) {
- mUpdaterAppPackageName = updaterAppPackageName;
-
- // Register for events of interest.
-
- // The intent filter that triggers when package update events happen that indicate there may
- // be work to do.
- IntentFilter packageIntentFilter = new IntentFilter();
- // Either of these mean a downgrade?
- packageIntentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- packageIntentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
- packageIntentFilter.addDataScheme("package");
- packageIntentFilter.addDataSchemeSpecificPart(
- updaterAppPackageName, PatternMatcher.PATTERN_LITERAL);
- packageIntentFilter.addDataSchemeSpecificPart(
- dataAppPackageName, PatternMatcher.PATTERN_LITERAL);
- Receiver packageUpdateReceiver = new Receiver(listener, true /* packageUpdated */);
- mContext.registerReceiver(packageUpdateReceiver, packageIntentFilter);
-
- // TODO(nfuller): Add more exotic intents as needed. e.g.
- // packageIntentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- // Also, disabled...?
- mReliabilityReceiver = new Receiver(listener, false /* packageUpdated */);
- }
-
- /** Sends an intent to trigger an update check. */
- @Override
- public void sendTriggerUpdateCheck(CheckToken checkToken) {
- RulesUpdaterContract.sendBroadcast(
- mContext, mUpdaterAppPackageName, checkToken.toByteArray());
- }
-
- @Override
- public synchronized void enableReliabilityTriggering() {
- if (!mReliabilityReceiverEnabled) {
- // The intent filter that exists to make updates reliable in the event of failures /
- // reboots.
- IntentFilter reliabilityIntentFilter = new IntentFilter();
- reliabilityIntentFilter.addAction(Intent.ACTION_IDLE_MAINTENANCE_START);
- mContext.registerReceiver(mReliabilityReceiver, reliabilityIntentFilter);
- mReliabilityReceiverEnabled = true;
- }
- }
-
- @Override
- public synchronized void disableReliabilityTriggering() {
- if (mReliabilityReceiverEnabled) {
- mContext.unregisterReceiver(mReliabilityReceiver);
- mReliabilityReceiverEnabled = false;
- }
- }
-
- private static class Receiver extends BroadcastReceiver {
- private final Listener mListener;
- private final boolean mPackageUpdated;
-
- private Receiver(Listener listener, boolean packageUpdated) {
- mListener = listener;
- mPackageUpdated = packageUpdated;
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- Slog.d(TAG, "Received intent: " + intent.toString());
- mListener.triggerUpdateIfNeeded(mPackageUpdated);
- }
- }
-
-}
diff --git a/services/core/java/com/android/server/timezone/PackageManagerHelper.java b/services/core/java/com/android/server/timezone/PackageManagerHelper.java
deleted file mode 100644
index 804941add891..000000000000
--- a/services/core/java/com/android/server/timezone/PackageManagerHelper.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.timezone;
-
-import android.content.Intent;
-import android.content.pm.PackageManager;
-
-/**
- * An easy-to-mock facade around PackageManager for use by {@link PackageTracker}; it is not
- * possible to test various cases with the real one because of the need to simulate package versions
- * and manifest configurations.
- */
-interface PackageManagerHelper {
-
- int getInstalledPackageVersion(String packageName)
- throws PackageManager.NameNotFoundException;
-
- boolean isPrivilegedApp(String packageName) throws PackageManager.NameNotFoundException;
-
- boolean usesPermission(String packageName, String requiredPermissionName)
- throws PackageManager.NameNotFoundException;
-
- boolean contentProviderRegistered(String authority, String requiredPackageName);
-
- boolean receiverRegistered(Intent intent, String requiredPermissionName)
- throws PackageManager.NameNotFoundException;
-}
diff --git a/services/core/java/com/android/server/timezone/PackageStatus.java b/services/core/java/com/android/server/timezone/PackageStatus.java
deleted file mode 100644
index 637909615b1b..000000000000
--- a/services/core/java/com/android/server/timezone/PackageStatus.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.timezone;
-
-import android.annotation.IntDef;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Information about the status of the time zone update / data packages that are persisted by the
- * Android system.
- */
-final class PackageStatus {
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({ CHECK_STARTED, CHECK_COMPLETED_SUCCESS, CHECK_COMPLETED_FAILURE })
- @interface CheckStatus {}
-
- /** A time zone update check has been started but not yet completed. */
- static final int CHECK_STARTED = 1;
- /** A time zone update check has been completed and succeeded. */
- static final int CHECK_COMPLETED_SUCCESS = 2;
- /** A time zone update check has been completed and failed. */
- static final int CHECK_COMPLETED_FAILURE = 3;
-
- @CheckStatus
- final int mCheckStatus;
-
- // Non-null
- final PackageVersions mVersions;
-
- PackageStatus(@CheckStatus int checkStatus, PackageVersions versions) {
- this.mCheckStatus = checkStatus;
- if (checkStatus < 1 || checkStatus > 3) {
- throw new IllegalArgumentException("Unknown checkStatus " + checkStatus);
- }
- if (versions == null) {
- throw new NullPointerException("versions == null");
- }
- this.mVersions = versions;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- PackageStatus that = (PackageStatus) o;
-
- if (mCheckStatus != that.mCheckStatus) {
- return false;
- }
- return mVersions.equals(that.mVersions);
- }
-
- @Override
- public int hashCode() {
- int result = mCheckStatus;
- result = 31 * result + mVersions.hashCode();
- return result;
- }
-
- @Override
- public String toString() {
- return "PackageStatus{" +
- "mCheckStatus=" + mCheckStatus +
- ", mVersions=" + mVersions +
- '}';
- }
-}
diff --git a/services/core/java/com/android/server/timezone/PackageStatusStorage.java b/services/core/java/com/android/server/timezone/PackageStatusStorage.java
deleted file mode 100644
index 31f0e3145f8a..000000000000
--- a/services/core/java/com/android/server/timezone/PackageStatusStorage.java
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.timezone;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
-import android.util.Slog;
-
-import java.io.File;
-
-import static com.android.server.timezone.PackageStatus.CHECK_COMPLETED_FAILURE;
-import static com.android.server.timezone.PackageStatus.CHECK_COMPLETED_SUCCESS;
-import static com.android.server.timezone.PackageStatus.CHECK_STARTED;
-
-/**
- * Storage logic for accessing/mutating the Android system's persistent state related to time zone
- * update checking. There is expected to be a single instance and all methods synchronized on
- * {@code this} for thread safety.
- */
-final class PackageStatusStorage {
-
- private static final String TAG = "timezone.PackageStatusStorage";
-
- private static final String DATABASE_NAME = "timezonepackagestatus.db";
- private static final int DATABASE_VERSION = 1;
-
- /** The table name. It will have a single row with _id == {@link #SINGLETON_ID} */
- private static final String TABLE = "status";
- private static final String COLUMN_ID = "_id";
-
- /**
- * Column that stores a monotonically increasing lock ID, used to detect concurrent update
- * issues without on-line locks. Incremented on every write.
- */
- private static final String COLUMN_OPTIMISTIC_LOCK_ID = "optimistic_lock_id";
-
- /**
- * Column that stores the current "check status" of the time zone update application packages.
- */
- private static final String COLUMN_CHECK_STATUS = "check_status";
-
- /**
- * Column that stores the version of the time zone rules update application being checked / last
- * checked.
- */
- private static final String COLUMN_UPDATE_APP_VERSION = "update_app_package_version";
-
- /**
- * Column that stores the version of the time zone rules data application being checked / last
- * checked.
- */
- private static final String COLUMN_DATA_APP_VERSION = "data_app_package_version";
-
- /**
- * The ID of the one row.
- */
- private static final int SINGLETON_ID = 1;
-
- private static final int UNKNOWN_PACKAGE_VERSION = -1;
-
- private final DatabaseHelper mDatabaseHelper;
-
- PackageStatusStorage(Context context) {
- mDatabaseHelper = new DatabaseHelper(context);
- }
-
- void deleteDatabaseForTests() {
- SQLiteDatabase.deleteDatabase(mDatabaseHelper.getDatabaseFile());
- }
-
- /**
- * Obtain the current check status of the application packages. Returns {@code null} the first
- * time it is called, or after {@link #resetCheckState()}.
- */
- PackageStatus getPackageStatus() {
- synchronized (this) {
- try {
- return getPackageStatusInternal();
- } catch (IllegalArgumentException e) {
- // This means that data exists in the table but it was bad.
- Slog.e(TAG, "Package status invalid, resetting and retrying", e);
-
- // Reset the storage so it is in a good state again.
- mDatabaseHelper.recoverFromBadData();
- return getPackageStatusInternal();
- }
- }
- }
-
- private PackageStatus getPackageStatusInternal() {
- String[] columns = {
- COLUMN_CHECK_STATUS, COLUMN_UPDATE_APP_VERSION, COLUMN_DATA_APP_VERSION
- };
- Cursor cursor = mDatabaseHelper.getReadableDatabase()
- .query(TABLE, columns, COLUMN_ID + " = ?",
- new String[] { Integer.toString(SINGLETON_ID) },
- null /* groupBy */, null /* having */, null /* orderBy */);
- if (cursor.getCount() != 1) {
- Slog.e(TAG, "Unable to find package status from package status row. Rows returned: "
- + cursor.getCount());
- return null;
- }
- cursor.moveToFirst();
-
- // Determine check status.
- if (cursor.isNull(0)) {
- // This is normal the first time getPackageStatus() is called, or after
- // resetCheckState().
- return null;
- }
- int checkStatus = cursor.getInt(0);
-
- // Determine package version.
- if (cursor.isNull(1) || cursor.isNull(2)) {
- Slog.e(TAG, "Package version information unexpectedly null");
- return null;
- }
- PackageVersions packageVersions = new PackageVersions(cursor.getInt(1), cursor.getInt(2));
-
- return new PackageStatus(checkStatus, packageVersions);
- }
-
- /**
- * Generate a new {@link CheckToken} that can be passed to the time zone rules update
- * application.
- */
- CheckToken generateCheckToken(PackageVersions currentInstalledVersions) {
- if (currentInstalledVersions == null) {
- throw new NullPointerException("currentInstalledVersions == null");
- }
-
- synchronized (this) {
- Integer optimisticLockId = getCurrentOptimisticLockId();
- if (optimisticLockId == null) {
- Slog.w(TAG, "Unable to find optimistic lock ID from package status row");
-
- // Recover.
- optimisticLockId = mDatabaseHelper.recoverFromBadData();
- }
-
- int newOptimisticLockId = optimisticLockId + 1;
- boolean statusRowUpdated = writeStatusRow(
- optimisticLockId, newOptimisticLockId, CHECK_STARTED, currentInstalledVersions);
- if (!statusRowUpdated) {
- Slog.e(TAG, "Unable to update status to CHECK_STARTED in package status row."
- + " synchronization failure?");
- return null;
- }
- return new CheckToken(newOptimisticLockId, currentInstalledVersions);
- }
- }
-
- /**
- * Reset the current device state to "unknown".
- */
- void resetCheckState() {
- synchronized(this) {
- Integer optimisticLockId = getCurrentOptimisticLockId();
- if (optimisticLockId == null) {
- Slog.w(TAG, "resetCheckState: Unable to find optimistic lock ID from package"
- + " status row");
- // Attempt to recover the storage state.
- optimisticLockId = mDatabaseHelper.recoverFromBadData();
- }
-
- int newOptimisticLockId = optimisticLockId + 1;
- if (!writeStatusRow(optimisticLockId, newOptimisticLockId,
- null /* status */, null /* packageVersions */)) {
- Slog.e(TAG, "resetCheckState: Unable to reset package status row,"
- + " newOptimisticLockId=" + newOptimisticLockId);
- }
- }
- }
-
- /**
- * Update the current device state if possible. Returns true if the update was successful.
- * {@code false} indicates the storage has been changed since the {@link CheckToken} was
- * generated and the update was discarded.
- */
- boolean markChecked(CheckToken checkToken, boolean succeeded) {
- synchronized (this) {
- int optimisticLockId = checkToken.mOptimisticLockId;
- int newOptimisticLockId = optimisticLockId + 1;
- int status = succeeded ? CHECK_COMPLETED_SUCCESS : CHECK_COMPLETED_FAILURE;
- return writeStatusRow(optimisticLockId, newOptimisticLockId,
- status, checkToken.mPackageVersions);
- }
- }
-
- // Caller should be synchronized(this)
- private Integer getCurrentOptimisticLockId() {
- final String[] columns = { COLUMN_OPTIMISTIC_LOCK_ID };
- final String querySelection = COLUMN_ID + " = ?";
- final String[] querySelectionArgs = { Integer.toString(SINGLETON_ID) };
-
- SQLiteDatabase database = mDatabaseHelper.getReadableDatabase();
- try (Cursor cursor = database.query(TABLE, columns, querySelection, querySelectionArgs,
- null /* groupBy */, null /* having */, null /* orderBy */)) {
- if (cursor.getCount() != 1) {
- Slog.w(TAG, cursor.getCount() + " rows returned, expected exactly one.");
- return null;
- }
- cursor.moveToFirst();
- return cursor.getInt(0);
- }
- }
-
- // Caller should be synchronized(this)
- private boolean writeStatusRow(int optimisticLockId, int newOptimisticLockId, Integer status,
- PackageVersions packageVersions) {
- if ((status == null) != (packageVersions == null)) {
- throw new IllegalArgumentException(
- "Provide both status and packageVersions, or neither.");
- }
-
- SQLiteDatabase database = mDatabaseHelper.getWritableDatabase();
- ContentValues values = new ContentValues();
- values.put(COLUMN_OPTIMISTIC_LOCK_ID, newOptimisticLockId);
- if (status == null) {
- values.putNull(COLUMN_CHECK_STATUS);
- values.put(COLUMN_UPDATE_APP_VERSION, UNKNOWN_PACKAGE_VERSION);
- values.put(COLUMN_DATA_APP_VERSION, UNKNOWN_PACKAGE_VERSION);
- } else {
- values.put(COLUMN_CHECK_STATUS, status);
- values.put(COLUMN_UPDATE_APP_VERSION, packageVersions.mUpdateAppVersion);
- values.put(COLUMN_DATA_APP_VERSION, packageVersions.mDataAppVersion);
- }
-
- String updateSelection = COLUMN_ID + " = ? AND " + COLUMN_OPTIMISTIC_LOCK_ID + " = ?";
- String[] updateSelectionArgs = {
- Integer.toString(SINGLETON_ID), Integer.toString(optimisticLockId)
- };
- int count = database.update(TABLE, values, updateSelection, updateSelectionArgs);
- if (count > 1) {
- // This has to be because of corruption: there should only ever be one row.
- Slog.w(TAG, "writeStatusRow: " + count + " rows updated, expected exactly one.");
- // Reset the table.
- mDatabaseHelper.recoverFromBadData();
- }
-
- // 1 is the success case. 0 rows updated means the row is missing or the optimistic lock ID
- // was not as expected, this could be because of corruption but is most likely due to an
- // optimistic lock failure. Callers can decide on a case-by-case basis.
- return count == 1;
- }
-
- /** Only used during tests to force an empty table. */
- void deleteRowForTests() {
- mDatabaseHelper.getWritableDatabase().delete(TABLE, null, null);
- }
-
- /** Only used during tests to force a known table state. */
- public void forceCheckStateForTests(int checkStatus, PackageVersions packageVersions) {
- int optimisticLockId = getCurrentOptimisticLockId();
- writeStatusRow(optimisticLockId, optimisticLockId, checkStatus, packageVersions);
- }
-
- static class DatabaseHelper extends SQLiteOpenHelper {
-
- private final Context mContext;
-
- public DatabaseHelper(Context context) {
- super(context, DATABASE_NAME, null, DATABASE_VERSION);
- mContext = context;
- }
-
- @Override
- public void onCreate(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE " + TABLE + " (" +
- "_id INTEGER PRIMARY KEY," +
- COLUMN_OPTIMISTIC_LOCK_ID + " INTEGER NOT NULL," +
- COLUMN_CHECK_STATUS + " INTEGER," +
- COLUMN_UPDATE_APP_VERSION + " INTEGER NOT NULL," +
- COLUMN_DATA_APP_VERSION + " INTEGER NOT NULL" +
- ");");
- insertInitialRowState(db);
- }
-
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {
- // no-op: nothing to upgrade
- }
-
- /** Recover the initial data row state, returning the new current optimistic lock ID */
- int recoverFromBadData() {
- // Delete the table content.
- SQLiteDatabase writableDatabase = getWritableDatabase();
- writableDatabase.delete(TABLE, null /* whereClause */, null /* whereArgs */);
-
- // Insert the initial content.
- return insertInitialRowState(writableDatabase);
- }
-
- /** Insert the initial data row, returning the optimistic lock ID */
- private static int insertInitialRowState(SQLiteDatabase db) {
- // Doesn't matter what it is, but we avoid the obvious starting value each time the row
- // is reset to ensure that old tokens are unlikely to work.
- final int initialOptimisticLockId = (int) System.currentTimeMillis();
-
- // Insert the one row.
- ContentValues values = new ContentValues();
- values.put(COLUMN_ID, SINGLETON_ID);
- values.put(COLUMN_OPTIMISTIC_LOCK_ID, initialOptimisticLockId);
- values.putNull(COLUMN_CHECK_STATUS);
- values.put(COLUMN_UPDATE_APP_VERSION, UNKNOWN_PACKAGE_VERSION);
- values.put(COLUMN_DATA_APP_VERSION, UNKNOWN_PACKAGE_VERSION);
- long id = db.insert(TABLE, null, values);
- if (id == -1) {
- Slog.w(TAG, "insertInitialRow: could not insert initial row, id=" + id);
- return -1;
- }
- return initialOptimisticLockId;
- }
-
- File getDatabaseFile() {
- return mContext.getDatabasePath(DATABASE_NAME);
- }
- }
-}
diff --git a/services/core/java/com/android/server/timezone/PackageTracker.java b/services/core/java/com/android/server/timezone/PackageTracker.java
deleted file mode 100644
index 8abf7df9952b..000000000000
--- a/services/core/java/com/android/server/timezone/PackageTracker.java
+++ /dev/null
@@ -1,504 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.timezone;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import android.app.timezone.RulesUpdaterContract;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.provider.TimeZoneRulesDataContract;
-import android.util.Slog;
-
-/**
- * Monitors the installed applications associated with time zone updates. If the app packages are
- * updated it indicates there <em>might</em> be a time zone rules update to apply so a targeted
- * broadcast intent is used to trigger the time zone updater app.
- *
- * <p>The "update triggering" behavior of this component can be disabled via device configuration.
- *
- * <p>The package tracker listens for package updates of the time zone "updater app" and "data app".
- * It also listens for "reliability" triggers. Reliability triggers are there to ensure that the
- * package tracker handles failures reliably and are "idle maintenance" events or something similar.
- * Reliability triggers can cause a time zone update check to take place if the current state is
- * unclear. For example, it can be unclear after boot or after a failure. If there are repeated
- * failures reliability updates are halted until the next boot.
- *
- * <p>This component keeps persistent track of the most recent app packages checked to avoid
- * unnecessary expense from broadcasting intents (which will cause other app processes to spawn).
- * The current status is also stored to detect whether the most recently-generated check is
- * complete successfully. For example, if the device was interrupted while doing a check and never
- * acknowledged a check then a check will be retried the next time a "reliability trigger" event
- * happens.
- */
-// Also made non-final so it can be mocked.
-@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-public class PackageTracker implements IntentHelper.Listener {
- private static final String TAG = "timezone.PackageTracker";
-
- private final PackageManagerHelper mPackageManagerHelper;
- private final IntentHelper mIntentHelper;
- private final ConfigHelper mConfigHelper;
- private final PackageStatusStorage mPackageStatusStorage;
- private final ClockHelper mClockHelper;
-
- // False if tracking is disabled.
- private boolean mTrackingEnabled;
-
- // These fields may be null if package tracking is disabled.
- private String mUpdateAppPackageName;
- private String mDataAppPackageName;
-
- // The time a triggered check is allowed to take before it is considered overdue.
- private int mCheckTimeAllowedMillis;
- // The number of failed checks in a row before reliability checks should stop happening.
- private long mFailedCheckRetryCount;
-
- // Reliability check state: If a check was triggered but not acknowledged within
- // mCheckTimeAllowedMillis then another one can be triggered.
- private Long mLastTriggerTimestamp = null;
-
- // Reliability check state: Whether any checks have been triggered at all.
- private boolean mCheckTriggered;
-
- // Reliability check state: A count of how many failures have occurred consecutively.
- private int mCheckFailureCount;
-
- /** Creates the {@link PackageTracker} for normal use. */
- static PackageTracker create(Context context) {
- PackageTrackerHelperImpl helperImpl = new PackageTrackerHelperImpl(context);
- return new PackageTracker(
- helperImpl /* clock */,
- helperImpl /* configHelper */,
- helperImpl /* packageManagerHelper */,
- new PackageStatusStorage(context),
- new IntentHelperImpl(context));
- }
-
- // A constructor that can be used by tests to supply mocked / faked dependencies.
- PackageTracker(ClockHelper clockHelper, ConfigHelper configHelper,
- PackageManagerHelper packageManagerHelper, PackageStatusStorage packageStatusStorage,
- IntentHelper intentHelper) {
- mClockHelper = clockHelper;
- mConfigHelper = configHelper;
- mPackageManagerHelper = packageManagerHelper;
- mPackageStatusStorage = packageStatusStorage;
- mIntentHelper = intentHelper;
- }
-
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- protected synchronized void start() {
- mTrackingEnabled = mConfigHelper.isTrackingEnabled();
- if (!mTrackingEnabled) {
- Slog.i(TAG, "Time zone updater / data package tracking explicitly disabled.");
- return;
- }
-
- mUpdateAppPackageName = mConfigHelper.getUpdateAppPackageName();
- mDataAppPackageName = mConfigHelper.getDataAppPackageName();
- mCheckTimeAllowedMillis = mConfigHelper.getCheckTimeAllowedMillis();
- mFailedCheckRetryCount = mConfigHelper.getFailedCheckRetryCount();
-
- // Validate the device configuration including the application packages.
- // The manifest entries in the apps themselves are not validated until use as they can
- // change and we don't want to prevent the system server starting due to a bad application.
- throwIfDeviceSettingsOrAppsAreBad();
-
- // Explicitly start in a reliability state where reliability triggering will do something.
- mCheckTriggered = false;
- mCheckFailureCount = 0;
-
- // Initialize the intent helper.
- mIntentHelper.initialize(mUpdateAppPackageName, mDataAppPackageName, this);
-
- // Enable the reliability triggering so we will have at least one reliability trigger if
- // a package isn't updated.
- mIntentHelper.enableReliabilityTriggering();
-
- Slog.i(TAG, "Time zone updater / data package tracking enabled");
- }
-
- /**
- * Performs checks that confirm the system image has correctly configured package
- * tracking configuration. Only called if package tracking is enabled. Throws an exception if
- * the device is configured badly which will prevent the device booting.
- */
- private void throwIfDeviceSettingsOrAppsAreBad() {
- // None of the checks below can be based on application manifest settings, otherwise a bad
- // update could leave the device in an unbootable state. See validateDataAppManifest() and
- // validateUpdaterAppManifest() for softer errors.
-
- throwRuntimeExceptionIfNullOrEmpty(
- mUpdateAppPackageName, "Update app package name missing.");
- throwRuntimeExceptionIfNullOrEmpty(mDataAppPackageName, "Data app package name missing.");
- if (mFailedCheckRetryCount < 1) {
- throw logAndThrowRuntimeException("mFailedRetryCount=" + mFailedCheckRetryCount, null);
- }
- if (mCheckTimeAllowedMillis < 1000) {
- throw logAndThrowRuntimeException(
- "mCheckTimeAllowedMillis=" + mCheckTimeAllowedMillis, null);
- }
-
- // Validate the updater application package.
- // TODO(nfuller) Uncomment or remove the code below. Currently an app stops being a priv-app
- // after it is replaced by one in data so this check fails. http://b/35995024
- // try {
- // if (!mPackageManagerHelper.isPrivilegedApp(mUpdateAppPackageName)) {
- // throw failWithException(
- // "Update app " + mUpdateAppPackageName + " must be a priv-app.", null);
- // }
- // } catch (PackageManager.NameNotFoundException e) {
- // throw failWithException("Could not determine update app package details for "
- // + mUpdateAppPackageName, e);
- // }
- // TODO(nfuller) Consider permission checks. While an updated system app retains permissions
- // obtained by the system version it's not clear how to check them.
- Slog.d(TAG, "Update app " + mUpdateAppPackageName + " is valid.");
-
- // Validate the data application package.
- // TODO(nfuller) Uncomment or remove the code below. Currently an app stops being a priv-app
- // after it is replaced by one in data. http://b/35995024
- // try {
- // if (!mPackageManagerHelper.isPrivilegedApp(mDataAppPackageName)) {
- // throw failWithException(
- // "Data app " + mDataAppPackageName + " must be a priv-app.", null);
- // }
- // } catch (PackageManager.NameNotFoundException e) {
- // throw failWithException("Could not determine data app package details for "
- // + mDataAppPackageName, e);
- // }
- // TODO(nfuller) Consider permission checks. While an updated system app retains permissions
- // obtained by the system version it's not clear how to check them.
- Slog.d(TAG, "Data app " + mDataAppPackageName + " is valid.");
- }
-
- /**
- * Inspects the current in-memory state, installed packages and storage state to determine if an
- * update check is needed and then trigger if it is.
- *
- * @param packageChanged true if this method was called because a known packaged definitely
- * changed, false if the cause is a reliability trigger
- */
- @Override
- public synchronized void triggerUpdateIfNeeded(boolean packageChanged) {
- if (!mTrackingEnabled) {
- throw new IllegalStateException("Unexpected call. Tracking is disabled.");
- }
-
- // Validate the applications' current manifest entries: make sure they are configured as
- // they should be. These are not fatal and just means that no update is triggered: we don't
- // want to take down the system server if an OEM or Google have pushed a bad update to
- // an application.
- boolean updaterAppManifestValid = validateUpdaterAppManifest();
- boolean dataAppManifestValid = validateDataAppManifest();
- if (!updaterAppManifestValid || !dataAppManifestValid) {
- Slog.e(TAG, "No update triggered due to invalid application manifest entries."
- + " updaterApp=" + updaterAppManifestValid
- + ", dataApp=" + dataAppManifestValid);
-
- // There's no point in doing reliability checks if the current packages are bad.
- mIntentHelper.disableReliabilityTriggering();
- return;
- }
-
- if (!packageChanged) {
- // This call was made because the device is doing a "reliability" check.
- // 4 possible cases:
- // 1) No check has previously triggered since restart. We want to trigger in this case.
- // 2) A check has previously triggered and it is in progress. We want to trigger if
- // the response is overdue.
- // 3) A check has previously triggered and it failed. We want to trigger, but only if
- // we're not in a persistent failure state.
- // 4) A check has previously triggered and it succeeded.
- // We don't want to trigger, and want to stop future triggers.
-
- if (!mCheckTriggered) {
- // Case 1.
- Slog.d(TAG, "triggerUpdateIfNeeded: First reliability trigger.");
- } else if (isCheckInProgress()) {
- // Case 2.
- if (!isCheckResponseOverdue()) {
- // A check is in progress but hasn't been given time to succeed.
- Slog.d(TAG,
- "triggerUpdateIfNeeded: checkComplete call is not yet overdue."
- + " Not triggering.");
- // Not doing any work, but also not disabling future reliability triggers.
- return;
- }
- } else if (mCheckFailureCount > mFailedCheckRetryCount) {
- // Case 3. If the system is in some kind of persistent failure state we don't want
- // to keep checking, so just stop.
- Slog.i(TAG, "triggerUpdateIfNeeded: number of allowed consecutive check failures"
- + " exceeded. Stopping reliability triggers until next reboot or package"
- + " update.");
- mIntentHelper.disableReliabilityTriggering();
- return;
- } else if (mCheckFailureCount == 0) {
- // Case 4.
- Slog.i(TAG, "triggerUpdateIfNeeded: No reliability check required. Last check was"
- + " successful.");
- mIntentHelper.disableReliabilityTriggering();
- return;
- }
- }
-
- // Read the currently installed data / updater package versions.
- PackageVersions currentInstalledVersions = lookupInstalledPackageVersions();
- if (currentInstalledVersions == null) {
- // This should not happen if the device is configured in a valid way.
- Slog.e(TAG, "triggerUpdateIfNeeded: currentInstalledVersions was null");
- mIntentHelper.disableReliabilityTriggering();
- return;
- }
-
- // Establish the current state using package manager and stored state. Determine if we have
- // already successfully checked the installed versions.
- PackageStatus packageStatus = mPackageStatusStorage.getPackageStatus();
- if (packageStatus == null) {
- // This can imply corrupt, uninitialized storage state (e.g. first check ever on a
- // device) or after some kind of reset.
- Slog.i(TAG, "triggerUpdateIfNeeded: No package status data found. Data check needed.");
- } else if (!packageStatus.mVersions.equals(currentInstalledVersions)) {
- // The stored package version information differs from the installed version.
- // Trigger the check in all cases.
- Slog.i(TAG, "triggerUpdateIfNeeded: Stored package versions="
- + packageStatus.mVersions + ", do not match current package versions="
- + currentInstalledVersions + ". Triggering check.");
- } else {
- Slog.i(TAG, "triggerUpdateIfNeeded: Stored package versions match currently"
- + " installed versions, currentInstalledVersions=" + currentInstalledVersions
- + ", packageStatus.mCheckStatus=" + packageStatus.mCheckStatus);
- if (packageStatus.mCheckStatus == PackageStatus.CHECK_COMPLETED_SUCCESS) {
- // The last check succeeded and nothing has changed. Do nothing and disable
- // reliability checks.
- Slog.i(TAG, "triggerUpdateIfNeeded: Prior check succeeded. No need to trigger.");
- mIntentHelper.disableReliabilityTriggering();
- return;
- }
- }
-
- // Generate a token to send to the updater app.
- CheckToken checkToken =
- mPackageStatusStorage.generateCheckToken(currentInstalledVersions);
- if (checkToken == null) {
- Slog.w(TAG, "triggerUpdateIfNeeded: Unable to generate check token."
- + " Not sending check request.");
- return;
- }
-
- // Trigger the update check.
- mIntentHelper.sendTriggerUpdateCheck(checkToken);
- mCheckTriggered = true;
-
- // Update the reliability check state in case the update fails.
- setCheckInProgress();
-
- // Enable reliability triggering in case the check doesn't succeed and there is no
- // response at all. Enabling reliability triggering is idempotent.
- mIntentHelper.enableReliabilityTriggering();
- }
-
- /**
- * Used to record the result of a check. Can be called even if active package tracking is
- * disabled.
- */
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- protected synchronized void recordCheckResult(CheckToken checkToken, boolean success) {
- Slog.i(TAG, "recordOperationResult: checkToken=" + checkToken + " success=" + success);
-
- // If package tracking is disabled it means no record-keeping is required. However, we do
- // want to clear out any stored state to make it clear that the current state is unknown and
- // should tracking become enabled again (perhaps through an OTA) we'd need to perform an
- // update check.
- if (!mTrackingEnabled) {
- // This means an updater has spontaneously modified time zone data without having been
- // triggered. This can happen if the OEM is handling their own updates, but we don't
- // need to do any tracking in this case.
-
- if (checkToken == null) {
- // This is the expected case if tracking is disabled but an OEM is handling time
- // zone installs using their own mechanism.
- Slog.d(TAG, "recordCheckResult: Tracking is disabled and no token has been"
- + " provided. Resetting tracking state.");
- } else {
- // This is unexpected. If tracking is disabled then no check token should have been
- // generated by the package tracker. An updater should never create its own token.
- // This could be a bug in the updater.
- Slog.w(TAG, "recordCheckResult: Tracking is disabled and a token " + checkToken
- + " has been unexpectedly provided. Resetting tracking state.");
- }
- mPackageStatusStorage.resetCheckState();
- return;
- }
-
- if (checkToken == null) {
- /*
- * If the checkToken is null it suggests an install / uninstall / acknowledgement has
- * occurred without a prior trigger (or the client didn't return the token it was given
- * for some reason, perhaps a bug).
- *
- * This shouldn't happen under normal circumstances:
- *
- * If package tracking is enabled, we assume it is the package tracker responsible for
- * triggering updates and a token should have been produced and returned.
- *
- * If the OEM is handling time zone updates case package tracking should be disabled.
- *
- * This could happen in tests. The device should recover back to a known state by
- * itself rather than be left in an invalid state.
- *
- * We treat this as putting the device into an unknown state and make sure that
- * reliability triggering is enabled so we should recover.
- */
- Slog.i(TAG, "recordCheckResult: Unexpectedly missing checkToken, resetting"
- + " storage state.");
- mPackageStatusStorage.resetCheckState();
-
- // Enable reliability triggering and reset the failure count so we know that the
- // next reliability trigger will do something.
- mIntentHelper.enableReliabilityTriggering();
- mCheckFailureCount = 0;
- } else {
- // This is the expected case when tracking is enabled: a check was triggered and it has
- // completed.
- boolean recordedCheckCompleteSuccessfully =
- mPackageStatusStorage.markChecked(checkToken, success);
- if (recordedCheckCompleteSuccessfully) {
- // If we have recorded the result (whatever it was) we know there is no check in
- // progress.
- setCheckComplete();
-
- if (success) {
- // Since the check was successful, no more reliability checks are required until
- // there is a package change.
- mIntentHelper.disableReliabilityTriggering();
- mCheckFailureCount = 0;
- } else {
- // Enable reliability triggering to potentially check again in future.
- mIntentHelper.enableReliabilityTriggering();
- mCheckFailureCount++;
- }
- } else {
- // The failure to record the check means an optimistic lock failure and suggests
- // that another check was triggered after the token was generated.
- Slog.i(TAG, "recordCheckResult: could not update token=" + checkToken
- + " with success=" + success + ". Optimistic lock failure");
-
- // Enable reliability triggering to potentially try again in future.
- mIntentHelper.enableReliabilityTriggering();
- mCheckFailureCount++;
- }
- }
- }
-
- /** Access to consecutive failure counts for use in tests. */
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- protected int getCheckFailureCountForTests() {
- return mCheckFailureCount;
- }
-
- private void setCheckInProgress() {
- mLastTriggerTimestamp = mClockHelper.currentTimestamp();
- }
-
- private void setCheckComplete() {
- mLastTriggerTimestamp = null;
- }
-
- private boolean isCheckInProgress() {
- return mLastTriggerTimestamp != null;
- }
-
- private boolean isCheckResponseOverdue() {
- if (mLastTriggerTimestamp == null) {
- return false;
- }
- // Risk of overflow, but highly unlikely given the implementation and not problematic.
- return mClockHelper.currentTimestamp() > mLastTriggerTimestamp + mCheckTimeAllowedMillis;
- }
-
- private PackageVersions lookupInstalledPackageVersions() {
- int updatePackageVersion;
- int dataPackageVersion;
- try {
- updatePackageVersion =
- mPackageManagerHelper.getInstalledPackageVersion(mUpdateAppPackageName);
- dataPackageVersion =
- mPackageManagerHelper.getInstalledPackageVersion(mDataAppPackageName);
- } catch (PackageManager.NameNotFoundException e) {
- Slog.w(TAG, "lookupInstalledPackageVersions: Unable to resolve installed package"
- + " versions", e);
- return null;
- }
- return new PackageVersions(updatePackageVersion, dataPackageVersion);
- }
-
- private boolean validateDataAppManifest() {
- // We only want to talk to a provider that exposed by the known data app package
- // so we look up the providers exposed by that app and check the well-known authority is
- // there. This prevents the case where *even if* the data app doesn't expose the provider
- // required, another app cannot expose one to replace it.
- if (!mPackageManagerHelper.contentProviderRegistered(
- TimeZoneRulesDataContract.AUTHORITY, mDataAppPackageName)) {
- // Error! Found the package but it didn't expose the correct provider.
- Slog.w(TAG, "validateDataAppManifest: Data app " + mDataAppPackageName
- + " does not expose the required provider with authority="
- + TimeZoneRulesDataContract.AUTHORITY);
- return false;
- }
- // TODO(nfuller) Add any permissions checks needed.
- return true;
- }
-
- private boolean validateUpdaterAppManifest() {
- try {
- // The updater app is expected to have the UPDATE_TIME_ZONE_RULES permission.
- // The updater app is expected to have a receiver for the intent we are going to trigger
- // and require the TRIGGER_TIME_ZONE_RULES_CHECK.
- if (!mPackageManagerHelper.usesPermission(
- mUpdateAppPackageName,
- RulesUpdaterContract.UPDATE_TIME_ZONE_RULES_PERMISSION)) {
- Slog.w(TAG, "validateUpdaterAppManifest: Updater app " + mDataAppPackageName
- + " does not use permission="
- + RulesUpdaterContract.UPDATE_TIME_ZONE_RULES_PERMISSION);
- return false;
- }
- if (!mPackageManagerHelper.receiverRegistered(
- RulesUpdaterContract.createUpdaterIntent(mUpdateAppPackageName),
- RulesUpdaterContract.TRIGGER_TIME_ZONE_RULES_CHECK_PERMISSION)) {
- return false;
- }
-
- return true;
- } catch (PackageManager.NameNotFoundException e) {
- Slog.w(TAG, "validateUpdaterAppManifest: Updater app " + mDataAppPackageName
- + " does not expose the required broadcast receiver.", e);
- return false;
- }
- }
-
- private static void throwRuntimeExceptionIfNullOrEmpty(String value, String message) {
- if (value == null || value.trim().isEmpty()) {
- throw logAndThrowRuntimeException(message, null);
- }
- }
-
- private static RuntimeException logAndThrowRuntimeException(String message, Throwable cause) {
- Slog.wtf(TAG, message, cause);
- throw new RuntimeException(message, cause);
- }
-}
diff --git a/services/core/java/com/android/server/timezone/PackageTrackerHelperImpl.java b/services/core/java/com/android/server/timezone/PackageTrackerHelperImpl.java
deleted file mode 100644
index 2e0c21bf007d..000000000000
--- a/services/core/java/com/android/server/timezone/PackageTrackerHelperImpl.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.timezone;
-
-import com.android.internal.R;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ProviderInfo;
-import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
-import android.os.SystemClock;
-import android.util.Slog;
-
-import java.util.List;
-
-/**
- * A single class that implements multiple helper interfaces for use by {@link PackageTracker}.
- */
-final class PackageTrackerHelperImpl implements ClockHelper, ConfigHelper, PackageManagerHelper {
-
- private static final String TAG = "PackageTrackerHelperImpl";
-
- private final Context mContext;
- private final PackageManager mPackageManager;
-
- PackageTrackerHelperImpl(Context context) {
- mContext = context;
- mPackageManager = context.getPackageManager();
- }
-
- @Override
- public boolean isTrackingEnabled() {
- return mContext.getResources().getBoolean(R.bool.config_timeZoneRulesUpdateTrackingEnabled);
- }
-
- @Override
- public String getUpdateAppPackageName() {
- return mContext.getResources().getString(R.string.config_timeZoneRulesUpdaterPackage);
- }
-
- @Override
- public String getDataAppPackageName() {
- Resources resources = mContext.getResources();
- return resources.getString(R.string.config_timeZoneRulesDataPackage);
- }
-
- @Override
- public int getCheckTimeAllowedMillis() {
- return mContext.getResources().getInteger(
- R.integer.config_timeZoneRulesCheckTimeMillisAllowed);
- }
-
- @Override
- public int getFailedCheckRetryCount() {
- return mContext.getResources().getInteger(R.integer.config_timeZoneRulesCheckRetryCount);
- }
-
- @Override
- public long currentTimestamp() {
- // Use of elapsedRealtime() because this is in-memory state and elapsedRealtime() shouldn't
- // change if the system clock changes.
- return SystemClock.elapsedRealtime();
- }
-
- @Override
- public int getInstalledPackageVersion(String packageName)
- throws PackageManager.NameNotFoundException {
- int flags = PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
- PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, flags);
- return packageInfo.versionCode;
- }
-
- @Override
- public boolean isPrivilegedApp(String packageName) throws PackageManager.NameNotFoundException {
- int flags = PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
- PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, flags);
- return packageInfo.applicationInfo.isPrivilegedApp();
- }
-
- @Override
- public boolean usesPermission(String packageName, String requiredPermissionName)
- throws PackageManager.NameNotFoundException {
- int flags = PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
- | PackageManager.GET_PERMISSIONS;
- PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, flags);
- if (packageInfo.requestedPermissions == null) {
- return false;
- }
- for (String requestedPermission : packageInfo.requestedPermissions) {
- if (requiredPermissionName.equals(requestedPermission)) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public boolean contentProviderRegistered(String authority, String requiredPackageName) {
- int flags = PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
- ProviderInfo providerInfo =
- mPackageManager.resolveContentProvider(authority, flags);
- if (providerInfo == null) {
- Slog.i(TAG, "contentProviderRegistered: No content provider registered with authority="
- + authority);
- return false;
- }
- boolean packageMatches =
- requiredPackageName.equals(providerInfo.applicationInfo.packageName);
- if (!packageMatches) {
- Slog.i(TAG, "contentProviderRegistered: App with packageName=" + requiredPackageName
- + " does not expose the a content provider with authority=" + authority);
- return false;
- }
- return true;
- }
-
- @Override
- public boolean receiverRegistered(Intent intent, String requiredPermissionName)
- throws PackageManager.NameNotFoundException {
-
- int flags = PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
- List<ResolveInfo> resolveInfo = mPackageManager.queryBroadcastReceivers(intent, flags);
- if (resolveInfo.size() != 1) {
- Slog.i(TAG, "receiverRegistered: Zero or multiple broadcast receiver registered for"
- + " intent=" + intent + ", found=" + resolveInfo);
- return false;
- }
-
- ResolveInfo matched = resolveInfo.get(0);
- boolean requiresPermission = requiredPermissionName.equals(matched.activityInfo.permission);
- if (!requiresPermission) {
- Slog.i(TAG, "receiverRegistered: Broadcast receiver registered for intent="
- + intent + " must require permission " + requiredPermissionName);
- }
- return requiresPermission;
- }
-}
diff --git a/services/core/java/com/android/server/timezone/PackageVersions.java b/services/core/java/com/android/server/timezone/PackageVersions.java
deleted file mode 100644
index fc0d6e1ad51e..000000000000
--- a/services/core/java/com/android/server/timezone/PackageVersions.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.timezone;
-
-/**
- * Package version information about the time zone updater and time zone data application packages.
- */
-final class PackageVersions {
-
- final int mUpdateAppVersion;
- final int mDataAppVersion;
-
- PackageVersions(int updateAppVersion, int dataAppVersion) {
- this.mUpdateAppVersion = updateAppVersion;
- this.mDataAppVersion = dataAppVersion;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- PackageVersions that = (PackageVersions) o;
-
- if (mUpdateAppVersion != that.mUpdateAppVersion) {
- return false;
- }
- return mDataAppVersion == that.mDataAppVersion;
- }
-
- @Override
- public int hashCode() {
- int result = mUpdateAppVersion;
- result = 31 * result + mDataAppVersion;
- return result;
- }
-
- @Override
- public String toString() {
- return "PackageVersions{" +
- "mUpdateAppVersion=" + mUpdateAppVersion +
- ", mDataAppVersion=" + mDataAppVersion +
- '}';
- }
-}
diff --git a/services/core/java/com/android/server/timezone/PermissionHelper.java b/services/core/java/com/android/server/timezone/PermissionHelper.java
deleted file mode 100644
index ba91c7f7b7ab..000000000000
--- a/services/core/java/com/android/server/timezone/PermissionHelper.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.timezone;
-
-/**
- * An easy-to-mock interface around permission checks for use by {@link RulesManagerService}.
- */
-public interface PermissionHelper {
-
- void enforceCallerHasPermission(String requiredPermission) throws SecurityException;
-}
diff --git a/services/core/java/com/android/server/timezone/RulesManagerService.java b/services/core/java/com/android/server/timezone/RulesManagerService.java
deleted file mode 100644
index 82bd35679b04..000000000000
--- a/services/core/java/com/android/server/timezone/RulesManagerService.java
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.timezone;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.SystemService;
-
-import android.app.timezone.Callback;
-import android.app.timezone.DistroFormatVersion;
-import android.app.timezone.DistroRulesVersion;
-import android.app.timezone.ICallback;
-import android.app.timezone.IRulesManager;
-import android.app.timezone.RulesManager;
-import android.app.timezone.RulesState;
-import android.content.Context;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-import android.util.Slog;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.concurrent.Executor;
-import java.util.concurrent.atomic.AtomicBoolean;
-import libcore.tzdata.shared2.DistroException;
-import libcore.tzdata.shared2.DistroVersion;
-import libcore.tzdata.shared2.StagedDistroOperation;
-import libcore.tzdata.update2.TimeZoneDistroInstaller;
-
-// TODO(nfuller) Add EventLog calls where useful in the system server.
-// TODO(nfuller) Check logging best practices in the system server.
-// TODO(nfuller) Check error handling best practices in the system server.
-public final class RulesManagerService extends IRulesManager.Stub {
-
- private static final String TAG = "timezone.RulesManagerService";
-
- /** The distro format supported by this device. */
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
- static final DistroFormatVersion DISTRO_FORMAT_VERSION_SUPPORTED =
- new DistroFormatVersion(
- DistroVersion.CURRENT_FORMAT_MAJOR_VERSION,
- DistroVersion.CURRENT_FORMAT_MINOR_VERSION);
-
- public static class Lifecycle extends SystemService {
- private RulesManagerService mService;
-
- public Lifecycle(Context context) {
- super(context);
- }
-
- @Override
- public void onStart() {
- mService = RulesManagerService.create(getContext());
- mService.start();
-
- publishBinderService(Context.TIME_ZONE_RULES_MANAGER_SERVICE, mService);
- }
- }
-
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
- static final String REQUIRED_UPDATER_PERMISSION =
- android.Manifest.permission.UPDATE_TIME_ZONE_RULES;
- private static final File SYSTEM_TZ_DATA_FILE = new File("/system/usr/share/zoneinfo/tzdata");
- private static final File TZ_DATA_DIR = new File("/data/misc/zoneinfo");
-
- private final AtomicBoolean mOperationInProgress = new AtomicBoolean(false);
- private final PermissionHelper mPermissionHelper;
- private final PackageTracker mPackageTracker;
- private final Executor mExecutor;
- private final TimeZoneDistroInstaller mInstaller;
- private final FileDescriptorHelper mFileDescriptorHelper;
-
- private static RulesManagerService create(Context context) {
- RulesManagerServiceHelperImpl helper = new RulesManagerServiceHelperImpl(context);
- return new RulesManagerService(
- helper /* permissionHelper */,
- helper /* executor */,
- helper /* fileDescriptorHelper */,
- PackageTracker.create(context),
- new TimeZoneDistroInstaller(TAG, SYSTEM_TZ_DATA_FILE, TZ_DATA_DIR));
- }
-
- // A constructor that can be used by tests to supply mocked / faked dependencies.
- RulesManagerService(PermissionHelper permissionHelper,
- Executor executor,
- FileDescriptorHelper fileDescriptorHelper, PackageTracker packageTracker,
- TimeZoneDistroInstaller timeZoneDistroInstaller) {
- mPermissionHelper = permissionHelper;
- mExecutor = executor;
- mFileDescriptorHelper = fileDescriptorHelper;
- mPackageTracker = packageTracker;
- mInstaller = timeZoneDistroInstaller;
- }
-
- public void start() {
- mPackageTracker.start();
- }
-
- @Override // Binder call
- public RulesState getRulesState() {
- mPermissionHelper.enforceCallerHasPermission(REQUIRED_UPDATER_PERMISSION);
-
- synchronized(this) {
- String systemRulesVersion;
- try {
- systemRulesVersion = mInstaller.getSystemRulesVersion();
- } catch (IOException e) {
- Slog.w(TAG, "Failed to read system rules", e);
- return null;
- }
-
- boolean operationInProgress = this.mOperationInProgress.get();
-
- // Determine the staged operation status, if possible.
- DistroRulesVersion stagedDistroRulesVersion = null;
- int stagedOperationStatus = RulesState.STAGED_OPERATION_UNKNOWN;
- if (!operationInProgress) {
- StagedDistroOperation stagedDistroOperation;
- try {
- stagedDistroOperation = mInstaller.getStagedDistroOperation();
- if (stagedDistroOperation == null) {
- stagedOperationStatus = RulesState.STAGED_OPERATION_NONE;
- } else if (stagedDistroOperation.isUninstall) {
- stagedOperationStatus = RulesState.STAGED_OPERATION_UNINSTALL;
- } else {
- // Must be an install.
- stagedOperationStatus = RulesState.STAGED_OPERATION_INSTALL;
- DistroVersion stagedDistroVersion = stagedDistroOperation.distroVersion;
- stagedDistroRulesVersion = new DistroRulesVersion(
- stagedDistroVersion.rulesVersion,
- stagedDistroVersion.revision);
- }
- } catch (DistroException | IOException e) {
- Slog.w(TAG, "Failed to read staged distro.", e);
- }
- }
-
- // Determine the installed distro state, if possible.
- DistroVersion installedDistroVersion;
- int distroStatus = RulesState.DISTRO_STATUS_UNKNOWN;
- DistroRulesVersion installedDistroRulesVersion = null;
- if (!operationInProgress) {
- try {
- installedDistroVersion = mInstaller.getInstalledDistroVersion();
- if (installedDistroVersion == null) {
- distroStatus = RulesState.DISTRO_STATUS_NONE;
- installedDistroRulesVersion = null;
- } else {
- distroStatus = RulesState.DISTRO_STATUS_INSTALLED;
- installedDistroRulesVersion = new DistroRulesVersion(
- installedDistroVersion.rulesVersion,
- installedDistroVersion.revision);
- }
- } catch (DistroException | IOException e) {
- Slog.w(TAG, "Failed to read installed distro.", e);
- }
- }
- return new RulesState(systemRulesVersion, DISTRO_FORMAT_VERSION_SUPPORTED,
- operationInProgress, stagedOperationStatus, stagedDistroRulesVersion,
- distroStatus, installedDistroRulesVersion);
- }
- }
-
- @Override
- public int requestInstall(
- ParcelFileDescriptor timeZoneDistro, byte[] checkTokenBytes, ICallback callback) {
- mPermissionHelper.enforceCallerHasPermission(REQUIRED_UPDATER_PERMISSION);
-
- CheckToken checkToken = null;
- if (checkTokenBytes != null) {
- checkToken = createCheckTokenOrThrow(checkTokenBytes);
- }
- synchronized (this) {
- if (timeZoneDistro == null) {
- throw new NullPointerException("timeZoneDistro == null");
- }
- if (callback == null) {
- throw new NullPointerException("observer == null");
- }
- if (mOperationInProgress.get()) {
- return RulesManager.ERROR_OPERATION_IN_PROGRESS;
- }
- mOperationInProgress.set(true);
-
- // Execute the install asynchronously.
- mExecutor.execute(new InstallRunnable(timeZoneDistro, checkToken, callback));
-
- return RulesManager.SUCCESS;
- }
- }
-
- private class InstallRunnable implements Runnable {
-
- private final ParcelFileDescriptor mTimeZoneDistro;
- private final CheckToken mCheckToken;
- private final ICallback mCallback;
-
- InstallRunnable(
- ParcelFileDescriptor timeZoneDistro, CheckToken checkToken, ICallback callback) {
- mTimeZoneDistro = timeZoneDistro;
- mCheckToken = checkToken;
- mCallback = callback;
- }
-
- @Override
- public void run() {
- // Adopt the ParcelFileDescriptor into this try-with-resources so it is closed
- // when we are done.
- boolean success = false;
- try {
- byte[] distroBytes =
- RulesManagerService.this.mFileDescriptorHelper.readFully(mTimeZoneDistro);
- int installerResult = mInstaller.stageInstallWithErrorCode(distroBytes);
- int resultCode = mapInstallerResultToApiCode(installerResult);
- sendFinishedStatus(mCallback, resultCode);
-
- // All the installer failure modes are currently non-recoverable and won't be
- // improved by trying again. Therefore success = true.
- success = true;
- } catch (Exception e) {
- Slog.w(TAG, "Failed to install distro.", e);
- sendFinishedStatus(mCallback, Callback.ERROR_UNKNOWN_FAILURE);
- } finally {
- // Notify the package tracker that the operation is now complete.
- mPackageTracker.recordCheckResult(mCheckToken, success);
-
- mOperationInProgress.set(false);
- }
- }
-
- private int mapInstallerResultToApiCode(int installerResult) {
- switch (installerResult) {
- case TimeZoneDistroInstaller.INSTALL_SUCCESS:
- return Callback.SUCCESS;
- case TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE:
- return Callback.ERROR_INSTALL_BAD_DISTRO_STRUCTURE;
- case TimeZoneDistroInstaller.INSTALL_FAIL_RULES_TOO_OLD:
- return Callback.ERROR_INSTALL_RULES_TOO_OLD;
- case TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_FORMAT_VERSION:
- return Callback.ERROR_INSTALL_BAD_DISTRO_FORMAT_VERSION;
- case TimeZoneDistroInstaller.INSTALL_FAIL_VALIDATION_ERROR:
- return Callback.ERROR_INSTALL_VALIDATION_ERROR;
- default:
- return Callback.ERROR_UNKNOWN_FAILURE;
- }
- }
- }
-
- @Override
- public int requestUninstall(byte[] checkTokenBytes, ICallback callback) {
- mPermissionHelper.enforceCallerHasPermission(REQUIRED_UPDATER_PERMISSION);
-
- CheckToken checkToken = null;
- if (checkTokenBytes != null) {
- checkToken = createCheckTokenOrThrow(checkTokenBytes);
- }
- synchronized(this) {
- if (callback == null) {
- throw new NullPointerException("callback == null");
- }
-
- if (mOperationInProgress.get()) {
- return RulesManager.ERROR_OPERATION_IN_PROGRESS;
- }
- mOperationInProgress.set(true);
-
- // Execute the uninstall asynchronously.
- mExecutor.execute(new UninstallRunnable(checkToken, callback));
-
- return RulesManager.SUCCESS;
- }
- }
-
- private class UninstallRunnable implements Runnable {
-
- private final CheckToken mCheckToken;
- private final ICallback mCallback;
-
- public UninstallRunnable(CheckToken checkToken, ICallback callback) {
- mCheckToken = checkToken;
- mCallback = callback;
- }
-
- @Override
- public void run() {
- boolean success = false;
- try {
- success = mInstaller.stageUninstall();
- // Right now we just have success (0) / failure (1). All clients should be checking
- // against SUCCESS. More granular failures may be added in future.
- int resultCode = success ? Callback.SUCCESS
- : Callback.ERROR_UNKNOWN_FAILURE;
- sendFinishedStatus(mCallback, resultCode);
- } catch (Exception e) {
- Slog.w(TAG, "Failed to uninstall distro.", e);
- sendFinishedStatus(mCallback, Callback.ERROR_UNKNOWN_FAILURE);
- } finally {
- // Notify the package tracker that the operation is now complete.
- mPackageTracker.recordCheckResult(mCheckToken, success);
-
- mOperationInProgress.set(false);
- }
- }
- }
-
- private void sendFinishedStatus(ICallback callback, int resultCode) {
- try {
- callback.onFinished(resultCode);
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to notify observer of result", e);
- }
- }
-
- @Override
- public void requestNothing(byte[] checkTokenBytes, boolean success) {
- mPermissionHelper.enforceCallerHasPermission(REQUIRED_UPDATER_PERMISSION);
- CheckToken checkToken = null;
- if (checkTokenBytes != null) {
- checkToken = createCheckTokenOrThrow(checkTokenBytes);
- }
- mPackageTracker.recordCheckResult(checkToken, success);
- }
-
- private static CheckToken createCheckTokenOrThrow(byte[] checkTokenBytes) {
- CheckToken checkToken;
- try {
- checkToken = CheckToken.fromByteArray(checkTokenBytes);
- } catch (IOException e) {
- throw new IllegalArgumentException("Unable to read token bytes "
- + Arrays.toString(checkTokenBytes), e);
- }
- return checkToken;
- }
-}
diff --git a/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java b/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java
deleted file mode 100644
index 15a571d6750c..000000000000
--- a/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.timezone;
-
-import android.content.Context;
-import android.os.ParcelFileDescriptor;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.concurrent.Executor;
-import libcore.io.Streams;
-
-/**
- * A single class that implements multiple helper interfaces for use by {@link RulesManagerService}.
- */
-final class RulesManagerServiceHelperImpl
- implements PermissionHelper, Executor, FileDescriptorHelper {
-
- private final Context mContext;
-
- RulesManagerServiceHelperImpl(Context context) {
- mContext = context;
- }
-
- @Override
- public void enforceCallerHasPermission(String requiredPermission) {
- mContext.enforceCallingPermission(requiredPermission, null /* message */);
- }
-
- // TODO Wake lock required?
- @Override
- public void execute(Runnable runnable) {
- // TODO Is there a better way?
- new Thread(runnable).start();
- }
-
- @Override
- public byte[] readFully(ParcelFileDescriptor parcelFileDescriptor) throws IOException {
- try (ParcelFileDescriptor pfd = parcelFileDescriptor) {
- // Read bytes
- FileInputStream in = new FileInputStream(pfd.getFileDescriptor(), false /* isOwner */);
- return Streams.readFully(in);
- }
- }
-}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 35062c17169c..4cdd7fe22228 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -200,8 +200,6 @@ public final class SystemServer {
"com.android.server.wallpaper.WallpaperManagerService$Lifecycle";
private static final String AUTO_FILL_MANAGER_SERVICE_CLASS =
"com.android.server.autofill.AutofillManagerService";
- private static final String TIME_ZONE_RULES_MANAGER_SERVICE_CLASS =
- "com.android.server.timezone.RulesManagerService$Lifecycle";
private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
@@ -1213,13 +1211,6 @@ public final class SystemServer {
traceEnd();
}
- if (!disableNonCoreServices && context.getResources().getBoolean(
- R.bool.config_enableUpdateableTimeZoneRules)) {
- traceBeginAndSlog("StartTimeZoneRulesManagerService");
- mSystemServiceManager.startService(TIME_ZONE_RULES_MANAGER_SERVICE_CLASS);
- Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
- }
-
traceBeginAndSlog("StartAudioService");
mSystemServiceManager.startService(AudioService.Lifecycle.class);
traceEnd();
diff --git a/services/tests/servicestests/src/com/android/server/timezone/CheckTokenTest.java b/services/tests/servicestests/src/com/android/server/timezone/CheckTokenTest.java
deleted file mode 100644
index 9603a06aaa66..000000000000
--- a/services/tests/servicestests/src/com/android/server/timezone/CheckTokenTest.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.timezone;
-
-import org.junit.Test;
-
-import android.support.test.filters.SmallTest;
-
-import java.io.IOException;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.fail;
-
-@SmallTest
-public class CheckTokenTest {
-
- @Test
- public void toByteArray() throws Exception {
- PackageVersions packageVersions =
- new PackageVersions(1 /* updateAppVersion */, 1 /* dataAppVersion */);
- CheckToken originalToken = new CheckToken(1 /* optimisticLockId */, packageVersions);
- assertEquals(originalToken, CheckToken.fromByteArray(originalToken.toByteArray()));
- }
-
- @Test
- public void fromByteArray() {
- PackageVersions packageVersions =
- new PackageVersions(1 /* updateAppVersion */, 1 /* dataAppVersion */);
- CheckToken token = new CheckToken(1, packageVersions);
- byte[] validTokenBytes = token.toByteArray();
- byte[] shortTokenBytes = new byte[validTokenBytes.length - 1];
- System.arraycopy(validTokenBytes, 0, shortTokenBytes, 0, shortTokenBytes.length);
-
- try {
- CheckToken.fromByteArray(shortTokenBytes);
- fail();
- } catch (IOException expected) {}
- }
-
- @Test
- public void equals() {
- PackageVersions packageVersions1 =
- new PackageVersions(1 /* updateAppVersion */, 1 /* dataAppVersion */);
- PackageVersions packageVersions2 =
- new PackageVersions(2 /* updateAppVersion */, 2 /* dataAppVersion */);
- assertFalse(packageVersions1.equals(packageVersions2));
-
- CheckToken baseline = new CheckToken(1, packageVersions1);
- assertEquals(baseline, baseline);
-
- CheckToken deepEqual = new CheckToken(1, packageVersions1);
- assertEquals(baseline, deepEqual);
-
- CheckToken differentOptimisticLockId = new CheckToken(2, packageVersions1);
- assertFalse(differentOptimisticLockId.equals(baseline));
-
- CheckToken differentPackageVersions = new CheckToken(1, packageVersions2);
- assertFalse(differentPackageVersions.equals(baseline));
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/timezone/PackageStatusStorageTest.java b/services/tests/servicestests/src/com/android/server/timezone/PackageStatusStorageTest.java
deleted file mode 100644
index e085270fc3a4..000000000000
--- a/services/tests/servicestests/src/com/android/server/timezone/PackageStatusStorageTest.java
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.timezone;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import android.content.Context;
-import android.database.sqlite.SQLiteDatabase;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-
-import static junit.framework.Assert.assertTrue;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-
-@SmallTest
-public class PackageStatusStorageTest {
- private static final PackageVersions VALID_PACKAGE_VERSIONS = new PackageVersions(1, 2);
-
- private PackageStatusStorage mPackageStatusStorage;
-
- @Before
- public void setUp() throws Exception {
- Context context = InstrumentationRegistry.getContext();
-
- // Using the instrumentation context means the database is created in a test app-specific
- // directory.
- mPackageStatusStorage = new PackageStatusStorage(context);
- }
-
- @After
- public void tearDown() throws Exception {
- mPackageStatusStorage.deleteDatabaseForTests();
- }
-
- @Test
- public void getPackageStatus_initialState() {
- assertNull(mPackageStatusStorage.getPackageStatus());
- }
-
- @Test
- public void resetCheckState() {
- // Assert initial state.
- assertNull(mPackageStatusStorage.getPackageStatus());
-
- CheckToken token1 = mPackageStatusStorage.generateCheckToken(VALID_PACKAGE_VERSIONS);
-
- // There should now be a state.
- assertNotNull(mPackageStatusStorage.getPackageStatus());
-
- // Now clear the state.
- mPackageStatusStorage.resetCheckState();
-
- // After reset, there should be no package state again.
- assertNull(mPackageStatusStorage.getPackageStatus());
-
- CheckToken token2 = mPackageStatusStorage.generateCheckToken(VALID_PACKAGE_VERSIONS);
-
- // Token after a reset should still be distinct.
- assertFalse(token1.equals(token2));
-
- // Now clear the state again.
- mPackageStatusStorage.resetCheckState();
-
- // After reset, there should be no package state again.
- assertNull(mPackageStatusStorage.getPackageStatus());
-
- CheckToken token3 = mPackageStatusStorage.generateCheckToken(VALID_PACKAGE_VERSIONS);
-
- // A CheckToken generated after a reset should still be distinct.
- assertFalse(token2.equals(token3));
- }
-
- @Test
- public void generateCheckToken_missingRowBehavior() {
- // Assert initial state.
- assertNull(mPackageStatusStorage.getPackageStatus());
-
- CheckToken token1 = mPackageStatusStorage.generateCheckToken(VALID_PACKAGE_VERSIONS);
- assertNotNull(token1);
-
- // There should now be state.
- assertNotNull(mPackageStatusStorage.getPackageStatus());
-
- // Corrupt the table by removing the one row.
- mPackageStatusStorage.deleteRowForTests();
-
- // Check that generateCheckToken recovers.
- assertNotNull(mPackageStatusStorage.generateCheckToken(VALID_PACKAGE_VERSIONS));
- }
-
- @Test
- public void getPackageStatus_missingRowBehavior() {
- // Assert initial state.
- assertNull(mPackageStatusStorage.getPackageStatus());
-
- CheckToken token1 = mPackageStatusStorage.generateCheckToken(VALID_PACKAGE_VERSIONS);
- assertNotNull(token1);
-
- // There should now be a state.
- assertNotNull(mPackageStatusStorage.getPackageStatus());
-
- // Corrupt the table by removing the one row.
- mPackageStatusStorage.deleteRowForTests();
-
- assertNull(mPackageStatusStorage.getPackageStatus());
- }
-
- @Test
- public void markChecked_missingRowBehavior() {
- // Assert initial state.
- CheckToken token1 = mPackageStatusStorage.generateCheckToken(VALID_PACKAGE_VERSIONS);
- assertNotNull(token1);
-
- // There should now be a state.
- assertNotNull(mPackageStatusStorage.getPackageStatus());
-
- // Corrupt the table by removing the one row.
- mPackageStatusStorage.deleteRowForTests();
-
- // The missing row should mean token1 is now considered invalid, so we should get a false.
- assertFalse(mPackageStatusStorage.markChecked(token1, true /* succeeded */));
-
- // The storage should have recovered and we should be able to carry on like before.
- CheckToken token2 = mPackageStatusStorage.generateCheckToken(VALID_PACKAGE_VERSIONS);
- assertTrue(mPackageStatusStorage.markChecked(token2, true /* succeeded */));
- }
-
- @Test
- public void checkToken_tokenIsUnique() {
- PackageVersions packageVersions = VALID_PACKAGE_VERSIONS;
- PackageStatus expectedPackageStatus =
- new PackageStatus(PackageStatus.CHECK_STARTED, packageVersions);
-
- CheckToken token1 = mPackageStatusStorage.generateCheckToken(packageVersions);
- assertEquals(packageVersions, token1.mPackageVersions);
-
- PackageStatus actualPackageStatus1 = mPackageStatusStorage.getPackageStatus();
- assertEquals(expectedPackageStatus, actualPackageStatus1);
-
- CheckToken token2 = mPackageStatusStorage.generateCheckToken(packageVersions);
- assertEquals(packageVersions, token1.mPackageVersions);
- assertFalse(token1.mOptimisticLockId == token2.mOptimisticLockId);
- assertFalse(token1.equals(token2));
- }
-
- @Test
- public void markChecked_checkSucceeded() {
- PackageVersions packageVersions = VALID_PACKAGE_VERSIONS;
-
- CheckToken token = mPackageStatusStorage.generateCheckToken(packageVersions);
- boolean writeOk = mPackageStatusStorage.markChecked(token, true /* succeeded */);
- assertTrue(writeOk);
-
- PackageStatus expectedPackageStatus =
- new PackageStatus(PackageStatus.CHECK_COMPLETED_SUCCESS, packageVersions);
- assertEquals(expectedPackageStatus, mPackageStatusStorage.getPackageStatus());
- }
-
- @Test
- public void markChecked_checkFailed() {
- PackageVersions packageVersions = VALID_PACKAGE_VERSIONS;
-
- CheckToken token = mPackageStatusStorage.generateCheckToken(packageVersions);
- boolean writeOk = mPackageStatusStorage.markChecked(token, false /* succeeded */);
- assertTrue(writeOk);
-
- PackageStatus expectedPackageStatus =
- new PackageStatus(PackageStatus.CHECK_COMPLETED_FAILURE, packageVersions);
- assertEquals(expectedPackageStatus, mPackageStatusStorage.getPackageStatus());
- }
-
- @Test
- public void markChecked_optimisticLocking_multipleToken() {
- PackageVersions packageVersions = VALID_PACKAGE_VERSIONS;
- CheckToken token1 = mPackageStatusStorage.generateCheckToken(packageVersions);
- CheckToken token2 = mPackageStatusStorage.generateCheckToken(packageVersions);
-
- PackageStatus packageStatusBeforeChecked = mPackageStatusStorage.getPackageStatus();
-
- boolean writeOk1 = mPackageStatusStorage.markChecked(token1, true /* succeeded */);
- // Generation of token2 should mean that token1 is no longer valid.
- assertFalse(writeOk1);
- assertEquals(packageStatusBeforeChecked, mPackageStatusStorage.getPackageStatus());
-
- boolean writeOk2 = mPackageStatusStorage.markChecked(token2, true /* succeeded */);
- // token2 should still be valid, and the attempt with token1 should have had no effect.
- assertTrue(writeOk2);
- PackageStatus expectedPackageStatus =
- new PackageStatus(PackageStatus.CHECK_COMPLETED_SUCCESS, packageVersions);
- assertEquals(expectedPackageStatus, mPackageStatusStorage.getPackageStatus());
- }
-
- @Test
- public void markChecked_optimisticLocking_repeatedTokenUse() {
- PackageVersions packageVersions = VALID_PACKAGE_VERSIONS;
- CheckToken token = mPackageStatusStorage.generateCheckToken(packageVersions);
-
- boolean writeOk1 = mPackageStatusStorage.markChecked(token, true /* succeeded */);
- assertTrue(writeOk1);
-
- PackageStatus expectedPackageStatus =
- new PackageStatus(PackageStatus.CHECK_COMPLETED_SUCCESS, packageVersions);
- assertEquals(expectedPackageStatus, mPackageStatusStorage.getPackageStatus());
-
- // token cannot be reused.
- boolean writeOk2 = mPackageStatusStorage.markChecked(token, true /* succeeded */);
- assertFalse(writeOk2);
- assertEquals(expectedPackageStatus, mPackageStatusStorage.getPackageStatus());
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/timezone/PackageStatusTest.java b/services/tests/servicestests/src/com/android/server/timezone/PackageStatusTest.java
deleted file mode 100644
index c0ae81e30049..000000000000
--- a/services/tests/servicestests/src/com/android/server/timezone/PackageStatusTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.timezone;
-
-import org.junit.Test;
-
-import android.support.test.filters.SmallTest;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-
-@SmallTest
-public class PackageStatusTest {
-
- @Test
- public void equals() {
- PackageVersions packageVersions1 =
- new PackageVersions(1 /* updateAppVersion */, 1 /* dataAppVersion */);
- PackageVersions packageVersions2 =
- new PackageVersions(2 /* updateAppVersion */, 1 /* dataAppVersion */);
- assertFalse(packageVersions1.equals(packageVersions2));
-
- PackageStatus baseline =
- new PackageStatus(PackageStatus.CHECK_STARTED, packageVersions1);
- assertEquals(baseline, baseline);
-
- PackageStatus deepEqual =
- new PackageStatus(PackageStatus.CHECK_STARTED, packageVersions1);
- assertEquals(baseline, deepEqual);
-
- PackageStatus differentStatus =
- new PackageStatus(PackageStatus.CHECK_COMPLETED_SUCCESS, packageVersions1);
- assertFalse(differentStatus.equals(baseline));
-
- PackageStatus differentPackageVersions =
- new PackageStatus(PackageStatus.CHECK_STARTED, packageVersions2);
- assertFalse(differentPackageVersions.equals(baseline));
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java b/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java
deleted file mode 100644
index 45b0af37f9e3..000000000000
--- a/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java
+++ /dev/null
@@ -1,1471 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.timezone;
-
-import org.hamcrest.BaseMatcher;
-import org.hamcrest.Description;
-import org.hamcrest.Matcher;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import android.app.timezone.RulesUpdaterContract;
-import android.content.Context;
-import android.content.Intent;
-import android.provider.TimeZoneRulesDataContract;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-import static org.mockito.hamcrest.MockitoHamcrest.argThat;
-
-/**
- * White box interaction / unit testing of the {@link PackageTracker}.
- */
-@SmallTest
-public class PackageTrackerTest {
- private static final String UPDATE_APP_PACKAGE_NAME = "updateAppPackageName";
- private static final String DATA_APP_PACKAGE_NAME = "dataAppPackageName";
- private static final PackageVersions INITIAL_APP_PACKAGE_VERSIONS =
- new PackageVersions(2 /* updateAppVersion */, 2 /* dataAppVersion */);
-
- private ConfigHelper mMockConfigHelper;
- private PackageManagerHelper mMockPackageManagerHelper;
-
- private FakeClockHelper mFakeClock;
- private FakeIntentHelper mFakeIntentHelper;
- private PackageStatusStorage mPackageStatusStorage;
- private PackageTracker mPackageTracker;
-
- @Before
- public void setUp() throws Exception {
- Context context = InstrumentationRegistry.getContext();
-
- mFakeClock = new FakeClockHelper();
-
- // Read-only interfaces so are easy to mock.
- mMockConfigHelper = mock(ConfigHelper.class);
- mMockPackageManagerHelper = mock(PackageManagerHelper.class);
-
- // Using the instrumentation context means the database is created in a test app-specific
- // directory. We can use the real thing for this test.
- mPackageStatusStorage = new PackageStatusStorage(context);
-
- // For other interactions with the Android framework we create a fake object.
- mFakeIntentHelper = new FakeIntentHelper();
-
- // Create the PackageTracker to use in tests.
- mPackageTracker = new PackageTracker(
- mFakeClock,
- mMockConfigHelper,
- mMockPackageManagerHelper,
- mPackageStatusStorage,
- mFakeIntentHelper);
- }
-
- @After
- public void tearDown() throws Exception {
- if (mPackageStatusStorage != null) {
- mPackageStatusStorage.deleteDatabaseForTests();
- }
- }
-
- @Test
- public void trackingDisabled_intentHelperNotUsed() {
- // Set up device configuration.
- configureTrackingDisabled();
-
- // Initialize the tracker.
- mPackageTracker.start();
-
- // Check the IntentHelper was not initialized.
- mFakeIntentHelper.assertNotInitialized();
-
- // Check reliability triggering state.
- mFakeIntentHelper.assertReliabilityTriggeringDisabled();
- }
-
- @Test
- public void trackingDisabled_triggerUpdateIfNeededNotAllowed() {
- // Set up device configuration.
- configureTrackingDisabled();
-
- // Initialize the tracker.
- mPackageTracker.start();
-
- // Check reliability triggering state.
- mFakeIntentHelper.assertReliabilityTriggeringDisabled();
-
- try {
- // This call should also not be allowed and will throw an exception if tracking is
- // disabled.
- mPackageTracker.triggerUpdateIfNeeded(true);
- fail();
- } catch (IllegalStateException expected) {}
-
- // Check reliability triggering state.
- mFakeIntentHelper.assertReliabilityTriggeringDisabled();
- }
-
- @Test
- public void trackingDisabled_unsolicitedResultsIgnored_withoutToken() {
- // Set up device configuration.
- configureTrackingDisabled();
-
- // Initialize the tracker.
- mPackageTracker.start();
-
- // Check reliability triggering state.
- mFakeIntentHelper.assertReliabilityTriggeringDisabled();
-
- // Receiving a check result when tracking is disabled should cause the storage to be
- // reset.
- mPackageTracker.recordCheckResult(null /* checkToken */, true /* success */);
-
- // Check reliability triggering state.
- mFakeIntentHelper.assertReliabilityTriggeringDisabled();
-
- // Assert the storage was reset.
- checkPackageStorageStatusIsInitialOrReset();
- }
-
- @Test
- public void trackingDisabled_unsolicitedResultsIgnored_withToken() {
- // Set up device configuration.
- configureTrackingDisabled();
-
- // Set the storage into an arbitrary state so we can detect a reset.
- mPackageStatusStorage.generateCheckToken(INITIAL_APP_PACKAGE_VERSIONS);
-
- // Initialize the tracker.
- mPackageTracker.start();
-
- // Check reliability triggering state.
- mFakeIntentHelper.assertReliabilityTriggeringDisabled();
-
- // Receiving a check result when tracking is disabled should cause the storage to be reset.
- mPackageTracker.recordCheckResult(createArbitraryCheckToken(), true /* success */);
-
- // Check reliability triggering state.
- mFakeIntentHelper.assertReliabilityTriggeringDisabled();
-
- // Assert the storage was reset.
- checkPackageStorageStatusIsInitialOrReset();
- }
-
- @Test
- public void trackingEnabled_updateAppConfigMissing() throws Exception {
- // Set up device configuration.
- configureTrackingEnabled();
- configureReliabilityConfigSettingsOk();
- configureUpdateAppPackageNameMissing();
- configureDataAppPackageOk(DATA_APP_PACKAGE_NAME);
-
- try {
- // Initialize the tracker.
- mPackageTracker.start();
- fail();
- } catch (RuntimeException expected) {}
-
- mFakeIntentHelper.assertNotInitialized();
-
- // Check reliability triggering state.
- mFakeIntentHelper.assertReliabilityTriggeringDisabled();
- }
-
- // TODO(nfuller): Uncomment or delete when it's clear what will happen with http://b/35995024
- // @Test
- // public void trackingEnabled_updateAppNotPrivileged() throws Exception {
- // // Set up device configuration.
- // configureTrackingEnabled();
- // configureReliabilityConfigSettingsOk();
- // configureUpdateAppPackageNotPrivileged(UPDATE_APP_PACKAGE_NAME);
- // configureDataAppPackageOk(DATA_APP_PACKAGE_NAME);
- //
- // try {
- // // Initialize the tracker.
- // mPackageTracker.start();
- // fail();
- // } catch (RuntimeException expected) {}
- //
- // mFakeIntentHelper.assertNotInitialized();
- //
- // // Check reliability triggering state.
- // mFakeIntentHelper.assertReliabilityTriggeringDisabled();
- // }
-
- @Test
- public void trackingEnabled_dataAppConfigMissing() throws Exception {
- // Set up device configuration.
- configureTrackingEnabled();
- configureReliabilityConfigSettingsOk();
- configureUpdateAppPackageOk(UPDATE_APP_PACKAGE_NAME);
- configureDataAppPackageNameMissing();
-
- try {
- // Initialize the tracker.
- mPackageTracker.start();
- fail();
- } catch (RuntimeException expected) {}
-
- mFakeIntentHelper.assertNotInitialized();
-
- // Check reliability triggering state.
- mFakeIntentHelper.assertReliabilityTriggeringDisabled();
- }
-
- // TODO(nfuller): Uncomment or delete when it's clear what will happen with http://b/35995024
- // @Test
- // public void trackingEnabled_dataAppNotPrivileged() throws Exception {
- // // Set up device configuration.
- // configureTrackingEnabled();
- // configureReliabilityConfigSettingsOk();
- // configureUpdateAppPackageOk(UPDATE_APP_PACKAGE_NAME);
- // configureDataAppPackageNotPrivileged(DATA_APP_PACKAGE_NAME);
- //
- // try {
- // // Initialize the tracker.
- // mPackageTracker.start();
- // fail();
- // } catch (RuntimeException expected) {}
- //
- // mFakeIntentHelper.assertNotInitialized();
- //
- // // Check reliability triggering state.
- // mFakeIntentHelper.assertReliabilityTriggeringDisabled();
- // }
-
- @Test
- public void trackingEnabled_packageUpdate_badUpdateAppManifestEntry() throws Exception {
- // Set up device configuration.
- configureTrackingEnabled();
- configureReliabilityConfigSettingsOk();
- configureValidApplications();
-
- // Initialize the tracker.
- mPackageTracker.start();
-
- // Check the intent helper is properly configured.
- checkIntentHelperInitializedAndReliabilityTrackingEnabled();
-
- // Check the initial storage state.
- checkPackageStorageStatusIsInitialOrReset();
-
- // Configure a bad manifest for the update app. Should effectively turn off tracking.
- PackageVersions packageVersions =
- new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
- configureUpdateAppManifestBad(UPDATE_APP_PACKAGE_NAME);
- configureDataAppManifestOk(DATA_APP_PACKAGE_NAME);
- configureUpdateAppPackageVersion(
- UPDATE_APP_PACKAGE_NAME, packageVersions.mUpdateAppVersion);
- configureDataAppPackageVersion(DATA_APP_PACKAGE_NAME, packageVersions.mDataAppVersion);
- // Simulate a tracked package being updated.
- mFakeIntentHelper.simulatePackageUpdatedEvent();
-
- // Assert the PackageTracker did not attempt to trigger an update.
- mFakeIntentHelper.assertUpdateNotTriggered();
-
- // Check reliability triggering state.
- mFakeIntentHelper.assertReliabilityTriggeringDisabled();
-
- // Assert the storage was not touched.
- checkPackageStorageStatusIsInitialOrReset();
- }
-
- @Test
- public void trackingEnabled_packageUpdate_badDataAppManifestEntry() throws Exception {
- // Set up device configuration.
- configureTrackingEnabled();
- configureReliabilityConfigSettingsOk();
- configureValidApplications();
-
- // Initialize the tracker.
- mPackageTracker.start();
-
- // Check the intent helper is properly configured.
- checkIntentHelperInitializedAndReliabilityTrackingEnabled();
-
- // Check the initial storage state.
- checkPackageStorageStatusIsInitialOrReset();
-
- // Configure a bad manifest for the data app. Should effectively turn off tracking.
- PackageVersions packageVersions =
- new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
- configureUpdateAppManifestOk(UPDATE_APP_PACKAGE_NAME);
- configureDataAppManifestBad(DATA_APP_PACKAGE_NAME);
- configureUpdateAppPackageVersion(
- UPDATE_APP_PACKAGE_NAME, packageVersions.mUpdateAppVersion);
- configureDataAppPackageVersion(DATA_APP_PACKAGE_NAME, packageVersions.mDataAppVersion);
- mFakeIntentHelper.simulatePackageUpdatedEvent();
-
- // Assert the PackageTracker did not attempt to trigger an update.
- mFakeIntentHelper.assertUpdateNotTriggered();
-
- // Check reliability triggering state.
- mFakeIntentHelper.assertReliabilityTriggeringDisabled();
-
- // Assert the storage was not touched.
- checkPackageStorageStatusIsInitialOrReset();
- }
-
- @Test
- public void trackingEnabled_packageUpdate_responseWithToken_success() throws Exception {
- trackingEnabled_packageUpdate_responseWithToken(true);
- }
-
- @Test
- public void trackingEnabled_packageUpdate_responseWithToken_failed() throws Exception {
- trackingEnabled_packageUpdate_responseWithToken(false);
- }
-
- private void trackingEnabled_packageUpdate_responseWithToken(boolean success) throws Exception {
- // Set up device configuration.
- configureTrackingEnabled();
- configureReliabilityConfigSettingsOk();
- configureValidApplications();
-
- // Initialize the tracker.
- mPackageTracker.start();
-
- // Check the intent helper is properly configured.
- checkIntentHelperInitializedAndReliabilityTrackingEnabled();
-
- // Check the initial storage state.
- checkPackageStorageStatusIsInitialOrReset();
-
- // Simulate a tracked package being updated.
- PackageVersions packageVersions =
- new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
- simulatePackageInstallation(packageVersions);
-
- // Confirm an update was triggered.
- checkUpdateCheckTriggered(packageVersions);
-
- // Get the token that was passed to the intent helper, and pass it back.
- CheckToken token = mFakeIntentHelper.captureAndResetLastToken();
- mPackageTracker.recordCheckResult(token, success);
-
- // Check storage and reliability triggering state.
- if (success) {
- checkUpdateCheckSuccessful(packageVersions);
- } else {
- checkUpdateCheckFailed(packageVersions);
- }
- }
-
- @Test
- public void trackingEnabled_packageUpdate_responseWithoutTokenCausesStorageReset_success()
- throws Exception {
- trackingEnabled_packageUpdate_responseWithoutTokenCausesStorageReset(true);
- }
-
- @Test
- public void trackingEnabled_packageUpdate_responseWithoutTokenCausesStorageReset_failed()
- throws Exception {
- trackingEnabled_packageUpdate_responseWithoutTokenCausesStorageReset(false);
- }
-
- private void trackingEnabled_packageUpdate_responseWithoutTokenCausesStorageReset(
- boolean success) throws Exception {
- // Set up device configuration.
- configureTrackingEnabled();
- configureReliabilityConfigSettingsOk();
- configureValidApplications();
-
- // Initialize the tracker.
- mPackageTracker.start();
-
- // Check the intent helper is properly configured.
- checkIntentHelperInitializedAndReliabilityTrackingEnabled();
-
- // Check the initial storage state.
- checkPackageStorageStatusIsInitialOrReset();
-
- // Set up installed app versions / manifests.
- PackageVersions packageVersions =
- new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
- simulatePackageInstallation(packageVersions);
-
- // Confirm an update was triggered.
- checkUpdateCheckTriggered(packageVersions);
-
- // Ignore the token that was given to the intent helper, just pass null.
- mPackageTracker.recordCheckResult(null /* checkToken */, success);
-
- // Check reliability triggering state.
- mFakeIntentHelper.assertReliabilityTriggeringEnabled();
-
- // Assert the storage was reset.
- checkPackageStorageStatusIsInitialOrReset();
- }
-
- /**
- * Two package updates triggered for the same package versions. The second is triggered while
- * the first is still happening.
- */
- @Test
- public void trackingEnabled_packageUpdate_twoChecksNoPackageChange_secondWhileFirstInProgress()
- throws Exception {
- // Set up device configuration.
- configureTrackingEnabled();
- configureReliabilityConfigSettingsOk();
- configureValidApplications();
-
- // Initialize the tracker.
- mPackageTracker.start();
-
- // Check the intent helper is properly configured.
- checkIntentHelperInitializedAndReliabilityTrackingEnabled();
-
- // Check the initial storage state.
- checkPackageStorageStatusIsInitialOrReset();
-
- // Simulate package installation.
- PackageVersions packageVersions =
- new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
- simulatePackageInstallation(packageVersions);
-
- // Confirm an update was triggered.
- checkUpdateCheckTriggered(packageVersions);
-
- // Get the first token.
- CheckToken token1 = mFakeIntentHelper.captureAndResetLastToken();
- assertEquals(packageVersions, token1.mPackageVersions);
-
- // Now attempt to generate another check while the first is in progress and without having
- // updated the package versions. The PackageTracker should trigger again for safety.
- simulatePackageInstallation(packageVersions);
-
- // Confirm an update was triggered.
- checkUpdateCheckTriggered(packageVersions);
-
- CheckToken token2 = mFakeIntentHelper.captureAndResetLastToken();
- assertEquals(packageVersions, token2.mPackageVersions);
- assertEquals(token1.mPackageVersions, token2.mPackageVersions);
- assertTrue(token1.mOptimisticLockId != token2.mOptimisticLockId);
- }
-
- /**
- * Two package updates triggered for the same package versions. The second happens after
- * the first has succeeded.
- */
- @Test
- public void trackingEnabled_packageUpdate_twoChecksNoPackageChange_sequential()
- throws Exception {
- // Set up device configuration.
- configureTrackingEnabled();
- configureReliabilityConfigSettingsOk();
- configureValidApplications();
-
- // Initialize the tracker.
- mPackageTracker.start();
-
- // Check the intent helper is properly configured.
- checkIntentHelperInitializedAndReliabilityTrackingEnabled();
-
- // Check the initial storage state.
- checkPackageStorageStatusIsInitialOrReset();
-
- // Simulate package installation.
- PackageVersions packageVersions =
- new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
- simulatePackageInstallation(packageVersions);
-
- // Confirm an update was triggered.
- checkUpdateCheckTriggered(packageVersions);
-
- // Get the token.
- CheckToken token = mFakeIntentHelper.captureAndResetLastToken();
- assertEquals(packageVersions, token.mPackageVersions);
-
- // Simulate a successful check.
- mPackageTracker.recordCheckResult(token, true /* success */);
-
- // Check storage and reliability triggering state.
- checkUpdateCheckSuccessful(packageVersions);
-
- // Now attempt to generate another check, but without having updated the package. The
- // PackageTracker should be smart enough to recognize there's nothing to do here.
- simulatePackageInstallation(packageVersions);
-
- // Assert the PackageTracker did not attempt to trigger an update.
- mFakeIntentHelper.assertUpdateNotTriggered();
-
- // Check storage and reliability triggering state.
- checkUpdateCheckSuccessful(packageVersions);
- }
-
- /**
- * Two package updates triggered for the same package versions. The second is triggered after
- * the first has failed.
- */
- @Test
- public void trackingEnabled_packageUpdate_afterFailure() throws Exception {
- // Set up device configuration.
- configureTrackingEnabled();
- configureReliabilityConfigSettingsOk();
- configureValidApplications();
-
- // Initialize the tracker.
- mPackageTracker.start();
-
- // Check the intent helper is properly configured.
- checkIntentHelperInitializedAndReliabilityTrackingEnabled();
-
- // Check the initial storage state.
- checkPackageStorageStatusIsInitialOrReset();
-
- // Simulate package installation.
- PackageVersions packageVersions =
- new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
- simulatePackageInstallation(packageVersions);
-
- // Confirm an update was triggered.
- checkUpdateCheckTriggered(packageVersions);
-
- // Get the first token.
- CheckToken token1 = mFakeIntentHelper.captureAndResetLastToken();
- assertEquals(packageVersions, token1.mPackageVersions);
-
- // Simulate an *unsuccessful* check.
- mPackageTracker.recordCheckResult(token1, false /* success */);
-
- // Check storage and reliability triggering state.
- checkUpdateCheckFailed(packageVersions);
-
- // Now generate another check, but without having updated the package. The
- // PackageTracker should recognize the last check failed and trigger again.
- simulatePackageInstallation(packageVersions);
-
- // Confirm an update was triggered.
- checkUpdateCheckTriggered(packageVersions);
-
- // Get the second token.
- CheckToken token2 = mFakeIntentHelper.captureAndResetLastToken();
-
- // Assert some things about the tokens.
- assertEquals(packageVersions, token2.mPackageVersions);
- assertTrue(token1.mOptimisticLockId != token2.mOptimisticLockId);
-
- // For completeness, now simulate this check was successful.
- mPackageTracker.recordCheckResult(token2, true /* success */);
-
- // Check storage and reliability triggering state.
- checkUpdateCheckSuccessful(packageVersions);
- }
-
- /**
- * Two package updates triggered for different package versions. The second is triggered while
- * the first is still happening.
- */
- @Test
- public void trackingEnabled_packageUpdate_twoChecksWithPackageChange_firstCheckInProcess()
- throws Exception {
- // Set up device configuration.
- configureTrackingEnabled();
- configureReliabilityConfigSettingsOk();
- configureValidApplications();
-
- // Initialize the package tracker.
- mPackageTracker.start();
-
- // Check the intent helper is properly configured.
- checkIntentHelperInitializedAndReliabilityTrackingEnabled();
-
- // Check the initial storage state.
- checkPackageStorageStatusIsInitialOrReset();
-
- // Simulate package installation.
- PackageVersions packageVersions1 =
- new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
- simulatePackageInstallation(packageVersions1);
-
- // Confirm an update was triggered.
- checkUpdateCheckTriggered(packageVersions1);
-
- // Get the first token.
- CheckToken token1 = mFakeIntentHelper.captureAndResetLastToken();
- assertEquals(packageVersions1, token1.mPackageVersions);
-
- // Simulate a tracked package being updated a second time (before the response for the
- // first has been received).
- PackageVersions packageVersions2 =
- new PackageVersions(3 /* updateAppPackageVersion */, 4 /* dataAppPackageVersion */);
- simulatePackageInstallation(packageVersions2);
-
- // Confirm an update was triggered.
- checkUpdateCheckTriggered(packageVersions2);
-
- // Get the second token.
- CheckToken token2 = mFakeIntentHelper.captureAndResetLastToken();
- assertEquals(packageVersions2, token2.mPackageVersions);
-
- // token1 should be invalid because the token2 was generated.
- mPackageTracker.recordCheckResult(token1, true /* success */);
-
- // Reliability triggering should still be enabled.
- mFakeIntentHelper.assertReliabilityTriggeringEnabled();
-
- // Check the expected storage state.
- checkPackageStorageStatus(PackageStatus.CHECK_STARTED, packageVersions2);
-
- // token2 should still be accepted.
- mPackageTracker.recordCheckResult(token2, true /* success */);
-
- // Check storage and reliability triggering state.
- checkUpdateCheckSuccessful(packageVersions2);
- }
-
- /**
- * Two package updates triggered for different package versions. The second is triggered after
- * the first has completed successfully.
- */
- @Test
- public void trackingEnabled_packageUpdate_twoChecksWithPackageChange_sequential()
- throws Exception {
- // Set up device configuration.
- configureTrackingEnabled();
- configureReliabilityConfigSettingsOk();
- configureValidApplications();
-
- // Initialize the package tracker.
- mPackageTracker.start();
-
- // Check the intent helper is properly configured.
- checkIntentHelperInitializedAndReliabilityTrackingEnabled();
-
- // Check the initial storage state.
- checkPackageStorageStatusIsInitialOrReset();
-
- // Simulate package installation.
- PackageVersions packageVersions1 =
- new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
- simulatePackageInstallation(packageVersions1);
-
- // Confirm an update was triggered.
- checkUpdateCheckTriggered(packageVersions1);
-
- // Get the first token.
- CheckToken token1 = mFakeIntentHelper.captureAndResetLastToken();
- assertEquals(packageVersions1, token1.mPackageVersions);
-
- // token1 should be accepted.
- mPackageTracker.recordCheckResult(token1, true /* success */);
-
- // Check storage and reliability triggering state.
- checkUpdateCheckSuccessful(packageVersions1);
-
- // Simulate a tracked package being updated a second time.
- PackageVersions packageVersions2 =
- new PackageVersions(3 /* updateAppPackageVersion */, 4 /* dataAppPackageVersion */);
- simulatePackageInstallation(packageVersions2);
-
- // Confirm an update was triggered.
- checkUpdateCheckTriggered(packageVersions2);
-
- // Get the second token.
- CheckToken token2 = mFakeIntentHelper.captureAndResetLastToken();
- assertEquals(packageVersions2, token2.mPackageVersions);
-
- // token2 should still be accepted.
- mPackageTracker.recordCheckResult(token2, true /* success */);
-
- // Check storage and reliability triggering state.
- checkUpdateCheckSuccessful(packageVersions2);
- }
-
- /**
- * Replaying the same token twice.
- */
- @Test
- public void trackingEnabled_packageUpdate_sameTokenReplayFails() throws Exception {
- // Set up device configuration.
- configureTrackingEnabled();
- configureReliabilityConfigSettingsOk();
- configureValidApplications();
-
- // Initialize the package tracker.
- mPackageTracker.start();
-
- // Check the intent helper is properly configured.
- checkIntentHelperInitializedAndReliabilityTrackingEnabled();
-
- // Check the initial storage state.
- checkPackageStorageStatusIsInitialOrReset();
-
- // Simulate package installation.
- PackageVersions packageVersions1 =
- new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
- simulatePackageInstallation(packageVersions1);
-
- // Confirm an update was triggered.
- checkUpdateCheckTriggered(packageVersions1);
-
- // Get the first token.
- CheckToken token1 = mFakeIntentHelper.captureAndResetLastToken();
- assertEquals(packageVersions1, token1.mPackageVersions);
-
- // token1 should be accepted.
- mPackageTracker.recordCheckResult(token1, true /* success */);
-
- // Check storage and reliability triggering state.
- checkUpdateCheckSuccessful(packageVersions1);
-
- // Apply token1 again.
- mPackageTracker.recordCheckResult(token1, true /* success */);
-
- // Check the expected storage state. No real way to tell if it has been updated, but
- // we can check the final state is still what it should be.
- checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_SUCCESS, packageVersions1);
-
- // Under the covers we expect it to fail to update because the storage should recognize that
- // the token is no longer valid.
- mFakeIntentHelper.assertReliabilityTriggeringEnabled();
-
- // Peek inside the package tracker to make sure it is tracking failure counts properly.
- assertEquals(1, mPackageTracker.getCheckFailureCountForTests());
- }
-
- @Test
- public void trackingEnabled_reliabilityTrigger_firstTime_initialStorage() throws Exception {
- // Set up device configuration.
- configureTrackingEnabled();
- configureReliabilityConfigSettingsOk();
- PackageVersions packageVersions = configureValidApplications();
-
- // Initialize the package tracker.
- mPackageTracker.start();
-
- // Check the intent helper is properly configured.
- checkIntentHelperInitializedAndReliabilityTrackingEnabled();
-
- // Check the initial storage state.
- checkPackageStorageStatusIsInitialOrReset();
-
- // Simulate a reliability trigger.
- mFakeIntentHelper.simulateReliabilityTrigger();
-
- // Assert the PackageTracker did trigger an update.
- checkUpdateCheckTriggered(packageVersions);
-
- // Confirm the token was correct.
- CheckToken token1 = mFakeIntentHelper.captureAndResetLastToken();
- assertEquals(packageVersions, token1.mPackageVersions);
-
- // token1 should be accepted.
- mPackageTracker.recordCheckResult(token1, true /* success */);
-
- // Check storage and reliability triggering state.
- checkUpdateCheckSuccessful(packageVersions);
- }
-
- @Test
- public void trackingEnabled_reliabilityTrigger_afterRebootNoTriggerNeeded() throws Exception {
- // Set up device configuration.
- configureTrackingEnabled();
- configureReliabilityConfigSettingsOk();
- PackageVersions packageVersions = configureValidApplications();
-
- // Force the storage into a state we want.
- mPackageStatusStorage.forceCheckStateForTests(
- PackageStatus.CHECK_COMPLETED_SUCCESS, packageVersions);
-
- // Initialize the package tracker.
- mPackageTracker.start();
-
- // Check the intent helper is properly configured.
- checkIntentHelperInitializedAndReliabilityTrackingEnabled();
-
- // Check the initial storage state.
- checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_SUCCESS, packageVersions);
-
- // Simulate a reliability trigger.
- mFakeIntentHelper.simulateReliabilityTrigger();
-
- // Assert the PackageTracker did not attempt to trigger an update.
- mFakeIntentHelper.assertUpdateNotTriggered();
-
- // Check storage and reliability triggering state.
- checkUpdateCheckSuccessful(packageVersions);
- }
-
- /**
- * Simulates the device starting where the storage records do not match the installed app
- * versions. The reliability trigger should cause the package tracker to perform a check.
- */
- @Test
- public void trackingEnabled_reliabilityTrigger_afterRebootTriggerNeededBecausePreviousFailed()
- throws Exception {
- // Set up device configuration.
- configureTrackingEnabled();
- configureReliabilityConfigSettingsOk();
-
- PackageVersions oldPackageVersions = new PackageVersions(1, 1);
- PackageVersions currentPackageVersions = new PackageVersions(2, 2);
-
- // Simulate there being a newer version installed than the one recorded in storage.
- configureValidApplications(currentPackageVersions);
-
- // Force the storage into a state we want.
- mPackageStatusStorage.forceCheckStateForTests(
- PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
-
- // Initialize the package tracker.
- mPackageTracker.start();
-
- // Check the intent helper is properly configured.
- checkIntentHelperInitializedAndReliabilityTrackingEnabled();
-
- // Check the initial storage state.
- checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
-
- // Simulate a reliability trigger.
- mFakeIntentHelper.simulateReliabilityTrigger();
-
- // Assert the PackageTracker did trigger an update.
- checkUpdateCheckTriggered(currentPackageVersions);
-
- // Simulate the update check completing successfully.
- CheckToken checkToken = mFakeIntentHelper.captureAndResetLastToken();
- mPackageTracker.recordCheckResult(checkToken, true /* success */);
-
- // Check storage and reliability triggering state.
- checkUpdateCheckSuccessful(currentPackageVersions);
- }
-
- /**
- * Simulates persistent failures of the reliability check. It should stop after the configured
- * number of checks.
- */
- @Test
- public void trackingEnabled_reliabilityTrigger_repeatedFailures() throws Exception {
- // Set up device configuration.
- configureTrackingEnabled();
-
- int retriesAllowed = 3;
- int checkDelayMillis = 5 * 60 * 1000;
- configureReliabilityConfigSettings(retriesAllowed, checkDelayMillis);
-
- PackageVersions oldPackageVersions = new PackageVersions(1, 1);
- PackageVersions currentPackageVersions = new PackageVersions(2, 2);
-
- // Simulate there being a newer version installed than the one recorded in storage.
- configureValidApplications(currentPackageVersions);
-
- // Force the storage into a state we want.
- mPackageStatusStorage.forceCheckStateForTests(
- PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
-
- // Initialize the package tracker.
- mPackageTracker.start();
-
- // Check the intent helper is properly configured.
- checkIntentHelperInitializedAndReliabilityTrackingEnabled();
-
- // Check the initial storage state.
- checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
-
- for (int i = 0; i < retriesAllowed + 1; i++) {
- // Simulate a reliability trigger.
- mFakeIntentHelper.simulateReliabilityTrigger();
-
- // Assert the PackageTracker did trigger an update.
- checkUpdateCheckTriggered(currentPackageVersions);
-
- // Check the PackageTracker failure count before calling recordCheckResult.
- assertEquals(i, mPackageTracker.getCheckFailureCountForTests());
-
- // Simulate a check failure.
- CheckToken checkToken = mFakeIntentHelper.captureAndResetLastToken();
- mPackageTracker.recordCheckResult(checkToken, false /* success */);
-
- // Peek inside the package tracker to make sure it is tracking failure counts properly.
- assertEquals(i + 1, mPackageTracker.getCheckFailureCountForTests());
-
- // Confirm nothing has changed.
- mFakeIntentHelper.assertUpdateNotTriggered();
- checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_FAILURE,
- currentPackageVersions);
-
- // Check reliability triggering is in the correct state.
- if (i <= retriesAllowed) {
- mFakeIntentHelper.assertReliabilityTriggeringEnabled();
- } else {
- mFakeIntentHelper.assertReliabilityTriggeringDisabled();
- }
- }
- }
-
- @Test
- public void trackingEnabled_reliabilityTrigger_failureCountIsReset() throws Exception {
- // Set up device configuration.
- configureTrackingEnabled();
-
- int retriesAllowed = 3;
- int checkDelayMillis = 5 * 60 * 1000;
- configureReliabilityConfigSettings(retriesAllowed, checkDelayMillis);
-
- PackageVersions oldPackageVersions = new PackageVersions(1, 1);
- PackageVersions currentPackageVersions = new PackageVersions(2, 2);
-
- // Simulate there being a newer version installed than the one recorded in storage.
- configureValidApplications(currentPackageVersions);
-
- // Force the storage into a state we want.
- mPackageStatusStorage.forceCheckStateForTests(
- PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
-
- // Initialize the package tracker.
- mPackageTracker.start();
-
- // Check the intent helper is properly configured.
- checkIntentHelperInitializedAndReliabilityTrackingEnabled();
-
- // Check the initial storage state.
- checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
-
- // Fail (retries - 1) times.
- for (int i = 0; i < retriesAllowed - 1; i++) {
- // Simulate a reliability trigger.
- mFakeIntentHelper.simulateReliabilityTrigger();
-
- // Assert the PackageTracker did trigger an update.
- checkUpdateCheckTriggered(currentPackageVersions);
-
- // Check the PackageTracker failure count before calling recordCheckResult.
- assertEquals(i, mPackageTracker.getCheckFailureCountForTests());
-
- // Simulate a check failure.
- CheckToken checkToken = mFakeIntentHelper.captureAndResetLastToken();
- mPackageTracker.recordCheckResult(checkToken, false /* success */);
-
- // Peek inside the package tracker to make sure it is tracking failure counts properly.
- assertEquals(i + 1, mPackageTracker.getCheckFailureCountForTests());
-
- // Confirm nothing has changed.
- mFakeIntentHelper.assertUpdateNotTriggered();
- checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_FAILURE,
- currentPackageVersions);
-
- // Check reliability triggering is still enabled.
- mFakeIntentHelper.assertReliabilityTriggeringEnabled();
- }
-
- // Simulate a reliability trigger.
- mFakeIntentHelper.simulateReliabilityTrigger();
-
- // Assert the PackageTracker did trigger an update.
- checkUpdateCheckTriggered(currentPackageVersions);
-
- // Check the PackageTracker failure count before calling recordCheckResult.
- assertEquals(retriesAllowed - 1, mPackageTracker.getCheckFailureCountForTests());
-
- // On the last possible try, succeed.
- CheckToken checkToken = mFakeIntentHelper.captureAndResetLastToken();
- mPackageTracker.recordCheckResult(checkToken, true /* success */);
-
- checkUpdateCheckSuccessful(currentPackageVersions);
- }
-
- /**
- * Simulates reliability triggers happening too close together. Package tracker should ignore
- * the ones it doesn't need.
- */
- @Test
- public void trackingEnabled_reliabilityTrigger_tooSoon() throws Exception {
- // Set up device configuration.
- configureTrackingEnabled();
-
- int retriesAllowed = 5;
- int checkDelayMillis = 5 * 60 * 1000;
- configureReliabilityConfigSettings(retriesAllowed, checkDelayMillis);
-
- PackageVersions oldPackageVersions = new PackageVersions(1, 1);
- PackageVersions currentPackageVersions = new PackageVersions(2, 2);
-
- // Simulate there being a newer version installed than the one recorded in storage.
- configureValidApplications(currentPackageVersions);
-
- // Force the storage into a state we want.
- mPackageStatusStorage.forceCheckStateForTests(
- PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
-
- // Initialize the package tracker.
- mPackageTracker.start();
-
- // Check the intent helper is properly configured.
- checkIntentHelperInitializedAndReliabilityTrackingEnabled();
-
- // Check the initial storage state.
- checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
-
- // Simulate a reliability trigger.
- mFakeIntentHelper.simulateReliabilityTrigger();
-
- // Assert the PackageTracker did trigger an update.
- checkUpdateCheckTriggered(currentPackageVersions);
- CheckToken token1 = mFakeIntentHelper.captureAndResetLastToken();
-
- // Increment the clock, but not enough.
- mFakeClock.incrementClock(checkDelayMillis - 1);
-
- // Simulate a reliability trigger.
- mFakeIntentHelper.simulateReliabilityTrigger();
-
- // Assert the PackageTracker did not trigger an update.
- mFakeIntentHelper.assertUpdateNotTriggered();
- checkPackageStorageStatus(PackageStatus.CHECK_STARTED, currentPackageVersions);
- mFakeIntentHelper.assertReliabilityTriggeringEnabled();
-
- // Increment the clock slightly more. Should now consider the response overdue.
- mFakeClock.incrementClock(2);
-
- // Simulate a reliability trigger.
- mFakeIntentHelper.simulateReliabilityTrigger();
-
- // Triggering should have happened.
- checkUpdateCheckTriggered(currentPackageVersions);
- CheckToken token2 = mFakeIntentHelper.captureAndResetLastToken();
-
- // Check a new token was generated.
- assertFalse(token1.equals(token2));
- }
-
- /**
- * Tests what happens when a package update doesn't complete and a reliability trigger cleans
- * up for it.
- */
- @Test
- public void trackingEnabled_reliabilityTrigger_afterPackageUpdateDidNotComplete()
- throws Exception {
-
- // Set up device configuration.
- configureTrackingEnabled();
-
- int retriesAllowed = 5;
- int checkDelayMillis = 5 * 60 * 1000;
- configureReliabilityConfigSettings(retriesAllowed, checkDelayMillis);
-
- PackageVersions currentPackageVersions = new PackageVersions(1, 1);
- PackageVersions newPackageVersions = new PackageVersions(2, 2);
-
- // Simulate there being a newer version installed than the one recorded in storage.
- configureValidApplications(currentPackageVersions);
-
- // Force the storage into a state we want.
- mPackageStatusStorage.forceCheckStateForTests(
- PackageStatus.CHECK_COMPLETED_SUCCESS, currentPackageVersions);
-
- // Initialize the package tracker.
- mPackageTracker.start();
-
- // Check the intent helper is properly configured.
- checkIntentHelperInitializedAndReliabilityTrackingEnabled();
-
- // Simulate a reliability trigger.
- simulatePackageInstallation(newPackageVersions);
-
- // Assert the PackageTracker did trigger an update.
- checkUpdateCheckTriggered(newPackageVersions);
- CheckToken token1 = mFakeIntentHelper.captureAndResetLastToken();
-
- // Increment the clock, but not enough.
- mFakeClock.incrementClock(checkDelayMillis + 1);
-
- // Simulate a reliability trigger.
- mFakeIntentHelper.simulateReliabilityTrigger();
-
- // Assert the PackageTracker triggered an update.
- checkUpdateCheckTriggered(newPackageVersions);
- CheckToken token2 = mFakeIntentHelper.captureAndResetLastToken();
-
- // Check a new token was generated.
- assertFalse(token1.equals(token2));
-
- // Simulate the reliability check completing.
- mPackageTracker.recordCheckResult(token2, true /* success */);
-
- // Check everything is now as it should be.
- checkUpdateCheckSuccessful(newPackageVersions);
- }
-
- /**
- * Simulates a reliability trigger happening too soon after a package update trigger occurred.
- */
- @Test
- public void trackingEnabled_reliabilityTriggerAfterUpdate_tooSoon() throws Exception {
- // Set up device configuration.
- configureTrackingEnabled();
-
- int retriesAllowed = 5;
- int checkDelayMillis = 5 * 60 * 1000;
- configureReliabilityConfigSettings(retriesAllowed, checkDelayMillis);
-
- PackageVersions currentPackageVersions = new PackageVersions(1, 1);
- PackageVersions newPackageVersions = new PackageVersions(2, 2);
-
- // Simulate there being a newer version installed than the one recorded in storage.
- configureValidApplications(currentPackageVersions);
-
- // Force the storage into a state we want.
- mPackageStatusStorage.forceCheckStateForTests(
- PackageStatus.CHECK_COMPLETED_SUCCESS, currentPackageVersions);
-
- // Initialize the package tracker.
- mPackageTracker.start();
-
- // Check the intent helper is properly configured.
- checkIntentHelperInitializedAndReliabilityTrackingEnabled();
-
- // Check the initial storage state.
- checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_SUCCESS, currentPackageVersions);
-
- // Simulate a package update trigger.
- simulatePackageInstallation(newPackageVersions);
-
- // Assert the PackageTracker did trigger an update.
- checkUpdateCheckTriggered(newPackageVersions);
- CheckToken token1 = mFakeIntentHelper.captureAndResetLastToken();
-
- // Increment the clock, but not enough.
- mFakeClock.incrementClock(checkDelayMillis - 1);
-
- // Simulate a reliability trigger.
- mFakeIntentHelper.simulateReliabilityTrigger();
-
- // Assert the PackageTracker did not trigger an update.
- mFakeIntentHelper.assertUpdateNotTriggered();
- checkPackageStorageStatus(PackageStatus.CHECK_STARTED, newPackageVersions);
- mFakeIntentHelper.assertReliabilityTriggeringEnabled();
-
- // Increment the clock slightly more. Should now consider the response overdue.
- mFakeClock.incrementClock(2);
-
- // Simulate a reliability trigger.
- mFakeIntentHelper.simulateReliabilityTrigger();
-
- // Triggering should have happened.
- checkUpdateCheckTriggered(newPackageVersions);
- CheckToken token2 = mFakeIntentHelper.captureAndResetLastToken();
-
- // Check a new token was generated.
- assertFalse(token1.equals(token2));
- }
-
- private void simulatePackageInstallation(PackageVersions packageVersions) throws Exception {
- configureApplicationsValidManifests(packageVersions);
-
- // Simulate a tracked package being updated.
- mFakeIntentHelper.simulatePackageUpdatedEvent();
- }
-
- /**
- * Checks an update check was triggered, reliability triggering is therefore enabled and the
- * storage state reflects that there is a check in progress.
- */
- private void checkUpdateCheckTriggered(PackageVersions packageVersions) {
- // Assert the PackageTracker attempted to trigger an update.
- mFakeIntentHelper.assertUpdateTriggered();
-
- // If an update check was triggered reliability triggering should always be enabled to
- // ensure that it can be completed if it fails.
- mFakeIntentHelper.assertReliabilityTriggeringEnabled();
-
- // Check the expected storage state.
- checkPackageStorageStatus(PackageStatus.CHECK_STARTED, packageVersions);
- }
-
- private void checkUpdateCheckFailed(PackageVersions packageVersions) {
- // Check reliability triggering state.
- mFakeIntentHelper.assertReliabilityTriggeringEnabled();
-
- // Assert the storage was updated.
- checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_FAILURE, packageVersions);
- }
-
- private void checkUpdateCheckSuccessful(PackageVersions packageVersions) {
- // Check reliability triggering state.
- mFakeIntentHelper.assertReliabilityTriggeringDisabled();
-
- // Assert the storage was updated.
- checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_SUCCESS, packageVersions);
-
- // Peek inside the package tracker to make sure it is tracking failure counts properly.
- assertEquals(0, mPackageTracker.getCheckFailureCountForTests());
- }
-
- private PackageVersions configureValidApplications() throws Exception {
- configureValidApplications(INITIAL_APP_PACKAGE_VERSIONS);
- return INITIAL_APP_PACKAGE_VERSIONS;
- }
-
- private void configureValidApplications(PackageVersions versions) throws Exception {
- configureUpdateAppPackageOk(UPDATE_APP_PACKAGE_NAME);
- configureDataAppPackageOk(DATA_APP_PACKAGE_NAME);
- configureApplicationsValidManifests(versions);
- }
-
- private void configureApplicationsValidManifests(PackageVersions versions) throws Exception {
- configureUpdateAppManifestOk(UPDATE_APP_PACKAGE_NAME);
- configureDataAppManifestOk(DATA_APP_PACKAGE_NAME);
- configureUpdateAppPackageVersion(UPDATE_APP_PACKAGE_NAME, versions.mUpdateAppVersion);
- configureDataAppPackageVersion(DATA_APP_PACKAGE_NAME, versions.mDataAppVersion);
- }
-
- private void configureUpdateAppPackageVersion(String updateAppPackageName,
- int updataAppPackageVersion) throws Exception {
- when(mMockPackageManagerHelper.getInstalledPackageVersion(updateAppPackageName))
- .thenReturn(updataAppPackageVersion);
- }
-
- private void configureDataAppPackageVersion(String dataAppPackageName,
- int dataAppPackageVersion) throws Exception {
- when(mMockPackageManagerHelper.getInstalledPackageVersion(dataAppPackageName))
- .thenReturn(dataAppPackageVersion);
- }
-
- private void configureUpdateAppManifestOk(String updateAppPackageName) throws Exception {
- Intent expectedIntent = RulesUpdaterContract.createUpdaterIntent(updateAppPackageName);
- when(mMockPackageManagerHelper.receiverRegistered(
- filterEquals(expectedIntent),
- eq(RulesUpdaterContract.TRIGGER_TIME_ZONE_RULES_CHECK_PERMISSION)))
- .thenReturn(true);
- when(mMockPackageManagerHelper.usesPermission(
- updateAppPackageName, RulesUpdaterContract.UPDATE_TIME_ZONE_RULES_PERMISSION))
- .thenReturn(true);
- }
-
- private void configureUpdateAppManifestBad(String updateAppPackageName) throws Exception {
- Intent expectedIntent = RulesUpdaterContract.createUpdaterIntent(updateAppPackageName);
- when(mMockPackageManagerHelper.receiverRegistered(
- filterEquals(expectedIntent),
- eq(RulesUpdaterContract.TRIGGER_TIME_ZONE_RULES_CHECK_PERMISSION)))
- .thenReturn(false);
- // Has permission, but that shouldn't matter if the check above is false.
- when(mMockPackageManagerHelper.usesPermission(
- updateAppPackageName, RulesUpdaterContract.UPDATE_TIME_ZONE_RULES_PERMISSION))
- .thenReturn(true);
- }
-
- private void configureDataAppManifestOk(String dataAppPackageName) throws Exception {
- when(mMockPackageManagerHelper.contentProviderRegistered(
- TimeZoneRulesDataContract.AUTHORITY, dataAppPackageName))
- .thenReturn(true);
- }
-
- private void configureDataAppManifestBad(String dataAppPackageName) throws Exception {
- // Simulate the data app not exposing the content provider we require.
- when(mMockPackageManagerHelper.contentProviderRegistered(
- TimeZoneRulesDataContract.AUTHORITY, dataAppPackageName))
- .thenReturn(false);
- }
-
- private void configureTrackingEnabled() {
- when(mMockConfigHelper.isTrackingEnabled()).thenReturn(true);
- }
-
- private void configureTrackingDisabled() {
- when(mMockConfigHelper.isTrackingEnabled()).thenReturn(false);
- }
-
- private void configureReliabilityConfigSettings(int retriesAllowed, int checkDelayMillis) {
- when(mMockConfigHelper.getFailedCheckRetryCount()).thenReturn(retriesAllowed);
- when(mMockConfigHelper.getCheckTimeAllowedMillis()).thenReturn(checkDelayMillis);
- }
-
- private void configureReliabilityConfigSettingsOk() {
- configureReliabilityConfigSettings(5, 5 * 60 * 1000);
- }
-
- private void configureUpdateAppPackageOk(String updateAppPackageName) throws Exception {
- when(mMockConfigHelper.getUpdateAppPackageName()).thenReturn(updateAppPackageName);
- when(mMockPackageManagerHelper.isPrivilegedApp(updateAppPackageName)).thenReturn(true);
- }
-
- private void configureUpdateAppPackageNotPrivileged(String updateAppPackageName)
- throws Exception {
- when(mMockConfigHelper.getUpdateAppPackageName()).thenReturn(updateAppPackageName);
- when(mMockPackageManagerHelper.isPrivilegedApp(updateAppPackageName)).thenReturn(false);
- }
-
- private void configureUpdateAppPackageNameMissing() {
- when(mMockConfigHelper.getUpdateAppPackageName()).thenReturn(null);
- }
-
- private void configureDataAppPackageOk(String dataAppPackageName) throws Exception {
- when(mMockConfigHelper.getDataAppPackageName()).thenReturn(dataAppPackageName);
- when(mMockPackageManagerHelper.isPrivilegedApp(dataAppPackageName)).thenReturn(true);
- }
-
- private void configureDataAppPackageNotPrivileged(String dataAppPackageName)
- throws Exception {
- when(mMockConfigHelper.getUpdateAppPackageName()).thenReturn(dataAppPackageName);
- when(mMockPackageManagerHelper.isPrivilegedApp(dataAppPackageName)).thenReturn(false);
- }
-
- private void configureDataAppPackageNameMissing() {
- when(mMockConfigHelper.getDataAppPackageName()).thenThrow(new RuntimeException());
- }
-
- private void checkIntentHelperInitializedAndReliabilityTrackingEnabled() {
- // Verify that calling start initialized the IntentHelper as well.
- mFakeIntentHelper.assertInitialized(UPDATE_APP_PACKAGE_NAME, DATA_APP_PACKAGE_NAME);
-
- // Assert that reliability tracking is always enabled after initialization.
- mFakeIntentHelper.assertReliabilityTriggeringEnabled();
- }
-
- private void checkPackageStorageStatus(
- int expectedCheckStatus, PackageVersions expectedPackageVersions) {
- PackageStatus packageStatus = mPackageStatusStorage.getPackageStatus();
- assertEquals(expectedCheckStatus, packageStatus.mCheckStatus);
- assertEquals(expectedPackageVersions, packageStatus.mVersions);
- }
-
- private void checkPackageStorageStatusIsInitialOrReset() {
- assertNull(mPackageStatusStorage.getPackageStatus());
- }
-
- private static CheckToken createArbitraryCheckToken() {
- return new CheckToken(1, INITIAL_APP_PACKAGE_VERSIONS);
- }
-
- /**
- * A fake IntentHelper implementation for use in tests.
- */
- private static class FakeIntentHelper implements IntentHelper {
-
- private Listener mListener;
- private String mUpdateAppPackageName;
- private String mDataAppPackageName;
-
- private CheckToken mLastToken;
-
- private boolean mReliabilityTriggeringEnabled;
-
- @Override
- public void initialize(String updateAppPackageName, String dataAppPackageName,
- Listener listener) {
- assertNotNull(updateAppPackageName);
- assertNotNull(dataAppPackageName);
- assertNotNull(listener);
- mListener = listener;
- mUpdateAppPackageName = updateAppPackageName;
- mDataAppPackageName = dataAppPackageName;
- }
-
- public void assertInitialized(
- String expectedUpdateAppPackageName, String expectedDataAppPackageName) {
- assertNotNull(mListener);
- assertEquals(expectedUpdateAppPackageName, mUpdateAppPackageName);
- assertEquals(expectedDataAppPackageName, mDataAppPackageName);
- }
-
- public void assertNotInitialized() {
- assertNull(mListener);
- }
-
- @Override
- public void sendTriggerUpdateCheck(CheckToken checkToken) {
- if (mLastToken != null) {
- fail("lastToken already set");
- }
- mLastToken = checkToken;
- }
-
- @Override
- public void enableReliabilityTriggering() {
- mReliabilityTriggeringEnabled = true;
- }
-
- @Override
- public void disableReliabilityTriggering() {
- mReliabilityTriggeringEnabled = false;
- }
-
- public void assertReliabilityTriggeringEnabled() {
- assertTrue(mReliabilityTriggeringEnabled);
- }
-
- public void assertReliabilityTriggeringDisabled() {
- assertFalse(mReliabilityTriggeringEnabled);
- }
-
- public void assertUpdateTriggered() {
- assertNotNull(mLastToken);
- }
-
- public void assertUpdateNotTriggered() {
- assertNull(mLastToken);
- }
-
- public CheckToken captureAndResetLastToken() {
- CheckToken toReturn = mLastToken;
- assertNotNull("No update triggered", toReturn);
- mLastToken = null;
- return toReturn;
- }
-
- public void simulatePackageUpdatedEvent() {
- mListener.triggerUpdateIfNeeded(true);
- }
-
- public void simulateReliabilityTrigger() {
- mListener.triggerUpdateIfNeeded(false);
- }
- }
-
- private static class FakeClockHelper implements ClockHelper {
-
- private long currentTime = 1000;
-
- @Override
- public long currentTimestamp() {
- return currentTime;
- }
-
- public void incrementClock(long millis) {
- currentTime += millis;
- }
- }
-
- /**
- * Registers a mockito parameter matcher that uses {@link Intent#filterEquals(Intent)}. to
- * check the parameter against the intent supplied.
- */
- private static Intent filterEquals(final Intent expected) {
- final Matcher<Intent> m = new BaseMatcher<Intent>() {
- @Override
- public boolean matches(Object actual) {
- return actual != null && expected.filterEquals((Intent) actual);
- }
- @Override
- public void describeTo(Description description) {
- description.appendText(expected.toString());
- }
- };
- return argThat(m);
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/timezone/PackageVersionsTest.java b/services/tests/servicestests/src/com/android/server/timezone/PackageVersionsTest.java
deleted file mode 100644
index a470f8f6c230..000000000000
--- a/services/tests/servicestests/src/com/android/server/timezone/PackageVersionsTest.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.timezone;
-
-import org.junit.Test;
-
-import android.support.test.filters.SmallTest;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-
-@SmallTest
-public class PackageVersionsTest {
-
- @Test
- public void equals() {
- PackageVersions baseline =
- new PackageVersions(1 /* updateAppVersion */, 1 /* dataAppVersion */);
- assertEquals(baseline, baseline);
-
- PackageVersions deepEqual =
- new PackageVersions(1 /* updateAppVersion */, 1 /* dataAppVersion */);
- assertEquals(baseline, deepEqual);
-
- PackageVersions differentUpdateAppVersion =
- new PackageVersions(2 /* updateAppVersion */, 1 /* dataAppVersion */);
- assertFalse(baseline.equals(differentUpdateAppVersion));
-
- PackageVersions differentDataAppVersion =
- new PackageVersions(1 /* updateAppVersion */, 2 /* dataAppVersion */);
- assertFalse(baseline.equals(differentDataAppVersion));
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java
deleted file mode 100644
index a7f4c9947482..000000000000
--- a/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java
+++ /dev/null
@@ -1,924 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.timezone;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import android.app.timezone.Callback;
-import android.app.timezone.DistroRulesVersion;
-import android.app.timezone.ICallback;
-import android.app.timezone.RulesManager;
-import android.app.timezone.RulesState;
-import android.os.ParcelFileDescriptor;
-
-import java.io.IOException;
-import java.util.concurrent.Executor;
-import javax.annotation.Nullable;
-import libcore.tzdata.shared2.DistroVersion;
-import libcore.tzdata.shared2.StagedDistroOperation;
-import libcore.tzdata.update2.TimeZoneDistroInstaller;
-
-import static com.android.server.timezone.RulesManagerService.REQUIRED_UPDATER_PERMISSION;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-/**
- * White box interaction / unit testing of the {@link RulesManagerService}.
- */
-public class RulesManagerServiceTest {
-
- private RulesManagerService mRulesManagerService;
-
- private FakeExecutor mFakeExecutor;
- private PermissionHelper mMockPermissionHelper;
- private FileDescriptorHelper mMockFileDescriptorHelper;
- private PackageTracker mMockPackageTracker;
- private TimeZoneDistroInstaller mMockTimeZoneDistroInstaller;
-
- @Before
- public void setUp() {
- mFakeExecutor = new FakeExecutor();
-
- mMockFileDescriptorHelper = mock(FileDescriptorHelper.class);
- mMockPackageTracker = mock(PackageTracker.class);
- mMockPermissionHelper = mock(PermissionHelper.class);
- mMockTimeZoneDistroInstaller = mock(TimeZoneDistroInstaller.class);
-
- mRulesManagerService = new RulesManagerService(
- mMockPermissionHelper,
- mFakeExecutor,
- mMockFileDescriptorHelper,
- mMockPackageTracker,
- mMockTimeZoneDistroInstaller);
- }
-
- @Test(expected = SecurityException.class)
- public void getRulesState_noCallerPermission() throws Exception {
- configureCallerDoesNotHavePermission();
- mRulesManagerService.getRulesState();
- }
-
- @Test(expected = SecurityException.class)
- public void requestInstall_noCallerPermission() throws Exception {
- configureCallerDoesNotHavePermission();
- mRulesManagerService.requestInstall(null, null, null);
- }
-
- @Test(expected = SecurityException.class)
- public void requestUninstall_noCallerPermission() throws Exception {
- configureCallerDoesNotHavePermission();
- mRulesManagerService.requestUninstall(null, null);
- }
-
- @Test(expected = SecurityException.class)
- public void requestNothing_noCallerPermission() throws Exception {
- configureCallerDoesNotHavePermission();
- mRulesManagerService.requestNothing(null, true);
- }
-
- @Test
- public void getRulesState_systemRulesError() throws Exception {
- configureDeviceCannotReadSystemRulesVersion();
-
- assertNull(mRulesManagerService.getRulesState());
- }
-
- @Test
- public void getRulesState_stagedInstall() throws Exception {
- configureCallerHasPermission();
-
- configureDeviceSystemRulesVersion("2016a");
-
- DistroVersion stagedDistroVersion = new DistroVersion(
- DistroVersion.CURRENT_FORMAT_MAJOR_VERSION,
- DistroVersion.CURRENT_FORMAT_MINOR_VERSION - 1,
- "2016c",
- 3);
- configureStagedInstall(stagedDistroVersion);
-
- DistroVersion installedDistroVersion = new DistroVersion(
- DistroVersion.CURRENT_FORMAT_MAJOR_VERSION,
- DistroVersion.CURRENT_FORMAT_MINOR_VERSION - 1,
- "2016b",
- 4);
- configureInstalledDistroVersion(installedDistroVersion);
-
- DistroRulesVersion stagedDistroRulesVersion = new DistroRulesVersion(
- stagedDistroVersion.rulesVersion, stagedDistroVersion.revision);
- DistroRulesVersion installedDistroRulesVersion = new DistroRulesVersion(
- installedDistroVersion.rulesVersion, installedDistroVersion.revision);
- RulesState expectedRuleState = new RulesState(
- "2016a", RulesManagerService.DISTRO_FORMAT_VERSION_SUPPORTED,
- false /* operationInProgress */,
- RulesState.STAGED_OPERATION_INSTALL, stagedDistroRulesVersion,
- RulesState.DISTRO_STATUS_INSTALLED, installedDistroRulesVersion);
- assertEquals(expectedRuleState, mRulesManagerService.getRulesState());
- }
-
- @Test
- public void getRulesState_nothingStaged() throws Exception {
- configureCallerHasPermission();
-
- configureDeviceSystemRulesVersion("2016a");
-
- configureNoStagedOperation();
-
- DistroVersion installedDistroVersion = new DistroVersion(
- DistroVersion.CURRENT_FORMAT_MAJOR_VERSION,
- DistroVersion.CURRENT_FORMAT_MINOR_VERSION - 1,
- "2016b",
- 4);
- configureInstalledDistroVersion(installedDistroVersion);
-
- DistroRulesVersion installedDistroRulesVersion = new DistroRulesVersion(
- installedDistroVersion.rulesVersion, installedDistroVersion.revision);
- RulesState expectedRuleState = new RulesState(
- "2016a", RulesManagerService.DISTRO_FORMAT_VERSION_SUPPORTED,
- false /* operationInProgress */,
- RulesState.STAGED_OPERATION_NONE, null /* stagedDistroRulesVersion */,
- RulesState.DISTRO_STATUS_INSTALLED, installedDistroRulesVersion);
- assertEquals(expectedRuleState, mRulesManagerService.getRulesState());
- }
-
- @Test
- public void getRulesState_uninstallStaged() throws Exception {
- configureCallerHasPermission();
-
- configureDeviceSystemRulesVersion("2016a");
-
- configureStagedUninstall();
-
- DistroVersion installedDistroVersion = new DistroVersion(
- DistroVersion.CURRENT_FORMAT_MAJOR_VERSION,
- DistroVersion.CURRENT_FORMAT_MINOR_VERSION - 1,
- "2016b",
- 4);
- configureInstalledDistroVersion(installedDistroVersion);
-
- DistroRulesVersion installedDistroRulesVersion = new DistroRulesVersion(
- installedDistroVersion.rulesVersion, installedDistroVersion.revision);
- RulesState expectedRuleState = new RulesState(
- "2016a", RulesManagerService.DISTRO_FORMAT_VERSION_SUPPORTED,
- false /* operationInProgress */,
- RulesState.STAGED_OPERATION_UNINSTALL, null /* stagedDistroRulesVersion */,
- RulesState.DISTRO_STATUS_INSTALLED, installedDistroRulesVersion);
- assertEquals(expectedRuleState, mRulesManagerService.getRulesState());
- }
-
- @Test
- public void getRulesState_installedRulesError() throws Exception {
- configureCallerHasPermission();
-
- String systemRulesVersion = "2016a";
- configureDeviceSystemRulesVersion(systemRulesVersion);
-
- configureStagedUninstall();
- configureDeviceCannotReadInstalledDistroVersion();
-
- RulesState expectedRuleState = new RulesState(
- "2016a", RulesManagerService.DISTRO_FORMAT_VERSION_SUPPORTED,
- false /* operationInProgress */,
- RulesState.STAGED_OPERATION_UNINSTALL, null /* stagedDistroRulesVersion */,
- RulesState.DISTRO_STATUS_UNKNOWN, null /* installedDistroRulesVersion */);
- assertEquals(expectedRuleState, mRulesManagerService.getRulesState());
- }
-
- @Test
- public void getRulesState_stagedRulesError() throws Exception {
- configureCallerHasPermission();
-
- String systemRulesVersion = "2016a";
- configureDeviceSystemRulesVersion(systemRulesVersion);
-
- configureDeviceCannotReadStagedDistroOperation();
-
- DistroVersion installedDistroVersion = new DistroVersion(
- DistroVersion.CURRENT_FORMAT_MAJOR_VERSION,
- DistroVersion.CURRENT_FORMAT_MINOR_VERSION - 1,
- "2016b",
- 4);
- configureInstalledDistroVersion(installedDistroVersion);
-
- DistroRulesVersion installedDistroRulesVersion = new DistroRulesVersion(
- installedDistroVersion.rulesVersion, installedDistroVersion.revision);
- RulesState expectedRuleState = new RulesState(
- "2016a", RulesManagerService.DISTRO_FORMAT_VERSION_SUPPORTED,
- false /* operationInProgress */,
- RulesState.STAGED_OPERATION_UNKNOWN, null /* stagedDistroRulesVersion */,
- RulesState.DISTRO_STATUS_INSTALLED, installedDistroRulesVersion);
- assertEquals(expectedRuleState, mRulesManagerService.getRulesState());
- }
-
- @Test
- public void getRulesState_noInstalledRules() throws Exception {
- configureCallerHasPermission();
-
- String systemRulesVersion = "2016a";
- configureDeviceSystemRulesVersion(systemRulesVersion);
- configureNoStagedOperation();
- configureInstalledDistroVersion(null);
-
- RulesState expectedRuleState = new RulesState(
- systemRulesVersion, RulesManagerService.DISTRO_FORMAT_VERSION_SUPPORTED,
- false /* operationInProgress */,
- RulesState.STAGED_OPERATION_NONE, null /* stagedDistroRulesVersion */,
- RulesState.DISTRO_STATUS_NONE, null /* installedDistroRulesVersion */);
- assertEquals(expectedRuleState, mRulesManagerService.getRulesState());
- }
-
- @Test
- public void getRulesState_operationInProgress() throws Exception {
- configureCallerHasPermission();
-
- String systemRulesVersion = "2016a";
- String installedRulesVersion = "2016b";
- int revision = 3;
-
- configureDeviceSystemRulesVersion(systemRulesVersion);
-
- DistroVersion installedDistroVersion = new DistroVersion(
- DistroVersion.CURRENT_FORMAT_MAJOR_VERSION,
- DistroVersion.CURRENT_FORMAT_MINOR_VERSION - 1,
- installedRulesVersion,
- revision);
- configureInstalledDistroVersion(installedDistroVersion);
-
- byte[] expectedContent = createArbitraryBytes(1000);
- ParcelFileDescriptor parcelFileDescriptor = createFakeParcelFileDescriptor();
- configureParcelFileDescriptorReadSuccess(parcelFileDescriptor, expectedContent);
-
- // Start an async operation so there is one in progress. The mFakeExecutor won't actually
- // execute it.
- byte[] tokenBytes = createArbitraryTokenBytes();
- ICallback callback = new StubbedCallback();
-
- mRulesManagerService.requestInstall(parcelFileDescriptor, tokenBytes, callback);
-
- RulesState expectedRuleState = new RulesState(
- systemRulesVersion, RulesManagerService.DISTRO_FORMAT_VERSION_SUPPORTED,
- true /* operationInProgress */,
- RulesState.STAGED_OPERATION_UNKNOWN, null /* stagedDistroRulesVersion */,
- RulesState.DISTRO_STATUS_UNKNOWN, null /* installedDistroRulesVersion */);
- assertEquals(expectedRuleState, mRulesManagerService.getRulesState());
- }
-
- @Test
- public void requestInstall_operationInProgress() throws Exception {
- configureCallerHasPermission();
-
- byte[] expectedContent = createArbitraryBytes(1000);
- ParcelFileDescriptor parcelFileDescriptor = createFakeParcelFileDescriptor();
- configureParcelFileDescriptorReadSuccess(parcelFileDescriptor, expectedContent);
-
- byte[] tokenBytes = createArbitraryTokenBytes();
- ICallback callback = new StubbedCallback();
-
- // First request should succeed.
- assertEquals(RulesManager.SUCCESS,
- mRulesManagerService.requestInstall(parcelFileDescriptor, tokenBytes, callback));
-
- // Something async should be enqueued. Clear it but do not execute it so we can detect the
- // second request does nothing.
- mFakeExecutor.getAndResetLastCommand();
-
- // Second request should fail.
- assertEquals(RulesManager.ERROR_OPERATION_IN_PROGRESS,
- mRulesManagerService.requestInstall(parcelFileDescriptor, tokenBytes, callback));
-
- // Assert nothing async was enqueued.
- mFakeExecutor.assertNothingQueued();
- verifyNoInstallerCallsMade();
- verifyNoPackageTrackerCallsMade();
- }
-
- @Test
- public void requestInstall_badToken() throws Exception {
- configureCallerHasPermission();
-
- byte[] expectedContent = createArbitraryBytes(1000);
- ParcelFileDescriptor parcelFileDescriptor = createFakeParcelFileDescriptor();
- configureParcelFileDescriptorReadSuccess(parcelFileDescriptor, expectedContent);
-
- byte[] badTokenBytes = new byte[2];
- ICallback callback = new StubbedCallback();
-
- try {
- mRulesManagerService.requestInstall(parcelFileDescriptor, badTokenBytes, callback);
- fail();
- } catch (IllegalArgumentException expected) {
- }
-
- // Assert nothing async was enqueued.
- mFakeExecutor.assertNothingQueued();
- verifyNoInstallerCallsMade();
- verifyNoPackageTrackerCallsMade();
- }
-
- @Test
- public void requestInstall_nullParcelFileDescriptor() throws Exception {
- configureCallerHasPermission();
-
- ParcelFileDescriptor parcelFileDescriptor = null;
- byte[] tokenBytes = createArbitraryTokenBytes();
- ICallback callback = new StubbedCallback();
-
- try {
- mRulesManagerService.requestInstall(parcelFileDescriptor, tokenBytes, callback);
- fail();
- } catch (NullPointerException expected) {}
-
- // Assert nothing async was enqueued.
- mFakeExecutor.assertNothingQueued();
- verifyNoInstallerCallsMade();
- verifyNoPackageTrackerCallsMade();
- }
-
- @Test
- public void requestInstall_nullCallback() throws Exception {
- configureCallerHasPermission();
-
- ParcelFileDescriptor parcelFileDescriptor = createFakeParcelFileDescriptor();
- byte[] tokenBytes = createArbitraryTokenBytes();
- ICallback callback = null;
-
- try {
- mRulesManagerService.requestInstall(parcelFileDescriptor, tokenBytes, callback);
- fail();
- } catch (NullPointerException expected) {}
-
- // Assert nothing async was enqueued.
- mFakeExecutor.assertNothingQueued();
- verifyNoInstallerCallsMade();
- verifyNoPackageTrackerCallsMade();
- }
-
- @Test
- public void requestInstall_asyncSuccess() throws Exception {
- configureCallerHasPermission();
-
- ParcelFileDescriptor parcelFileDescriptor = createFakeParcelFileDescriptor();
- byte[] expectedContent = createArbitraryBytes(1000);
- configureParcelFileDescriptorReadSuccess(parcelFileDescriptor, expectedContent);
-
- CheckToken token = createArbitraryToken();
- byte[] tokenBytes = token.toByteArray();
-
- TestCallback callback = new TestCallback();
-
- // Request the install.
- assertEquals(RulesManager.SUCCESS,
- mRulesManagerService.requestInstall(parcelFileDescriptor, tokenBytes, callback));
-
- // Assert nothing has happened yet.
- callback.assertNoResultReceived();
- verifyNoInstallerCallsMade();
- verifyNoPackageTrackerCallsMade();
-
- // Set up the installer.
- configureStageInstallExpectation(expectedContent, TimeZoneDistroInstaller.INSTALL_SUCCESS);
-
- // Simulate the async execution.
- mFakeExecutor.simulateAsyncExecutionOfLastCommand();
-
- // Verify the expected calls were made to other components.
- verifyStageInstallCalled(expectedContent);
- verifyPackageTrackerCalled(token, true /* success */);
-
- // Check the callback was called.
- callback.assertResultReceived(Callback.SUCCESS);
- }
-
- @Test
- public void requestInstall_nullTokenBytes() throws Exception {
- configureCallerHasPermission();
-
- ParcelFileDescriptor parcelFileDescriptor = createFakeParcelFileDescriptor();
- byte[] expectedContent = createArbitraryBytes(1000);
- configureParcelFileDescriptorReadSuccess(parcelFileDescriptor, expectedContent);
-
- TestCallback callback = new TestCallback();
-
- // Request the install.
- assertEquals(RulesManager.SUCCESS,
- mRulesManagerService.requestInstall(
- parcelFileDescriptor, null /* tokenBytes */, callback));
-
- // Assert nothing has happened yet.
- verifyNoInstallerCallsMade();
- callback.assertNoResultReceived();
-
- // Set up the installer.
- configureStageInstallExpectation(expectedContent, TimeZoneDistroInstaller.INSTALL_SUCCESS);
-
- // Simulate the async execution.
- mFakeExecutor.simulateAsyncExecutionOfLastCommand();
-
- // Verify the expected calls were made to other components.
- verifyStageInstallCalled(expectedContent);
- verifyPackageTrackerCalled(null /* expectedToken */, true /* success */);
-
- // Check the callback was received.
- callback.assertResultReceived(Callback.SUCCESS);
- }
-
- @Test
- public void requestInstall_asyncInstallFail() throws Exception {
- configureCallerHasPermission();
-
- byte[] expectedContent = createArbitraryBytes(1000);
- ParcelFileDescriptor parcelFileDescriptor = createFakeParcelFileDescriptor();
- configureParcelFileDescriptorReadSuccess(parcelFileDescriptor, expectedContent);
-
- CheckToken token = createArbitraryToken();
- byte[] tokenBytes = token.toByteArray();
-
- TestCallback callback = new TestCallback();
-
- // Request the install.
- assertEquals(RulesManager.SUCCESS,
- mRulesManagerService.requestInstall(parcelFileDescriptor, tokenBytes, callback));
-
- // Assert nothing has happened yet.
- verifyNoInstallerCallsMade();
- callback.assertNoResultReceived();
-
- // Set up the installer.
- configureStageInstallExpectation(
- expectedContent, TimeZoneDistroInstaller.INSTALL_FAIL_VALIDATION_ERROR);
-
- // Simulate the async execution.
- mFakeExecutor.simulateAsyncExecutionOfLastCommand();
-
- // Verify the expected calls were made to other components.
- verifyStageInstallCalled(expectedContent);
-
- // Validation failure is treated like a successful check: repeating it won't improve things.
- boolean expectedSuccess = true;
- verifyPackageTrackerCalled(token, expectedSuccess);
-
- // Check the callback was received.
- callback.assertResultReceived(Callback.ERROR_INSTALL_VALIDATION_ERROR);
- }
-
- @Test
- public void requestInstall_asyncParcelFileDescriptorReadFail() throws Exception {
- configureCallerHasPermission();
-
- ParcelFileDescriptor parcelFileDescriptor = createFakeParcelFileDescriptor();
- configureParcelFileDescriptorReadFailure(parcelFileDescriptor);
-
- CheckToken token = createArbitraryToken();
- byte[] tokenBytes = token.toByteArray();
-
- TestCallback callback = new TestCallback();
-
- // Request the install.
- assertEquals(RulesManager.SUCCESS,
- mRulesManagerService.requestInstall(parcelFileDescriptor, tokenBytes, callback));
-
- // Simulate the async execution.
- mFakeExecutor.simulateAsyncExecutionOfLastCommand();
-
- // Verify nothing else happened.
- verifyNoInstallerCallsMade();
-
- // A failure to read the ParcelFileDescriptor is treated as a failure. It might be the
- // result of a file system error. This is a fairly arbitrary choice.
- verifyPackageTrackerCalled(token, false /* success */);
-
- verifyNoPackageTrackerCallsMade();
-
- // Check the callback was received.
- callback.assertResultReceived(Callback.ERROR_UNKNOWN_FAILURE);
- }
-
- @Test
- public void requestUninstall_operationInProgress() throws Exception {
- configureCallerHasPermission();
-
- byte[] tokenBytes = createArbitraryTokenBytes();
- ICallback callback = new StubbedCallback();
-
- // First request should succeed.
- assertEquals(RulesManager.SUCCESS,
- mRulesManagerService.requestUninstall(tokenBytes, callback));
-
- // Something async should be enqueued. Clear it but do not execute it so we can detect the
- // second request does nothing.
- mFakeExecutor.getAndResetLastCommand();
-
- // Second request should fail.
- assertEquals(RulesManager.ERROR_OPERATION_IN_PROGRESS,
- mRulesManagerService.requestUninstall(tokenBytes, callback));
-
- // Assert nothing async was enqueued.
- mFakeExecutor.assertNothingQueued();
- verifyNoInstallerCallsMade();
- verifyNoPackageTrackerCallsMade();
- }
-
- @Test
- public void requestUninstall_badToken() throws Exception {
- configureCallerHasPermission();
-
- byte[] badTokenBytes = new byte[2];
- ICallback callback = new StubbedCallback();
-
- try {
- mRulesManagerService.requestUninstall(badTokenBytes, callback);
- fail();
- } catch (IllegalArgumentException expected) {
- }
-
- // Assert nothing async was enqueued.
- mFakeExecutor.assertNothingQueued();
- verifyNoInstallerCallsMade();
- verifyNoPackageTrackerCallsMade();
- }
-
- @Test
- public void requestUninstall_nullCallback() throws Exception {
- configureCallerHasPermission();
-
- byte[] tokenBytes = createArbitraryTokenBytes();
- ICallback callback = null;
-
- try {
- mRulesManagerService.requestUninstall(tokenBytes, callback);
- fail();
- } catch (NullPointerException expected) {}
-
- // Assert nothing async was enqueued.
- mFakeExecutor.assertNothingQueued();
- verifyNoInstallerCallsMade();
- verifyNoPackageTrackerCallsMade();
- }
-
- @Test
- public void requestUninstall_asyncSuccess() throws Exception {
- configureCallerHasPermission();
-
- CheckToken token = createArbitraryToken();
- byte[] tokenBytes = token.toByteArray();
-
- TestCallback callback = new TestCallback();
-
- // Request the uninstall.
- assertEquals(RulesManager.SUCCESS,
- mRulesManagerService.requestUninstall(tokenBytes, callback));
-
- // Assert nothing has happened yet.
- callback.assertNoResultReceived();
- verifyNoInstallerCallsMade();
- verifyNoPackageTrackerCallsMade();
-
- // Set up the installer.
- configureStageUninstallExpectation(true /* success */);
-
- // Simulate the async execution.
- mFakeExecutor.simulateAsyncExecutionOfLastCommand();
-
- // Verify the expected calls were made to other components.
- verifyStageUninstallCalled();
- verifyPackageTrackerCalled(token, true /* success */);
-
- // Check the callback was called.
- callback.assertResultReceived(Callback.SUCCESS);
- }
-
- @Test
- public void requestUninstall_nullTokenBytes() throws Exception {
- configureCallerHasPermission();
-
- TestCallback callback = new TestCallback();
-
- // Request the uninstall.
- assertEquals(RulesManager.SUCCESS,
- mRulesManagerService.requestUninstall(null /* tokenBytes */, callback));
-
- // Assert nothing has happened yet.
- verifyNoInstallerCallsMade();
- callback.assertNoResultReceived();
-
- // Set up the installer.
- configureStageUninstallExpectation(true /* success */);
-
- // Simulate the async execution.
- mFakeExecutor.simulateAsyncExecutionOfLastCommand();
-
- // Verify the expected calls were made to other components.
- verifyStageUninstallCalled();
- verifyPackageTrackerCalled(null /* expectedToken */, true /* success */);
-
- // Check the callback was received.
- callback.assertResultReceived(Callback.SUCCESS);
- }
-
- @Test
- public void requestUninstall_asyncUninstallFail() throws Exception {
- configureCallerHasPermission();
-
- CheckToken token = createArbitraryToken();
- byte[] tokenBytes = token.toByteArray();
-
- TestCallback callback = new TestCallback();
-
- // Request the uninstall.
- assertEquals(RulesManager.SUCCESS,
- mRulesManagerService.requestUninstall(tokenBytes, callback));
-
- // Assert nothing has happened yet.
- verifyNoInstallerCallsMade();
- callback.assertNoResultReceived();
-
- // Set up the installer.
- configureStageUninstallExpectation(false /* success */);
-
- // Simulate the async execution.
- mFakeExecutor.simulateAsyncExecutionOfLastCommand();
-
- // Verify the expected calls were made to other components.
- verifyStageUninstallCalled();
- verifyPackageTrackerCalled(token, false /* success */);
-
- // Check the callback was received.
- callback.assertResultReceived(Callback.ERROR_UNKNOWN_FAILURE);
- }
-
- @Test
- public void requestNothing_operationInProgressOk() throws Exception {
- configureCallerHasPermission();
-
- // Set up a parallel operation.
- assertEquals(RulesManager.SUCCESS,
- mRulesManagerService.requestUninstall(null, new StubbedCallback()));
- // Something async should be enqueued. Clear it but do not execute it to simulate it still
- // being in progress.
- mFakeExecutor.getAndResetLastCommand();
-
- CheckToken token = createArbitraryToken();
- byte[] tokenBytes = token.toByteArray();
-
- // Make the call.
- mRulesManagerService.requestNothing(tokenBytes, true /* success */);
-
- // Assert nothing async was enqueued.
- mFakeExecutor.assertNothingQueued();
-
- // Verify the expected calls were made to other components.
- verifyPackageTrackerCalled(token, true /* success */);
- verifyNoInstallerCallsMade();
- }
-
- @Test
- public void requestNothing_badToken() throws Exception {
- configureCallerHasPermission();
-
- byte[] badTokenBytes = new byte[2];
-
- try {
- mRulesManagerService.requestNothing(badTokenBytes, true /* success */);
- fail();
- } catch (IllegalArgumentException expected) {
- }
-
- // Assert nothing async was enqueued.
- mFakeExecutor.assertNothingQueued();
-
- // Assert no other calls were made.
- verifyNoInstallerCallsMade();
- verifyNoPackageTrackerCallsMade();
- }
-
- @Test
- public void requestNothing() throws Exception {
- configureCallerHasPermission();
-
- CheckToken token = createArbitraryToken();
- byte[] tokenBytes = token.toByteArray();
-
- // Make the call.
- mRulesManagerService.requestNothing(tokenBytes, false /* success */);
-
- // Assert everything required was done.
- verifyNoInstallerCallsMade();
- verifyPackageTrackerCalled(token, false /* success */);
- }
-
- @Test
- public void requestNothing_nullTokenBytes() throws Exception {
- configureCallerHasPermission();
-
- // Make the call.
- mRulesManagerService.requestNothing(null /* tokenBytes */, true /* success */);
-
- // Assert everything required was done.
- verifyNoInstallerCallsMade();
- verifyPackageTrackerCalled(null /* token */, true /* success */);
- }
-
- private void verifyNoPackageTrackerCallsMade() {
- verifyNoMoreInteractions(mMockPackageTracker);
- reset(mMockPackageTracker);
- }
-
- private void verifyPackageTrackerCalled(
- CheckToken expectedCheckToken, boolean expectedSuccess) {
- verify(mMockPackageTracker).recordCheckResult(expectedCheckToken, expectedSuccess);
- reset(mMockPackageTracker);
- }
-
- private void configureCallerHasPermission() throws Exception {
- doNothing()
- .when(mMockPermissionHelper)
- .enforceCallerHasPermission(REQUIRED_UPDATER_PERMISSION);
- }
-
- private void configureCallerDoesNotHavePermission() {
- doThrow(new SecurityException("Simulated permission failure"))
- .when(mMockPermissionHelper)
- .enforceCallerHasPermission(REQUIRED_UPDATER_PERMISSION);
- }
-
- private void configureParcelFileDescriptorReadSuccess(ParcelFileDescriptor parcelFileDescriptor,
- byte[] content) throws Exception {
- when(mMockFileDescriptorHelper.readFully(parcelFileDescriptor)).thenReturn(content);
- }
-
- private void configureParcelFileDescriptorReadFailure(ParcelFileDescriptor parcelFileDescriptor)
- throws Exception {
- when(mMockFileDescriptorHelper.readFully(parcelFileDescriptor))
- .thenThrow(new IOException("Simulated failure"));
- }
-
- private void configureStageInstallExpectation(byte[] expectedContent, int resultCode)
- throws Exception {
- when(mMockTimeZoneDistroInstaller.stageInstallWithErrorCode(eq(expectedContent)))
- .thenReturn(resultCode);
- }
-
- private void configureStageUninstallExpectation(boolean success) throws Exception {
- doReturn(success).when(mMockTimeZoneDistroInstaller).stageUninstall();
- }
-
- private void verifyStageInstallCalled(byte[] expectedContent) throws Exception {
- verify(mMockTimeZoneDistroInstaller).stageInstallWithErrorCode(eq(expectedContent));
- verifyNoMoreInteractions(mMockTimeZoneDistroInstaller);
- reset(mMockTimeZoneDistroInstaller);
- }
-
- private void verifyStageUninstallCalled() throws Exception {
- verify(mMockTimeZoneDistroInstaller).stageUninstall();
- verifyNoMoreInteractions(mMockTimeZoneDistroInstaller);
- reset(mMockTimeZoneDistroInstaller);
- }
-
- private void verifyNoInstallerCallsMade() {
- verifyNoMoreInteractions(mMockTimeZoneDistroInstaller);
- reset(mMockTimeZoneDistroInstaller);
- }
-
- private static byte[] createArbitraryBytes(int length) {
- byte[] bytes = new byte[length];
- for (int i = 0; i < length; i++) {
- bytes[i] = (byte) i;
- }
- return bytes;
- }
-
- private byte[] createArbitraryTokenBytes() {
- return createArbitraryToken().toByteArray();
- }
-
- private CheckToken createArbitraryToken() {
- return new CheckToken(1, new PackageVersions(1, 1));
- }
-
- private ParcelFileDescriptor createFakeParcelFileDescriptor() {
- return new ParcelFileDescriptor((ParcelFileDescriptor) null);
- }
-
- private void configureDeviceSystemRulesVersion(String systemRulesVersion) throws Exception {
- when(mMockTimeZoneDistroInstaller.getSystemRulesVersion()).thenReturn(systemRulesVersion);
- }
-
- private void configureInstalledDistroVersion(@Nullable DistroVersion installedDistroVersion)
- throws Exception {
- when(mMockTimeZoneDistroInstaller.getInstalledDistroVersion())
- .thenReturn(installedDistroVersion);
- }
-
- private void configureStagedInstall(DistroVersion stagedDistroVersion) throws Exception {
- when(mMockTimeZoneDistroInstaller.getStagedDistroOperation())
- .thenReturn(StagedDistroOperation.install(stagedDistroVersion));
- }
-
- private void configureStagedUninstall() throws Exception {
- when(mMockTimeZoneDistroInstaller.getStagedDistroOperation())
- .thenReturn(StagedDistroOperation.uninstall());
- }
-
- private void configureNoStagedOperation() throws Exception {
- when(mMockTimeZoneDistroInstaller.getStagedDistroOperation()).thenReturn(null);
- }
-
- private void configureDeviceCannotReadStagedDistroOperation() throws Exception {
- when(mMockTimeZoneDistroInstaller.getStagedDistroOperation())
- .thenThrow(new IOException("Simulated failure"));
- }
-
- private void configureDeviceCannotReadSystemRulesVersion() throws Exception {
- when(mMockTimeZoneDistroInstaller.getSystemRulesVersion())
- .thenThrow(new IOException("Simulated failure"));
- }
-
- private void configureDeviceCannotReadInstalledDistroVersion() throws Exception {
- when(mMockTimeZoneDistroInstaller.getInstalledDistroVersion())
- .thenThrow(new IOException("Simulated failure"));
- }
-
- private static class FakeExecutor implements Executor {
-
- private Runnable mLastCommand;
-
- @Override
- public void execute(Runnable command) {
- assertNull(mLastCommand);
- assertNotNull(command);
- mLastCommand = command;
- }
-
- public Runnable getAndResetLastCommand() {
- assertNotNull(mLastCommand);
- Runnable toReturn = mLastCommand;
- mLastCommand = null;
- return toReturn;
- }
-
- public void simulateAsyncExecutionOfLastCommand() {
- Runnable toRun = getAndResetLastCommand();
- toRun.run();
- }
-
- public void assertNothingQueued() {
- assertNull(mLastCommand);
- }
- }
-
- private static class TestCallback extends ICallback.Stub {
-
- private boolean mOnFinishedCalled;
- private int mLastError;
-
- @Override
- public void onFinished(int error) {
- assertFalse(mOnFinishedCalled);
- mOnFinishedCalled = true;
- mLastError = error;
- }
-
- public void assertResultReceived(int expectedResult) {
- assertTrue(mOnFinishedCalled);
- assertEquals(expectedResult, mLastError);
- }
-
- public void assertNoResultReceived() {
- assertFalse(mOnFinishedCalled);
- }
- }
-
- private static class StubbedCallback extends ICallback.Stub {
- @Override
- public void onFinished(int error) {
- fail("Unexpected call");
- }
- }
-}