diff options
author | TreeHugger Robot <treehugger-gerrit@google.com> | 2017-08-12 05:30:30 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2017-08-12 05:30:30 +0000 |
commit | 8193291ca36146af752dbd87e6fcab5274fd9b3d (patch) | |
tree | e2cc4afa98e15839777f095d09d07efdc12a77f6 | |
parent | a031b0d6a127a4db89e60397737b6f53dcb13a8b (diff) | |
parent | 3f0122b50feb749cabc7c54f0e3653df7b4a4223 (diff) | |
download | base-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"
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"); - } - } -} |