diff options
Diffstat (limited to 'core/java')
| -rw-r--r-- | core/java/android/app/SystemServiceRegistry.java | 12 | ||||
| -rw-r--r-- | core/java/android/content/Context.java | 12 | ||||
| -rw-r--r-- | core/java/android/content/Intent.java | 28 | ||||
| -rw-r--r-- | core/java/android/content/pm/PackageInstaller.java | 10 | ||||
| -rw-r--r-- | core/java/android/content/pm/PackageManager.java | 11 | ||||
| -rw-r--r-- | core/java/android/content/pm/PackageManagerInternal.java | 44 | ||||
| -rw-r--r-- | core/java/android/content/rollback/IRollbackManager.aidl | 41 | ||||
| -rw-r--r-- | core/java/android/content/rollback/PackageRollbackInfo.aidl | 18 | ||||
| -rw-r--r-- | core/java/android/content/rollback/PackageRollbackInfo.java | 109 | ||||
| -rw-r--r-- | core/java/android/content/rollback/RollbackInfo.aidl | 18 | ||||
| -rw-r--r-- | core/java/android/content/rollback/RollbackInfo.java | 70 | ||||
| -rw-r--r-- | core/java/android/content/rollback/RollbackManager.java | 174 |
12 files changed, 547 insertions, 0 deletions
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index fb72f06e541f..3f6ebc8e63e9 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -49,6 +49,8 @@ import android.content.pm.LauncherApps; import android.content.pm.PackageManager; import android.content.pm.ShortcutManager; import android.content.res.Resources; +import android.content.rollback.IRollbackManager; +import android.content.rollback.RollbackManager; import android.debug.AdbManager; import android.debug.IAdbManager; import android.hardware.ConsumerIrManager; @@ -1169,6 +1171,16 @@ final class SystemServiceRegistry { throws ServiceNotFoundException { return new RoleManager(ctx.getOuterContext()); }}); + + registerService(Context.ROLLBACK_SERVICE, RollbackManager.class, + new CachedServiceFetcher<RollbackManager>() { + @Override + public RollbackManager createService(ContextImpl ctx) + throws ServiceNotFoundException { + IBinder b = ServiceManager.getServiceOrThrow(Context.ROLLBACK_SERVICE); + return new RollbackManager(ctx.getOuterContext(), + IRollbackManager.Stub.asInterface(b)); + }}); //CHECKSTYLE:ON IndentationCheck } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 5c9fced0f2cb..125c4c6b6503 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3123,6 +3123,7 @@ public abstract class Context { APPWIDGET_SERVICE, //@hide: VOICE_INTERACTION_MANAGER_SERVICE, //@hide: BACKUP_SERVICE, + ROLLBACK_SERVICE, DROPBOX_SERVICE, //@hide: DEVICE_IDLE_CONTROLLER, DEVICE_POLICY_SERVICE, @@ -4003,6 +4004,17 @@ public abstract class Context { public static final String BACKUP_SERVICE = "backup"; /** + * Use with {@link #getSystemService(String)} to retrieve an + * {@link android.content.rollback.RollbackManager} for communicating + * with the rollback manager + * + * @see #getSystemService(String) + * @hide TODO(ruhler): hidden, @TestApi until we decide on public vs. @SystemApi. + */ + @TestApi + public static final String ROLLBACK_SERVICE = "rollback"; + + /** * Use with {@link #getSystemService(String)} to retrieve a * {@link android.os.DropBoxManager} instance for recording * diagnostic logs. diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index d5c6c63243f6..1e3908c556af 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -27,6 +27,7 @@ import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; @@ -2248,6 +2249,32 @@ public class Intent implements Parcelable, Cloneable { @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED"; /** + * Broadcast Action: Sent to the system rollback manager when a package + * needs to have rollback enabled. + * <p class="note"> + * This is a protected intent that can only be sent by the system. + * </p> + * + * @hide This broadcast is used internally by the system. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_PACKAGE_ENABLE_ROLLBACK = + "android.intent.action.PACKAGE_ENABLE_ROLLBACK"; + /** + * Broadcast Action: An existing version of an application package has been + * rolled back to a previous version. + * The data contains the name of the package. + * + * <p class="note">This is a protected intent that can only be sent + * by the system. + * + * @hide TODO: hidden, @TestApi until we decide on public vs. @SystemApi. + */ + @TestApi + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_PACKAGE_ROLLBACK_EXECUTED = + "android.intent.action.PACKAGE_ROLLBACK_EXECUTED"; + /** * @hide * Broadcast Action: Ask system services if there is any reason to * restart the given package. The data contains the name of the @@ -10343,6 +10370,7 @@ public class Intent implements Parcelable, Cloneable { case ACTION_MEDIA_SCANNER_SCAN_FILE: case ACTION_PACKAGE_NEEDS_VERIFICATION: case ACTION_PACKAGE_VERIFIED: + case ACTION_PACKAGE_ENABLE_ROLLBACK: // Ignore legacy actions break; default: diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index f06df3d4dfba..a2fd83f9d8a0 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -24,6 +24,7 @@ import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; import android.app.AppGlobals; @@ -1425,6 +1426,15 @@ public class PackageInstaller { this.grantedRuntimePermissions = permissions; } + /** + * Request that rollbacks be enabled for the given upgrade. + * @hide TODO: hidden, @TestApi until we decide on public vs. @SystemApi. + */ + @TestApi + public void setEnableRollback() { + installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK; + } + /** {@hide} */ @SystemApi public void setAllowDowngrade(boolean allowDowngrade) { diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 9d604bbd75aa..260879625b01 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -720,6 +720,9 @@ public abstract class PackageManager { INSTALL_FORCE_SDK, INSTALL_FULL_APP, INSTALL_ALLOCATE_AGGRESSIVE, + INSTALL_VIRTUAL_PRELOAD, + INSTALL_APEX, + INSTALL_ENABLE_ROLLBACK, }) @Retention(RetentionPolicy.SOURCE) public @interface InstallFlags {} @@ -857,6 +860,14 @@ public abstract class PackageManager { */ public static final int INSTALL_APEX = 0x00020000; + /** + * Flag parameter for {@link #installPackage} to indicate that rollback + * should be enabled for this install. + * + * @hide + */ + public static final int INSTALL_ENABLE_ROLLBACK = 0x00040000; + /** @hide */ @IntDef(flag = true, prefix = { "DONT_KILL_APP" }, value = { DONT_KILL_APP diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java index 5db9f506e6e4..83979e925be1 100644 --- a/core/java/android/content/pm/PackageManagerInternal.java +++ b/core/java/android/content/pm/PackageManagerInternal.java @@ -759,4 +759,48 @@ public abstract class PackageManagerInternal { /** Returns whether the given package is enabled for the given user */ public abstract @PackageManager.EnabledState int getApplicationEnabledState( String packageName, int userId); + + /** + * Extra field name for the token of a request to enable rollback for a + * package. + */ + public static final String EXTRA_ENABLE_ROLLBACK_TOKEN = + "android.content.pm.extra.ENABLE_ROLLBACK_TOKEN"; + + /** + * Extra field name for the installFlags of a request to enable rollback + * for a package. + */ + public static final String EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS = + "android.content.pm.extra.ENABLE_ROLLBACK_INSTALL_FLAGS"; + + /** + * Used as the {@code enableRollbackCode} argument for + * {@link PackageManagerInternal#setEnableRollbackCode} to indicate that + * enabling rollback succeeded. + */ + public static final int ENABLE_ROLLBACK_SUCCEEDED = 1; + + /** + * Used as the {@code enableRollbackCode} argument for + * {@link PackageManagerInternal#setEnableRollbackCode} to indicate that + * enabling rollback failed. + */ + public static final int ENABLE_ROLLBACK_FAILED = -1; + + /** + * Allows the rollback manager listening to the + * {@link Intent#ACTION_PACKAGE_ENABLE_ROLLBACK enable rollback broadcast} + * to respond to the package manager. The response must include the + * {@code enableRollbackCode} which is one of + * {@link PackageManager#ENABLE_ROLLBACK_SUCCEEDED} or + * {@link PackageManager#ENABLE_ROLLBACK_FAILED}. + * + * @param token pending package identifier as passed via the + * {@link PackageManager#EXTRA_ENABLE_ROLLBACK_TOKEN} Intent extra. + * @param enableRollbackCode the status code result of enabling rollback + * @throws SecurityException if the caller does not have the + * PACKAGE_ROLLBACK_AGENT permission. + */ + public abstract void setEnableRollbackCode(int token, int enableRollbackCode); } diff --git a/core/java/android/content/rollback/IRollbackManager.aidl b/core/java/android/content/rollback/IRollbackManager.aidl new file mode 100644 index 000000000000..7f557cd8bbe8 --- /dev/null +++ b/core/java/android/content/rollback/IRollbackManager.aidl @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2018, 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.content.rollback; + +import android.content.pm.ParceledListSlice; +import android.content.pm.StringParceledListSlice; +import android.content.rollback.RollbackInfo; +import android.content.IntentSender; + +/** {@hide} */ +interface IRollbackManager { + + RollbackInfo getAvailableRollback(String packageName); + + StringParceledListSlice getPackagesWithAvailableRollbacks(); + + ParceledListSlice getRecentlyExecutedRollbacks(); + + void executeRollback(in RollbackInfo rollback, String callerPackageName, + in IntentSender statusReceiver); + + // Exposed for test purposes only. + void reloadPersistedData(); + + // Exposed for test purposes only. + void expireRollbackForPackage(String packageName); +} diff --git a/core/java/android/content/rollback/PackageRollbackInfo.aidl b/core/java/android/content/rollback/PackageRollbackInfo.aidl new file mode 100644 index 000000000000..9cb52c982754 --- /dev/null +++ b/core/java/android/content/rollback/PackageRollbackInfo.aidl @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2018 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.content.rollback; + +parcelable PackageRollbackInfo; diff --git a/core/java/android/content/rollback/PackageRollbackInfo.java b/core/java/android/content/rollback/PackageRollbackInfo.java new file mode 100644 index 000000000000..0c057656d59a --- /dev/null +++ b/core/java/android/content/rollback/PackageRollbackInfo.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2018 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.content.rollback; + +import android.annotation.TestApi; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * Information about a rollback available for a particular package. + * + * @hide TODO: hidden, @TestApi until we decide on public vs. @SystemApi. + */ +@TestApi +public final class PackageRollbackInfo implements Parcelable { + /** + * The name of a package being rolled back. + */ + public final String packageName; + + /** + * The version the package was rolled back from. + */ + public final PackageVersion higherVersion; + + /** + * The version the package was rolled back to. + */ + public final PackageVersion lowerVersion; + + /** + * Represents a version of a package. + */ + public static class PackageVersion { + public final long versionCode; + + // TODO(b/120200473): Include apk sha or some other way to distinguish + // between two different apks with the same version code. + public PackageVersion(long versionCode) { + this.versionCode = versionCode; + } + + @Override + public boolean equals(Object other) { + if (other instanceof PackageVersion) { + PackageVersion otherVersion = (PackageVersion) other; + return versionCode == otherVersion.versionCode; + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(versionCode); + } + } + + public PackageRollbackInfo(String packageName, + PackageVersion higherVersion, PackageVersion lowerVersion) { + this.packageName = packageName; + this.higherVersion = higherVersion; + this.lowerVersion = lowerVersion; + } + + private PackageRollbackInfo(Parcel in) { + this.packageName = in.readString(); + this.higherVersion = new PackageVersion(in.readLong()); + this.lowerVersion = new PackageVersion(in.readLong()); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeString(packageName); + out.writeLong(higherVersion.versionCode); + out.writeLong(lowerVersion.versionCode); + } + + public static final Parcelable.Creator<PackageRollbackInfo> CREATOR = + new Parcelable.Creator<PackageRollbackInfo>() { + public PackageRollbackInfo createFromParcel(Parcel in) { + return new PackageRollbackInfo(in); + } + + public PackageRollbackInfo[] newArray(int size) { + return new PackageRollbackInfo[size]; + } + }; +} diff --git a/core/java/android/content/rollback/RollbackInfo.aidl b/core/java/android/content/rollback/RollbackInfo.aidl new file mode 100644 index 000000000000..a9dc5cd59cbb --- /dev/null +++ b/core/java/android/content/rollback/RollbackInfo.aidl @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2018 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.content.rollback; + +parcelable RollbackInfo; diff --git a/core/java/android/content/rollback/RollbackInfo.java b/core/java/android/content/rollback/RollbackInfo.java new file mode 100644 index 000000000000..5fa4e57e78e5 --- /dev/null +++ b/core/java/android/content/rollback/RollbackInfo.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2018 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.content.rollback; + +import android.annotation.TestApi; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Information about a set of packages that can be, or already have been + * rolled back together. + * + * @hide TODO: hidden, @TestApi until we decide on public vs. @SystemApi. + */ +@TestApi +public final class RollbackInfo implements Parcelable { + + /** + * The package that needs to be rolled back. + */ + public final PackageRollbackInfo targetPackage; + + // TODO: Add a list of additional packages rolled back due to atomic + // install dependencies when rollback of atomic installs is supported. + // TODO: Add a flag to indicate if reboot is required, when rollback of + // staged installs is supported. + + public RollbackInfo(PackageRollbackInfo targetPackage) { + this.targetPackage = targetPackage; + } + + private RollbackInfo(Parcel in) { + this.targetPackage = PackageRollbackInfo.CREATOR.createFromParcel(in); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + targetPackage.writeToParcel(out, flags); + } + + public static final Parcelable.Creator<RollbackInfo> CREATOR = + new Parcelable.Creator<RollbackInfo>() { + public RollbackInfo createFromParcel(Parcel in) { + return new RollbackInfo(in); + } + + public RollbackInfo[] newArray(int size) { + return new RollbackInfo[size]; + } + }; +} diff --git a/core/java/android/content/rollback/RollbackManager.java b/core/java/android/content/rollback/RollbackManager.java new file mode 100644 index 000000000000..294151aff82c --- /dev/null +++ b/core/java/android/content/rollback/RollbackManager.java @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2018 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.content.rollback; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemService; +import android.annotation.TestApi; +import android.content.Context; +import android.content.IntentSender; +import android.os.RemoteException; + +import java.util.List; + +/** + * Offers the ability to rollback packages after upgrade. + * <p> + * For packages installed with rollbacks enabled, the RollbackManager can be + * used to initiate rollback of those packages for a limited time period after + * upgrade. + * + * TODO: Require an appropriate permission for apps to use these APIs. + * + * @see PackageInstaller.SessionParams#setEnableRollback() + * @hide TODO: hidden, @TestApi until we decide on public vs. @SystemApi. + */ +@TestApi +@SystemService(Context.ROLLBACK_SERVICE) +public final class RollbackManager { + private final String mCallerPackageName; + private final IRollbackManager mBinder; + + /** {@hide} */ + public RollbackManager(Context context, IRollbackManager binder) { + mCallerPackageName = context.getPackageName(); + mBinder = binder; + } + + /** + * Returns the rollback currently available to be executed for the given + * package. + * <p> + * The returned RollbackInfo describes what packages would be rolled back, + * including package version codes before and after rollback. The rollback + * can be initiated using {@link #executeRollback(RollbackInfo,IntentSender)}. + * <p> + * TODO: What if there is no package installed on device for packageName? + * + * @param packageName name of the package to get the availble RollbackInfo for. + * @return the rollback available for the package, or null if no rollback + * is available for the package. + */ + public @Nullable RollbackInfo getAvailableRollback(@NonNull String packageName) { + try { + return mBinder.getAvailableRollback(packageName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Gets the names of packages that are available for rollback. + * Call {@link #getAvailableRollback(String)} to get more information + * about the rollback available for a particular package. + * + * @return the names of packages that are available for rollback. + */ + public @NonNull List<String> getPackagesWithAvailableRollbacks() { + try { + return mBinder.getPackagesWithAvailableRollbacks().getList(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + + /** + * Gets the list of all recently executed rollbacks. + * This is for the purposes of preventing re-install of a bad version of a + * package. + * <p> + * Returns an empty list if there are no recently executed rollbacks. + * <p> + * To avoid having to keep around complete rollback history forever on a + * device, the returned list of rollbacks is only guaranteed to include + * rollbacks that are still relevant. A rollback is no longer considered + * relevant if the package is subsequently uninstalled or upgraded + * (without the possibility of rollback) to a higher version code than was + * rolled back from. + * + * @return the recently executed rollbacks + */ + public @NonNull List<RollbackInfo> getRecentlyExecutedRollbacks() { + try { + return mBinder.getRecentlyExecutedRollbacks().getList(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Execute the given rollback, rolling back all versions of the packages + * to the last good versions previously installed on the device as + * specified in the given rollback object. The rollback will fail if any + * of the installed packages or available rollbacks are inconsistent with + * the versions specified in the given rollback object, which can happen + * if a package has been updated or a rollback expired since the rollback + * object was retrieved from {@link #getAvailableRollback(String)}. + * <p> + * TODO: Specify the returns status codes. + * TODO: What happens in case reboot is required for the rollback to take + * effect for staged installs? + * + * @param rollback to execute + * @param statusReceiver where to deliver the results + */ + public void executeRollback(@NonNull RollbackInfo rollback, + @NonNull IntentSender statusReceiver) { + try { + mBinder.executeRollback(rollback, mCallerPackageName, statusReceiver); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Reload all persisted rollback data from device storage. + * This API is meant to test that rollback state is properly preserved + * across device reboot, by simulating what happens on reboot without + * actually rebooting the device. + * + * @hide + */ + @TestApi + public void reloadPersistedData() { + try { + mBinder.reloadPersistedData(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Expire the rollback data for a given package. + * This API is meant to facilitate testing of rollback logic for + * expiring rollback data. + * + * @param packageName the name of the package to expire data for. + * + * @hide + */ + @TestApi + public void expireRollbackForPackage(@NonNull String packageName) { + try { + mBinder.expireRollbackForPackage(packageName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } +} |
