diff --git a/api/test-current.txt b/api/test-current.txt index 1ed4c4cb599dd..5eeac478fa309 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -694,6 +694,7 @@ package android.content.pm { method public void setEnableRollback(boolean); method @RequiresPermission("android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS") public void setGrantedRuntimePermissions(String[]); method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setInstallAsApex(); + method public void setRequestDowngrade(boolean); method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setStaged(); } @@ -795,6 +796,7 @@ package android.content.rollback { } public final class RollbackManager { + method @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS) public void blockRollbackManager(long); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) public void commitRollback(int, @NonNull java.util.List, @NonNull android.content.IntentSender); method @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS) public void expireRollbackForPackage(@NonNull String); method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) public java.util.List getAvailableRollbacks(); diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index a15caa09bb608..69ce3bd550712 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -1552,7 +1552,7 @@ public class PackageInstaller { } /** {@hide} */ - @SystemApi + @SystemApi @TestApi public void setRequestDowngrade(boolean requestDowngrade) { if (requestDowngrade) { installFlags |= PackageManager.INSTALL_REQUEST_DOWNGRADE; diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index a81d7ec915d4a..812ae93f06415 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -256,6 +256,8 @@ public class PackageParser { /** @hide */ public static final String APK_FILE_EXTENSION = ".apk"; + /** @hide */ + public static final String APEX_FILE_EXTENSION = ".apex"; /** @hide */ public static class NewPermissionInfo { diff --git a/core/java/android/content/rollback/IRollbackManager.aidl b/core/java/android/content/rollback/IRollbackManager.aidl index 1b84f2987a8f9..8c2a65faf8edb 100644 --- a/core/java/android/content/rollback/IRollbackManager.aidl +++ b/core/java/android/content/rollback/IRollbackManager.aidl @@ -24,7 +24,7 @@ import android.content.IntentSender; interface IRollbackManager { ParceledListSlice getAvailableRollbacks(); - ParceledListSlice getRecentlyExecutedRollbacks(); + ParceledListSlice getRecentlyCommittedRollbacks(); void commitRollback(int rollbackId, in ParceledListSlice causePackages, String callerPackageName, in IntentSender statusReceiver); @@ -51,4 +51,7 @@ interface IRollbackManager { // Used by the staging manager to notify the RollbackManager of the apk // session for a staged session. void notifyStagedApkSession(int originalSessionId, int apkSessionId); + + // For test purposes only. + void blockRollbackManager(long millis); } diff --git a/core/java/android/content/rollback/RollbackManager.java b/core/java/android/content/rollback/RollbackManager.java index 9a10a0c4766b8..73b8a48d9153c 100644 --- a/core/java/android/content/rollback/RollbackManager.java +++ b/core/java/android/content/rollback/RollbackManager.java @@ -114,7 +114,7 @@ public final class RollbackManager { }) public @NonNull List getRecentlyCommittedRollbacks() { try { - return mBinder.getRecentlyExecutedRollbacks().getList(); + return mBinder.getRecentlyCommittedRollbacks().getList(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -250,4 +250,25 @@ public final class RollbackManager { throw e.rethrowFromSystemServer(); } } + + /** + * Block the RollbackManager for a specified amount of time. + * This API is meant to facilitate testing of race conditions in + * RollbackManager. Blocks RollbackManager from processing anything for + * the given number of milliseconds. + * + * @param millis number of milliseconds to block the RollbackManager for + * @throws SecurityException if the caller does not have appropriate permissions. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS) + @TestApi + public void blockRollbackManager(long millis) { + try { + mBinder.blockRollbackManager(millis); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index b661a8553698c..7091c7ca73163 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -23,6 +23,7 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STOR import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR; import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK; import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SPLIT; +import static android.content.pm.PackageParser.APEX_FILE_EXTENSION; import static android.content.pm.PackageParser.APK_FILE_EXTENSION; import static android.system.OsConstants.O_CREAT; import static android.system.OsConstants.O_RDONLY; @@ -1484,7 +1485,29 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { "Too many files for apex install"); } - mResolvedBaseFile = addedFiles[0]; + try { + resolveStageDirLocked(); + } catch (IOException e) { + throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR, + "Failed to resolve stage location", e); + } + + File addedFile = addedFiles[0]; // there is only one file + + // Ensure file name has proper suffix + final String sourceName = addedFile.getName(); + final String targetName = sourceName.endsWith(APEX_FILE_EXTENSION) + ? sourceName + : sourceName + APEX_FILE_EXTENSION; + if (!FileUtils.isValidExtFilename(targetName)) { + throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, + "Invalid filename: " + targetName); + } + + final File targetFile = new File(mResolvedStageDir, targetName); + resolveAndStageFile(addedFile, targetFile); + + mResolvedBaseFile = targetFile; } /** diff --git a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java index 56e1d080a988c..f5f7d67ba0b11 100644 --- a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java +++ b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java @@ -20,7 +20,7 @@ import android.content.rollback.PackageRollbackInfo; import android.content.rollback.PackageRollbackInfo.RestoreInfo; import android.os.storage.StorageManager; import android.util.IntArray; -import android.util.Log; +import android.util.Slog; import android.util.SparseLongArray; import com.android.internal.annotations.VisibleForTesting; @@ -62,7 +62,7 @@ public class AppDataRollbackHelper { if (isUserCredentialLocked(user)) { // We've encountered a user that hasn't unlocked on a FBE device, so we can't copy // across app user data until the user unlocks their device. - Log.v(TAG, "User: " + user + " isn't unlocked, skipping CE userdata backup."); + Slog.v(TAG, "User: " + user + " isn't unlocked, skipping CE userdata backup."); storageFlags = Installer.FLAG_STORAGE_DE; packageRollbackInfo.addPendingBackup(user); } else { @@ -76,7 +76,7 @@ public class AppDataRollbackHelper { packageRollbackInfo.putCeSnapshotInode(user, ceSnapshotInode); } } catch (InstallerException ie) { - Log.e(TAG, "Unable to create app data snapshot for: " + Slog.e(TAG, "Unable to create app data snapshot for: " + packageRollbackInfo.getPackageName() + ", userId: " + user, ie); } } @@ -122,7 +122,7 @@ public class AppDataRollbackHelper { mInstaller.restoreAppDataSnapshot(packageRollbackInfo.getPackageName(), appId, seInfo, userId, rollbackId, storageFlags); } catch (InstallerException ie) { - Log.e(TAG, "Unable to restore app data snapshot: " + Slog.e(TAG, "Unable to restore app data snapshot: " + packageRollbackInfo.getPackageName(), ie); } @@ -148,7 +148,7 @@ public class AppDataRollbackHelper { ceSnapshotInodes.delete(user); } } catch (InstallerException ie) { - Log.e(TAG, "Unable to delete app data snapshot for " + Slog.e(TAG, "Unable to delete app data snapshot for " + packageRollbackInfo.getPackageName(), ie); } } @@ -257,7 +257,7 @@ public class AppDataRollbackHelper { info.putCeSnapshotInode(userId, ceSnapshotInode); pendingBackupUsers.remove(idx); } catch (InstallerException ie) { - Log.e(TAG, + Slog.e(TAG, "Unable to create app data snapshot for: " + info.getPackageName() + ", userId: " + userId, ie); } @@ -277,7 +277,7 @@ public class AppDataRollbackHelper { Installer.FLAG_STORAGE_CE); info.removeRestoreInfo(ri); } catch (InstallerException ie) { - Log.e(TAG, "Unable to restore app data snapshot for: " + Slog.e(TAG, "Unable to restore app data snapshot for: " + info.getPackageName(), ie); } } diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index 08c1bb536211c..cfa370bf63a33 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java @@ -45,14 +45,13 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.ParcelFileDescriptor; import android.os.Process; -import android.os.UserHandle; // duped to avoid merge conflict -import android.os.UserManager; // out of order to avoid merge conflict import android.os.SystemClock; import android.os.UserHandle; +import android.os.UserManager; import android.provider.DeviceConfig; import android.util.ArraySet; import android.util.IntArray; -import android.util.Log; +import android.util.Slog; import android.util.SparseBooleanArray; import android.util.SparseLongArray; @@ -76,6 +75,7 @@ import java.util.Iterator; import java.util.List; import java.util.Random; import java.util.Set; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; @@ -115,9 +115,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { private final Set mNewRollbacks = new ArraySet<>(); // The list of all rollbacks, including available and committed rollbacks. - // This list is null until the rollback data has been loaded. @GuardedBy("mLock") - private List mRollbacks; + private final List mRollbacks; private final RollbackStore mRollbackStore; @@ -139,29 +138,25 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { // SystemService#onStart. mInstaller = new Installer(mContext); mInstaller.onStart(); - mHandlerThread = new HandlerThread("RollbackManagerServiceHandler"); - mHandlerThread.start(); - - // Monitor the handler thread - Watchdog.getInstance().addThread(getHandler(), HANDLER_THREAD_TIMEOUT_DURATION_MILLIS); mRollbackStore = new RollbackStore(new File(Environment.getDataDirectory(), "rollback")); mPackageHealthObserver = new RollbackPackageHealthObserver(mContext); mAppDataRollbackHelper = new AppDataRollbackHelper(mInstaller); - // Kick off loading of the rollback data from strorage in a background - // thread. - // TODO: Consider loading the rollback data directly here instead, to - // avoid the need to call ensureRollbackDataLoaded every time before - // accessing the rollback data? - // TODO: Test that this kicks off initial scheduling of rollback - // expiration. - getHandler().post(() -> ensureRollbackDataLoaded()); + // Load rollback data from device storage. + synchronized (mLock) { + mRollbacks = mRollbackStore.loadAllRollbackData(); + for (RollbackData data : mRollbacks) { + mAllocatedRollbackIds.put(data.info.getRollbackId(), true); + } + } + + // Kick off and start monitoring the handler thread. + mHandlerThread = new HandlerThread("RollbackManagerServiceHandler"); + mHandlerThread.start(); + Watchdog.getInstance().addThread(getHandler(), HANDLER_THREAD_TIMEOUT_DURATION_MILLIS); - // TODO: Make sure to register these call backs when a new user is - // added too. - SessionCallback sessionCallback = new SessionCallback(); for (UserInfo userInfo : UserManager.get(mContext).getUsers(true)) { registerUserCallbacks(userInfo.getUserHandle()); } @@ -171,7 +166,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { try { enableRollbackFilter.addDataType("application/vnd.android.package-archive"); } catch (IntentFilter.MalformedMimeTypeException e) { - Log.e(TAG, "addDataType", e); + Slog.e(TAG, "addDataType", e); } mContext.registerReceiver(new BroadcastReceiver() { @@ -251,13 +246,10 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { private void registerUserCallbacks(UserHandle user) { Context context = getContextAsUser(user); if (context == null) { - Log.e(TAG, "Unable to register user callbacks for user " + user); + Slog.e(TAG, "Unable to register user callbacks for user " + user); return; } - // TODO: Reuse the same SessionCallback and broadcast receiver - // instances, rather than creating new instances for each user. - context.getPackageManager().getPackageInstaller() .registerSessionCallback(new SessionCallback(), getHandler()); @@ -290,7 +282,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { public ParceledListSlice getAvailableRollbacks() { enforceManageRollbacks("getAvailableRollbacks"); if (Thread.currentThread().equals(mHandlerThread)) { - Log.wtf(TAG, "Calling getAvailableRollbacks from mHandlerThread " + Slog.wtf(TAG, "Calling getAvailableRollbacks from mHandlerThread " + "causes a deadlock"); throw new IllegalStateException("Cannot call RollbackManager#getAvailableRollbacks " + "from the handler thread!"); @@ -300,20 +292,15 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { // to get the most up-to-date results. This is intended to reduce test // flakiness when checking available rollbacks immediately after // installing a package with rollback enabled. - final LinkedBlockingQueue result = new LinkedBlockingQueue<>(); - getHandler().post(() -> result.offer(true)); - + CountDownLatch latch = new CountDownLatch(1); + getHandler().post(() -> latch.countDown()); try { - result.take(); + latch.await(); } catch (InterruptedException ie) { - // We may not get the most up-to-date information, but whatever we - // can get now is better than nothing, so log but otherwise ignore - // the exception. - Log.w(TAG, "Interrupted while waiting for handler thread in getAvailableRollbacks"); + throw new IllegalStateException("RollbackManagerHandlerThread interrupted"); } synchronized (mLock) { - ensureRollbackDataLoadedLocked(); List rollbacks = new ArrayList<>(); for (int i = 0; i < mRollbacks.size(); ++i) { RollbackData data = mRollbacks.get(i); @@ -326,11 +313,10 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { } @Override - public ParceledListSlice getRecentlyExecutedRollbacks() { + public ParceledListSlice getRecentlyCommittedRollbacks() { enforceManageRollbacks("getRecentlyCommittedRollbacks"); synchronized (mLock) { - ensureRollbackDataLoadedLocked(); List rollbacks = new ArrayList<>(); for (int i = 0; i < mRollbacks.size(); ++i) { RollbackData data = mRollbacks.get(i); @@ -345,7 +331,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { @Override public void commitRollback(int rollbackId, ParceledListSlice causePackages, String callerPackageName, IntentSender statusReceiver) { - enforceManageRollbacks("executeRollback"); + enforceManageRollbacks("commitRollback"); final int callingUid = Binder.getCallingUid(); AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class); @@ -365,8 +351,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { final long timeDifference = mRelativeBootTime - oldRelativeBootTime; synchronized (mLock) { - ensureRollbackDataLoadedLocked(); - Iterator iter = mRollbacks.iterator(); while (iter.hasNext()) { RollbackData data = iter.next(); @@ -393,7 +377,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { */ private void commitRollbackInternal(int rollbackId, List causePackages, String callerPackageName, IntentSender statusReceiver) { - Log.i(TAG, "Initiating rollback"); + Slog.i(TAG, "Initiating rollback"); RollbackData data = getRollbackForId(rollbackId); if (data == null || data.state != RollbackData.ROLLBACK_STATE_AVAILABLE) { @@ -532,7 +516,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { } parentSession.commit(receiver.getIntentSender()); } catch (IOException e) { - Log.e(TAG, "Rollback failed", e); + Slog.e(TAG, "Rollback failed", e); sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE, "IOException: " + e.toString()); return; @@ -545,13 +529,21 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { Manifest.permission.TEST_MANAGE_ROLLBACKS, "reloadPersistedData"); - synchronized (mLock) { - mRollbacks = null; - } + CountDownLatch latch = new CountDownLatch(1); getHandler().post(() -> { updateRollbackLifetimeDurationInMillis(); - ensureRollbackDataLoaded(); + synchronized (mLock) { + mRollbacks.clear(); + mRollbacks.addAll(mRollbackStore.loadAllRollbackData()); + } + latch.countDown(); }); + + try { + latch.await(); + } catch (InterruptedException ie) { + throw new IllegalStateException("RollbackManagerHandlerThread interrupted"); + } } @Override @@ -560,7 +552,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { Manifest.permission.TEST_MANAGE_ROLLBACKS, "expireRollbackForPackage"); synchronized (mLock) { - ensureRollbackDataLoadedLocked(); Iterator iter = mRollbacks.iterator(); while (iter.hasNext()) { RollbackData data = iter.next(); @@ -575,6 +566,20 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { } } + @Override + public void blockRollbackManager(long millis) { + mContext.enforceCallingOrSelfPermission( + Manifest.permission.TEST_MANAGE_ROLLBACKS, + "blockRollbackManager"); + getHandler().post(() -> { + try { + Thread.sleep(millis); + } catch (InterruptedException e) { + throw new IllegalStateException("RollbackManagerHandlerThread interrupted"); + } + }); + } + void onUnlockUser(int userId) { getHandler().post(() -> { final List rollbacks; @@ -613,7 +618,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { List restoreInProgress = new ArrayList<>(); Set apexPackageNames = new HashSet<>(); synchronized (mLock) { - ensureRollbackDataLoadedLocked(); for (RollbackData data : mRollbacks) { if (data.isStaged()) { if (data.state == RollbackData.ROLLBACK_STATE_ENABLING) { @@ -635,17 +639,14 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { PackageInstaller installer = mContext.getPackageManager().getPackageInstaller(); PackageInstaller.SessionInfo session = installer.getSessionInfo( data.stagedSessionId); - // TODO: What if session is null? - if (session != null) { - if (session.isStagedSessionApplied()) { - makeRollbackAvailable(data); - } else if (session.isStagedSessionFailed()) { - // TODO: Do we need to remove this from - // mRollbacks, or is it okay to leave as - // unavailable until the next reboot when it will go - // away on its own? - deleteRollback(data); - } + if (session == null || session.isStagedSessionFailed()) { + // TODO: Do we need to remove this from + // mRollbacks, or is it okay to leave as + // unavailable until the next reboot when it will go + // away on its own? + deleteRollback(data); + } else if (session.isStagedSessionApplied()) { + makeRollbackAvailable(data); } } @@ -675,42 +676,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { }); } - /** - * Load rollback data from storage if it has not already been loaded. - * After calling this funciton, mAvailableRollbacks and - * mRecentlyExecutedRollbacks will be non-null. - */ - private void ensureRollbackDataLoaded() { - synchronized (mLock) { - ensureRollbackDataLoadedLocked(); - } - } - - /** - * Load rollback data from storage if it has not already been loaded. - * After calling this function, mRollbacks will be non-null. - */ - @GuardedBy("mLock") - private void ensureRollbackDataLoadedLocked() { - if (mRollbacks == null) { - loadAllRollbackDataLocked(); - } - } - - /** - * Load all rollback data from storage. - * Note: We do potentially heavy IO here while holding mLock, because we - * have to have the rollback data loaded before we can do anything else - * meaningful. - */ - @GuardedBy("mLock") - private void loadAllRollbackDataLocked() { - mRollbacks = mRollbackStore.loadAllRollbackData(); - for (RollbackData data : mRollbacks) { - mAllocatedRollbackIds.put(data.info.getRollbackId(), true); - } - } - /** * Called when a package has been replaced with a different version. * Removes all backups for the package not matching the currently @@ -722,7 +687,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { VersionedPackage installedVersion = getInstalledPackageVersion(packageName); synchronized (mLock) { - ensureRollbackDataLoadedLocked(); Iterator iter = mRollbacks.iterator(); while (iter.hasNext()) { RollbackData data = iter.next(); @@ -761,7 +725,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { */ private void sendFailure(IntentSender statusReceiver, @RollbackManager.Status int status, String message) { - Log.e(TAG, message); + Slog.e(TAG, message); try { final Intent fillIn = new Intent(); fillIn.putExtra(RollbackManager.EXTRA_STATUS, status); @@ -791,8 +755,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { Instant now = Instant.now(); Instant oldest = null; synchronized (mLock) { - ensureRollbackDataLoadedLocked(); - Iterator iter = mRollbacks.iterator(); while (iter.hasNext()) { RollbackData data = iter.next(); @@ -876,7 +838,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { // session. final Context context = getContextAsUser(UserHandle.of(user)); if (context == null) { - Log.e(TAG, "Unable to create context for install session user."); + Slog.e(TAG, "Unable to create context for install session user."); return false; } @@ -903,7 +865,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { } if (parentSession == null || packageSession == null) { - Log.e(TAG, "Unable to find session for enabled rollback."); + Slog.e(TAG, "Unable to find session for enabled rollback."); return false; } @@ -912,7 +874,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { // TODO: This check could be made more efficient. RollbackData rd = null; synchronized (mLock) { - ensureRollbackDataLoadedLocked(); for (int i = 0; i < mRollbacks.size(); ++i) { RollbackData data = mRollbacks.get(i); if (data.apkSessionId == parentSession.getSessionId()) { @@ -930,7 +891,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { newPackage = PackageParser.parsePackageLite( new File(packageSession.resolvedBaseCodePath), 0); } catch (PackageParser.PackageParserException e) { - Log.e(TAG, "Unable to parse new package", e); + Slog.e(TAG, "Unable to parse new package", e); return false; } String packageName = newPackage.packageName; @@ -940,7 +901,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { return true; } } - Log.e(TAG, "Unable to find package in apk session"); + Slog.e(TAG, "Unable to find package in apk session"); return false; } @@ -972,16 +933,16 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { // TODO: Don't attempt to enable rollback for split installs. final int installFlags = session.installFlags; if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) == 0) { - Log.e(TAG, "Rollback is not enabled."); + Slog.e(TAG, "Rollback is not enabled."); return false; } if ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) { - Log.e(TAG, "Rollbacks not supported for instant app install"); + Slog.e(TAG, "Rollbacks not supported for instant app install"); return false; } if (session.resolvedBaseCodePath == null) { - Log.e(TAG, "Session code path has not been resolved."); + Slog.e(TAG, "Session code path has not been resolved."); return false; } @@ -990,17 +951,17 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { try { newPackage = PackageParser.parsePackageLite(new File(session.resolvedBaseCodePath), 0); } catch (PackageParser.PackageParserException e) { - Log.e(TAG, "Unable to parse new package", e); + Slog.e(TAG, "Unable to parse new package", e); return false; } String packageName = newPackage.packageName; - Log.i(TAG, "Enabling rollback for install of " + packageName + Slog.i(TAG, "Enabling rollback for install of " + packageName + ", session:" + session.sessionId); String installerPackageName = session.getInstallerPackageName(); if (!enableRollbackAllowed(installerPackageName, packageName)) { - Log.e(TAG, "Installer " + installerPackageName + Slog.e(TAG, "Installer " + installerPackageName + " is not allowed to enable rollback on " + packageName); return false; } @@ -1016,7 +977,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { } catch (PackageManager.NameNotFoundException e) { // TODO: Support rolling back fresh package installs rather than // fail here. Test this case. - Log.e(TAG, packageName + " is not installed"); + Slog.e(TAG, packageName + " is not installed"); return false; } @@ -1038,7 +999,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { } } } catch (IOException e) { - Log.e(TAG, "Unable to copy package for rollback for " + packageName, e); + Slog.e(TAG, "Unable to copy package for rollback for " + packageName, e); return false; } @@ -1068,7 +1029,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { private void snapshotUserDataInternal(String packageName) { synchronized (mLock) { // staged installs - ensureRollbackDataLoadedLocked(); for (int i = 0; i < mRollbacks.size(); i++) { RollbackData data = mRollbacks.get(i); if (data.state != RollbackData.ROLLBACK_STATE_ENABLING) { @@ -1101,7 +1061,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { PackageRollbackInfo info = null; RollbackData rollbackData = null; synchronized (mLock) { - ensureRollbackDataLoadedLocked(); for (int i = 0; i < mRollbacks.size(); ++i) { RollbackData data = mRollbacks.get(i); if (data.restoreUserDataInProgress) { @@ -1143,7 +1102,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { final PackageInstaller.SessionInfo session = installer.getSessionInfo(sessionId); if (session == null) { - Log.e(TAG, "No matching install session for: " + sessionId); + Slog.e(TAG, "No matching install session for: " + sessionId); result.offer(false); return; } @@ -1156,7 +1115,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { if (!session.isMultiPackage()) { if (!enableRollbackForPackageSession(newRollback.data, session, new int[0])) { - Log.e(TAG, "Unable to enable rollback for session: " + sessionId); + Slog.e(TAG, "Unable to enable rollback for session: " + sessionId); result.offer(false); return; } @@ -1165,13 +1124,13 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { final PackageInstaller.SessionInfo childSession = installer.getSessionInfo(childSessionId); if (childSession == null) { - Log.e(TAG, "No matching child install session for: " + childSessionId); + Slog.e(TAG, "No matching child install session for: " + childSessionId); result.offer(false); return; } if (!enableRollbackForPackageSession(newRollback.data, childSession, new int[0])) { - Log.e(TAG, "Unable to enable rollback for session: " + sessionId); + Slog.e(TAG, "Unable to enable rollback for session: " + sessionId); result.offer(false); return; } @@ -1184,7 +1143,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { try { return result.take(); } catch (InterruptedException ie) { - Log.e(TAG, "Interrupted while waiting for notifyStagedSession response"); + Slog.e(TAG, "Interrupted while waiting for notifyStagedSession response"); return false; } } @@ -1197,7 +1156,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { getHandler().post(() -> { RollbackData rd = null; synchronized (mLock) { - ensureRollbackDataLoadedLocked(); for (int i = 0; i < mRollbacks.size(); ++i) { RollbackData data = mRollbacks.get(i); if (data.stagedSessionId == originalSessionId) { @@ -1343,7 +1301,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { return null; } if (newRollback.isCancelled) { - Log.e(TAG, "Rollback has been cancelled by PackageManager"); + Slog.e(TAG, "Rollback has been cancelled by PackageManager"); deleteRollback(data); return null; } @@ -1352,7 +1310,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { // this is running on the handler thread and all changes to the // data.info occur on the handler thread. if (data.info.getPackages().size() != newRollback.packageSessionIds.length) { - Log.e(TAG, "Failed to enable rollback for all packages in session."); + Slog.e(TAG, "Failed to enable rollback for all packages in session."); deleteRollback(data); return null; } @@ -1369,7 +1327,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { // device reboots between when the session is // committed and this point. Revisit this after // adding support for rollback of staged installs. - ensureRollbackDataLoadedLocked(); mRollbacks.add(data); } @@ -1406,9 +1363,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { */ private RollbackData getRollbackForId(int rollbackId) { synchronized (mLock) { - // TODO: Have ensureRollbackDataLoadedLocked return the list of - // available rollbacks, to hopefully avoid forgetting to call it? - ensureRollbackDataLoadedLocked(); for (int i = 0; i < mRollbacks.size(); ++i) { RollbackData data = mRollbacks.get(i); if (data.info.getRollbackId() == rollbackId) { @@ -1472,7 +1426,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { try { mRollbackStore.saveRollbackData(rollbackData); } catch (IOException ioe) { - Log.e(TAG, "Unable to save rollback info for: " + Slog.e(TAG, "Unable to save rollback info for: " + rollbackData.info.getRollbackId(), ioe); } } diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java index 8a26368c3e133..1c36dc7791e69 100644 --- a/services/core/java/com/android/server/rollback/RollbackStore.java +++ b/services/core/java/com/android/server/rollback/RollbackStore.java @@ -25,7 +25,7 @@ import android.content.rollback.PackageRollbackInfo; import android.content.rollback.PackageRollbackInfo.RestoreInfo; import android.content.rollback.RollbackInfo; import android.util.IntArray; -import android.util.Log; +import android.util.Slog; import android.util.SparseLongArray; import libcore.io.IoUtils; @@ -83,7 +83,7 @@ class RollbackStore { try { rollbacks.add(loadRollbackData(rollbackDir)); } catch (IOException e) { - Log.e(TAG, "Unable to read rollback data at " + rollbackDir, e); + Slog.e(TAG, "Unable to read rollback data at " + rollbackDir, e); removeFile(rollbackDir); } } diff --git a/services/core/java/com/android/server/rollback/TEST_MAPPING b/services/core/java/com/android/server/rollback/TEST_MAPPING index 8c7b5acf5c3ab..2cc931bfac5b1 100644 --- a/services/core/java/com/android/server/rollback/TEST_MAPPING +++ b/services/core/java/com/android/server/rollback/TEST_MAPPING @@ -1,11 +1,5 @@ { "presubmit": [ - { - "name": "RollbackTest" - }, - { - "name": "StagedRollbackTest" - }, { "name": "FrameworksServicesTests", "options": [ @@ -21,6 +15,9 @@ }, { "path": "cts/hostsidetests/rollback" + }, + { + "path": "frameworks/base/tests/RollbackTest" } ] } diff --git a/tests/RollbackTest/Android.bp b/tests/RollbackTest/Android.bp index aec40558ad51e..2bd5931eccbe1 100644 --- a/tests/RollbackTest/Android.bp +++ b/tests/RollbackTest/Android.bp @@ -12,88 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -android_test_helper_app { - name: "RollbackTestAppAv1", - manifest: "TestApp/Av1.xml", - sdk_version: "current", - srcs: ["TestApp/src/**/*.java"], - resource_dirs: ["TestApp/res_v1"], -} - -android_test_helper_app { - name: "RollbackTestAppAv2", - manifest: "TestApp/Av2.xml", - sdk_version: "current", - srcs: ["TestApp/src/**/*.java"], - resource_dirs: ["TestApp/res_v2"], -} - -android_test_helper_app { - name: "RollbackTestAppAv3", - manifest: "TestApp/Av3.xml", - sdk_version: "current", - srcs: ["TestApp/src/**/*.java"], - resource_dirs: ["TestApp/res_v3"], -} - -android_test_helper_app { - name: "RollbackTestAppACrashingV2", - manifest: "TestApp/ACrashingV2.xml", - sdk_version: "current", - srcs: ["TestApp/src/**/*.java"], - resource_dirs: ["TestApp/res_v2"], -} - -android_test_helper_app { - name: "RollbackTestAppBv1", - manifest: "TestApp/Bv1.xml", - sdk_version: "current", - srcs: ["TestApp/src/**/*.java"], - resource_dirs: ["TestApp/res_v1"], -} - -android_test_helper_app { - name: "RollbackTestAppBv2", - manifest: "TestApp/Bv2.xml", - sdk_version: "current", - srcs: ["TestApp/src/**/*.java"], - resource_dirs: ["TestApp/res_v2"], -} - -android_test_helper_app { - name: "RollbackTestAppASplitV1", - manifest: "TestApp/Av1.xml", - sdk_version: "current", - srcs: ["TestApp/src/**/*.java"], - resource_dirs: ["TestApp/res_v1"], - package_splits: ["anydpi"], -} - -android_test_helper_app { - name: "RollbackTestAppASplitV2", - manifest: "TestApp/Av2.xml", - sdk_version: "current", - srcs: ["TestApp/src/**/*.java"], - resource_dirs: ["TestApp/res_v2"], - package_splits: ["anydpi"], -} - android_test { name: "RollbackTest", manifest: "RollbackTest/AndroidManifest.xml", srcs: ["RollbackTest/src/**/*.java"], - static_libs: ["androidx.test.rules"], + static_libs: ["androidx.test.rules", "cts-rollback-lib", "cts-install-lib"], test_suites: ["general-tests"], - java_resources: [ - ":RollbackTestAppAv1", - ":RollbackTestAppAv2", - ":RollbackTestAppAv3", - ":RollbackTestAppACrashingV2", - ":RollbackTestAppBv1", - ":RollbackTestAppBv2", - ":RollbackTestAppASplitV1", - ":RollbackTestAppASplitV2", - ], test_config: "RollbackTest.xml", // TODO: sdk_version: "test_current" when Intent#resolveSystemservice is TestApi } @@ -105,3 +29,11 @@ java_test_host { test_suites: ["general-tests"], test_config: "StagedRollbackTest.xml", } + +java_test_host { + name: "SecondaryUserRollbackTest", + srcs: ["SecondaryUserRollbackTest/src/**/*.java"], + libs: ["tradefed"], + test_suites: ["general-tests"], + test_config: "SecondaryUserRollbackTest.xml", +} diff --git a/tests/RollbackTest/RollbackTest/AndroidManifest.xml b/tests/RollbackTest/RollbackTest/AndroidManifest.xml index 5380dc9fc8cdd..2b8c96484210e 100644 --- a/tests/RollbackTest/RollbackTest/AndroidManifest.xml +++ b/tests/RollbackTest/RollbackTest/AndroidManifest.xml @@ -18,7 +18,7 @@ package="com.android.tests.rollback" > - diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/LocalIntentSender.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/LocalIntentSender.java deleted file mode 100644 index 267ef7377b36e..0000000000000 --- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/LocalIntentSender.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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 com.android.tests.rollback; - -import android.app.PendingIntent; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentSender; - -import androidx.test.InstrumentationRegistry; - -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; - -/** - * Make IntentSender that sends intent locally. - */ -public class LocalIntentSender extends BroadcastReceiver { - - private static final String TAG = "RollbackTest"; - - private static final BlockingQueue sIntentSenderResults = new LinkedBlockingQueue<>(); - - @Override - public void onReceive(Context context, Intent intent) { - sIntentSenderResults.add(intent); - } - - /** - * Get a LocalIntentSender. - */ - static IntentSender getIntentSender() { - Context context = InstrumentationRegistry.getContext(); - Intent intent = new Intent(context, LocalIntentSender.class); - PendingIntent pending = PendingIntent.getBroadcast(context, 0, intent, 0); - return pending.getIntentSender(); - } - - /** - * Returns the most recent Intent sent by a LocalIntentSender. - */ - static Intent getIntentSenderResult() throws InterruptedException { - return sIntentSenderResults.take(); - } -} diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java deleted file mode 100644 index ebe54187ddb6a..0000000000000 --- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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 com.android.tests.rollback; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.util.Log; - -import androidx.test.InstrumentationRegistry; - -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; - -/** - * A broadcast receiver that can be used to get - * ACTION_ROLLBACK_COMMITTED broadcasts. - */ -class RollbackBroadcastReceiver extends BroadcastReceiver { - - private static final String TAG = "RollbackTest"; - - private final BlockingQueue mRollbackBroadcasts = new LinkedBlockingQueue<>(); - - /** - * Creates a RollbackBroadcastReceiver and registers it with the given - * context. - */ - RollbackBroadcastReceiver() { - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_ROLLBACK_COMMITTED); - InstrumentationRegistry.getContext().registerReceiver(this, filter); - } - - @Override - public void onReceive(Context context, Intent intent) { - Log.i(TAG, "Received rollback broadcast intent"); - mRollbackBroadcasts.add(intent); - } - - /** - * Polls for at most the given amount of time for the next rollback - * broadcast. - */ - Intent poll(long timeout, TimeUnit unit) throws InterruptedException { - return mRollbackBroadcasts.poll(timeout, unit); - } - - /** - * Waits forever for the next rollback broadcast. - */ - Intent take() throws InterruptedException { - return mRollbackBroadcasts.take(); - } - - /** - * Unregisters this broadcast receiver. - */ - void unregister() { - InstrumentationRegistry.getContext().unregisterReceiver(this); - } -} diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java index 1b002cadb07fc..b57bd4d64dc2f 100644 --- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java +++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java @@ -16,14 +16,12 @@ package com.android.tests.rollback; -import static com.android.tests.rollback.RollbackTestUtils.assertPackageRollbackInfoEquals; -import static com.android.tests.rollback.RollbackTestUtils.assertRollbackInfoEquals; -import static com.android.tests.rollback.RollbackTestUtils.getUniqueRollbackInfoForPackage; -import static com.android.tests.rollback.RollbackTestUtils.processUserData; +import static com.android.cts.install.lib.InstallUtils.processUserData; +import static com.android.cts.rollback.lib.RollbackInfoSubject.assertThat; +import static com.android.cts.rollback.lib.RollbackUtils.getUniqueRollbackInfoForPackage; + +import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; import android.Manifest; @@ -31,15 +29,21 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.pm.VersionedPackage; import android.content.rollback.RollbackInfo; import android.content.rollback.RollbackManager; import android.provider.DeviceConfig; -import android.provider.Settings; import android.util.Log; import androidx.test.InstrumentationRegistry; +import com.android.cts.install.lib.Install; +import com.android.cts.install.lib.InstallUtils; +import com.android.cts.install.lib.TestApp; +import com.android.cts.install.lib.Uninstall; +import com.android.cts.rollback.lib.Rollback; +import com.android.cts.rollback.lib.RollbackBroadcastReceiver; +import com.android.cts.rollback.lib.RollbackUtils; + import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -57,8 +61,6 @@ public class RollbackTest { private static final String TAG = "RollbackTest"; - private static final String TEST_APP_A = "com.android.tests.rollback.testapp.A"; - private static final String TEST_APP_B = "com.android.tests.rollback.testapp.B"; private static final String INSTRUMENTED_APP = "com.android.tests.rollback"; // copied from PackageManagerService#PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS @@ -88,7 +90,7 @@ public class RollbackTest { context.registerReceiver(enableRollbackReceiver, enableRollbackFilter); try { - RollbackTestUtils.adoptShellPermissionIdentity( + InstallUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, Manifest.permission.TEST_MANAGE_ROLLBACKS, @@ -97,18 +99,18 @@ public class RollbackTest { // Register a broadcast receiver for notification when the // rollback has been committed. RollbackBroadcastReceiver broadcastReceiver = new RollbackBroadcastReceiver(); - RollbackManager rm = RollbackTestUtils.getRollbackManager(); + RollbackManager rm = RollbackUtils.getRollbackManager(); - // Uninstall TEST_APP_A - RollbackTestUtils.uninstall(TEST_APP_A); - assertEquals(-1, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + // Uninstall TestApp.A + Uninstall.packages(TestApp.A); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1); // TODO: There is currently a race condition between when the app is // uninstalled and when rollback manager deletes the rollback. Fix it // so that's not the case! for (int i = 0; i < 5; ++i) { RollbackInfo rollback = getUniqueRollbackInfoForPackage( - rm.getRecentlyCommittedRollbacks(), TEST_APP_A); + rm.getRecentlyCommittedRollbacks(), TestApp.A); if (rollback != null) { Log.i(TAG, "Sleeping 1 second to wait for uninstall to take effect."); Thread.sleep(1000); @@ -116,50 +118,65 @@ public class RollbackTest { } // The app should not be available for rollback. - assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A)); + assertThat( + getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TestApp.A)).isNull(); // There should be no recently committed rollbacks for this package. - assertNull(getUniqueRollbackInfoForPackage( - rm.getRecentlyCommittedRollbacks(), TEST_APP_A)); + assertThat(getUniqueRollbackInfoForPackage( + rm.getRecentlyCommittedRollbacks(), TestApp.A)).isNull(); // Install v1 of the app (without rollbacks enabled). - RollbackTestUtils.install("RollbackTestAppAv1.apk", false); - assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + Install.single(TestApp.A1).commit(); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1); // Upgrade from v1 to v2, with rollbacks enabled. - RollbackTestUtils.install("RollbackTestAppAv2.apk", true); - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + Install.single(TestApp.A2).setEnableRollback().commit(); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2); // The app should now be available for rollback. - RollbackInfo rollback = getUniqueRollbackInfoForPackage( - rm.getAvailableRollbacks(), TEST_APP_A); - assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback); + RollbackInfo available = getUniqueRollbackInfoForPackage( + rm.getAvailableRollbacks(), TestApp.A); + assertThat(available).isNotNull(); + assertThat(available).isNotStaged(); + assertThat(available).packagesContainsExactly( + Rollback.from(TestApp.A2).to(TestApp.A1)); // We should not have received any rollback requests yet. // TODO: Possibly flaky if, by chance, some other app on device // happens to be rolled back at the same time? - assertNull(broadcastReceiver.poll(0, TimeUnit.SECONDS)); + assertThat(broadcastReceiver.poll(0, TimeUnit.SECONDS)).isNull(); // Roll back the app. - RollbackTestUtils.rollback(rollback.getRollbackId()); - assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + RollbackUtils.rollback(available.getRollbackId()); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1); // Verify we received a broadcast for the rollback. // TODO: Race condition between the timeout and when the broadcast is // received could lead to test flakiness. Intent broadcast = broadcastReceiver.poll(5, TimeUnit.SECONDS); - assertNotNull(broadcast); - assertNull(broadcastReceiver.poll(0, TimeUnit.SECONDS)); + if (context.getUser().isSystem()) { + // Only system user should receive those broadcasts. + assertThat(broadcast).isNotNull(); + assertThat(broadcastReceiver.poll(0, TimeUnit.SECONDS)).isNull(); + } else { + // This is in case the test was running under a secondary user, in which case + // the broadcast won't be received here. + assertThat(broadcast).isNull(); + } // Verify the recent rollback has been recorded. - rollback = getUniqueRollbackInfoForPackage( - rm.getRecentlyCommittedRollbacks(), TEST_APP_A); - assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback); + RollbackInfo committed = getUniqueRollbackInfoForPackage( + rm.getRecentlyCommittedRollbacks(), TestApp.A); + assertThat(committed).isNotNull(); + assertThat(committed).isNotStaged(); + assertThat(committed).packagesContainsExactly( + Rollback.from(TestApp.A2).to(TestApp.A1)); + assertThat(committed).hasRollbackId(available.getRollbackId()); broadcastReceiver.unregister(); context.unregisterReceiver(enableRollbackReceiver); } finally { - RollbackTestUtils.dropShellPermissionIdentity(); + InstallUtils.dropShellPermissionIdentity(); } } @@ -169,50 +186,58 @@ public class RollbackTest { @Test public void testAvailableRollbackPersistence() throws Exception { try { - RollbackTestUtils.adoptShellPermissionIdentity( + InstallUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, Manifest.permission.TEST_MANAGE_ROLLBACKS); - RollbackManager rm = RollbackTestUtils.getRollbackManager(); + RollbackManager rm = RollbackUtils.getRollbackManager(); - RollbackTestUtils.uninstall(TEST_APP_A); - RollbackTestUtils.install("RollbackTestAppAv1.apk", false); - RollbackTestUtils.install("RollbackTestAppAv2.apk", true); - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + Uninstall.packages(TestApp.A); + Install.single(TestApp.A1).commit(); + Install.single(TestApp.A2).setEnableRollback().commit(); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2); - RollbackTestUtils.uninstall(TEST_APP_B); - RollbackTestUtils.install("RollbackTestAppBv1.apk", false); - RollbackTestUtils.install("RollbackTestAppBv2.apk", true); - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B)); + Uninstall.packages(TestApp.B); + Install.single(TestApp.B1).commit(); + Install.single(TestApp.B2).setEnableRollback().commit(); + assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2); // Both test apps should now be available for rollback. RollbackInfo rollbackA = getUniqueRollbackInfoForPackage( - rm.getAvailableRollbacks(), TEST_APP_A); - assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA); + rm.getAvailableRollbacks(), TestApp.A); + assertThat(rollbackA).isNotNull(); + assertThat(rollbackA).packagesContainsExactly( + Rollback.from(TestApp.A2).to(TestApp.A1)); RollbackInfo rollbackB = getUniqueRollbackInfoForPackage( - rm.getAvailableRollbacks(), TEST_APP_B); - assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB); + rm.getAvailableRollbacks(), TestApp.B); + assertThat(rollbackB).isNotNull(); + assertThat(rollbackB).packagesContainsExactly( + Rollback.from(TestApp.B2).to(TestApp.B1)); // Reload the persisted data. rm.reloadPersistedData(); // The apps should still be available for rollback. rollbackA = getUniqueRollbackInfoForPackage( - rm.getAvailableRollbacks(), TEST_APP_A); - assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA); + rm.getAvailableRollbacks(), TestApp.A); + assertThat(rollbackA).isNotNull(); + assertThat(rollbackA).packagesContainsExactly( + Rollback.from(TestApp.A2).to(TestApp.A1)); rollbackB = getUniqueRollbackInfoForPackage( - rm.getAvailableRollbacks(), TEST_APP_B); - assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB); + rm.getAvailableRollbacks(), TestApp.B); + assertThat(rollbackB).isNotNull(); + assertThat(rollbackB).packagesContainsExactly( + Rollback.from(TestApp.B2).to(TestApp.B1)); // Rollback of B should not rollback A - RollbackTestUtils.rollback(rollbackB.getRollbackId()); - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); - assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B)); + RollbackUtils.rollback(rollbackB.getRollbackId()); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2); + assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1); } finally { - RollbackTestUtils.dropShellPermissionIdentity(); + InstallUtils.dropShellPermissionIdentity(); } } @@ -222,49 +247,78 @@ public class RollbackTest { @Test public void testAvailableMultiPackageRollbackPersistence() throws Exception { try { - RollbackTestUtils.adoptShellPermissionIdentity( + InstallUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, Manifest.permission.TEST_MANAGE_ROLLBACKS); - RollbackManager rm = RollbackTestUtils.getRollbackManager(); + RollbackManager rm = RollbackUtils.getRollbackManager(); - RollbackTestUtils.uninstall(TEST_APP_A); - RollbackTestUtils.uninstall(TEST_APP_B); - RollbackTestUtils.installMultiPackage(false, - "RollbackTestAppAv1.apk", - "RollbackTestAppBv1.apk"); - RollbackTestUtils.installMultiPackage(true, - "RollbackTestAppAv2.apk", - "RollbackTestAppBv2.apk"); - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B)); + Uninstall.packages(TestApp.A, TestApp.B); + Install.multi(TestApp.A1, TestApp.B1).commit(); + Install.multi(TestApp.A2, TestApp.B2).setEnableRollback().commit(); + + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2); + assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2); // The app should now be available for rollback. - RollbackInfo rollbackA = getUniqueRollbackInfoForPackage( - rm.getAvailableRollbacks(), TEST_APP_A); - assertRollbackInfoForAandB(rollbackA); + RollbackInfo availableA = getUniqueRollbackInfoForPackage( + rm.getAvailableRollbacks(), TestApp.A); + assertThat(availableA).isNotNull(); + assertThat(availableA).packagesContainsExactly( + Rollback.from(TestApp.A2).to(TestApp.A1), + Rollback.from(TestApp.B2).to(TestApp.B1)); - RollbackInfo rollbackB = getUniqueRollbackInfoForPackage( - rm.getAvailableRollbacks(), TEST_APP_B); - assertRollbackInfoForAandB(rollbackB); + RollbackInfo availableB = getUniqueRollbackInfoForPackage( + rm.getAvailableRollbacks(), TestApp.B); + assertThat(availableB).isNotNull(); + assertThat(availableB).packagesContainsExactly( + Rollback.from(TestApp.A2).to(TestApp.A1), + Rollback.from(TestApp.B2).to(TestApp.B1)); + + // Assert they're both the same rollback + assertThat(availableA).hasRollbackId(availableB.getRollbackId()); // Reload the persisted data. rm.reloadPersistedData(); // The apps should still be available for rollback. - rollbackA = getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A); - assertRollbackInfoForAandB(rollbackA); + availableA = getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TestApp.A); + assertThat(availableA).isNotNull(); + assertThat(availableA).packagesContainsExactly( + Rollback.from(TestApp.A2).to(TestApp.A1), + Rollback.from(TestApp.B2).to(TestApp.B1)); - rollbackB = getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_B); - assertRollbackInfoForAandB(rollbackB); + availableB = getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TestApp.B); + assertThat(availableB).isNotNull(); + assertThat(availableB).packagesContainsExactly( + Rollback.from(TestApp.A2).to(TestApp.A1), + Rollback.from(TestApp.B2).to(TestApp.B1)); // Rollback of B should rollback A as well - RollbackTestUtils.rollback(rollbackB.getRollbackId()); - assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); - assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B)); + RollbackUtils.rollback(availableB.getRollbackId()); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1); + assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1); + + RollbackInfo committedA = getUniqueRollbackInfoForPackage( + rm.getRecentlyCommittedRollbacks(), TestApp.A); + assertThat(committedA).isNotNull(); + assertThat(committedA).packagesContainsExactly( + Rollback.from(TestApp.A2).to(TestApp.A1), + Rollback.from(TestApp.B2).to(TestApp.B1)); + + RollbackInfo committedB = getUniqueRollbackInfoForPackage( + rm.getRecentlyCommittedRollbacks(), TestApp.A); + assertThat(committedB).isNotNull(); + assertThat(committedB).packagesContainsExactly( + Rollback.from(TestApp.A2).to(TestApp.A1), + Rollback.from(TestApp.B2).to(TestApp.B1)); + + // Assert they're both the same rollback + assertThat(committedA).hasRollbackId(committedB.getRollbackId()); + assertThat(committedA).hasRollbackId(availableA.getRollbackId()); } finally { - RollbackTestUtils.dropShellPermissionIdentity(); + InstallUtils.dropShellPermissionIdentity(); } } @@ -274,42 +328,50 @@ public class RollbackTest { @Test public void testRecentlyCommittedRollbackPersistence() throws Exception { try { - RollbackTestUtils.adoptShellPermissionIdentity( + InstallUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, Manifest.permission.TEST_MANAGE_ROLLBACKS); - RollbackManager rm = RollbackTestUtils.getRollbackManager(); + RollbackManager rm = RollbackUtils.getRollbackManager(); - RollbackTestUtils.uninstall(TEST_APP_A); - RollbackTestUtils.install("RollbackTestAppAv1.apk", false); - RollbackTestUtils.install("RollbackTestAppAv2.apk", true); - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + Uninstall.packages(TestApp.A); + Install.single(TestApp.A1).commit(); + Install.single(TestApp.A2).setEnableRollback().commit(); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2); // The app should now be available for rollback. - RollbackInfo rollback = getUniqueRollbackInfoForPackage( - rm.getAvailableRollbacks(), TEST_APP_A); + RollbackInfo available = getUniqueRollbackInfoForPackage( + rm.getAvailableRollbacks(), TestApp.A); + assertThat(available).isNotNull(); // Roll back the app. - VersionedPackage cause = new VersionedPackage( - "com.android.tests.rollback.testapp.Foo", 42); - RollbackTestUtils.rollback(rollback.getRollbackId(), cause); - assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + TestApp cause = new TestApp("Foo", "com.android.tests.rollback.testapp.Foo", + /*versionCode*/ 42, /*isApex*/ false); + RollbackUtils.rollback(available.getRollbackId(), cause); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1); // Verify the recent rollback has been recorded. - rollback = getUniqueRollbackInfoForPackage( - rm.getRecentlyCommittedRollbacks(), TEST_APP_A); - assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback, cause); + RollbackInfo committed = getUniqueRollbackInfoForPackage( + rm.getRecentlyCommittedRollbacks(), TestApp.A); + assertThat(committed).isNotNull(); + assertThat(committed).packagesContainsExactly( + Rollback.from(TestApp.A2).to(TestApp.A1)); + assertThat(committed).causePackagesContainsExactly(cause); // Reload the persisted data. rm.reloadPersistedData(); // Verify the recent rollback is still recorded. - rollback = getUniqueRollbackInfoForPackage( - rm.getRecentlyCommittedRollbacks(), TEST_APP_A); - assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback, cause); + committed = getUniqueRollbackInfoForPackage( + rm.getRecentlyCommittedRollbacks(), TestApp.A); + assertThat(committed).isNotNull(); + assertThat(committed).packagesContainsExactly( + Rollback.from(TestApp.A2).to(TestApp.A1)); + assertThat(committed).causePackagesContainsExactly(cause); + assertThat(committed).hasRollbackId(available.getRollbackId()); } finally { - RollbackTestUtils.dropShellPermissionIdentity(); + InstallUtils.dropShellPermissionIdentity(); } } @@ -320,10 +382,10 @@ public class RollbackTest { public void testRollbackExpiresAfterLifetime() throws Exception { long expirationTime = TimeUnit.SECONDS.toMillis(30); long defaultExpirationTime = TimeUnit.HOURS.toMillis(48); - RollbackManager rm = RollbackTestUtils.getRollbackManager(); + RollbackManager rm = RollbackUtils.getRollbackManager(); try { - RollbackTestUtils.adoptShellPermissionIdentity( + InstallUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, Manifest.permission.TEST_MANAGE_ROLLBACKS, @@ -336,39 +398,45 @@ public class RollbackTest { // Pull the new expiration time from DeviceConfig rm.reloadPersistedData(); - // Uninstall TEST_APP_A - RollbackTestUtils.uninstall(TEST_APP_A); - assertEquals(-1, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + // Uninstall TestApp.A + Uninstall.packages(TestApp.A); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1); // Install v1 of the app (without rollbacks enabled). - RollbackTestUtils.install("RollbackTestAppAv1.apk", false); - assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + Install.single(TestApp.A1).commit(); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1); // Upgrade from v1 to v2, with rollbacks enabled. - RollbackTestUtils.install("RollbackTestAppAv2.apk", true); - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + Install.single(TestApp.A2).setEnableRollback().commit(); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2); // Check that the rollback data has not expired Thread.sleep(1000); RollbackInfo rollback = getUniqueRollbackInfoForPackage( - rm.getAvailableRollbacks(), TEST_APP_A); - assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback); + rm.getAvailableRollbacks(), TestApp.A); + assertThat(rollback).isNotNull(); + assertThat(rollback).packagesContainsExactly( + Rollback.from(TestApp.A2).to(TestApp.A1)); // Give it a little more time, but still not the long enough to expire Thread.sleep(expirationTime / 2); rollback = getUniqueRollbackInfoForPackage( - rm.getAvailableRollbacks(), TEST_APP_A); - assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback); + rm.getAvailableRollbacks(), TestApp.A); + assertThat(rollback).isNotNull(); + assertThat(rollback).packagesContainsExactly( + Rollback.from(TestApp.A2).to(TestApp.A1)); // Check that the data has expired after the expiration time (with a buffer of 1 second) Thread.sleep(expirationTime / 2); - assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A)); + rollback = getUniqueRollbackInfoForPackage( + rm.getAvailableRollbacks(), TestApp.A); + assertThat(rollback).isNull(); } finally { DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT, RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS, Long.toString(defaultExpirationTime), false /* makeDefault*/); - RollbackTestUtils.dropShellPermissionIdentity(); + InstallUtils.dropShellPermissionIdentity(); } } @@ -380,10 +448,10 @@ public class RollbackTest { public void testTimeChangeDoesNotAffectLifetime() throws Exception { long expirationTime = TimeUnit.SECONDS.toMillis(30); long defaultExpirationTime = TimeUnit.HOURS.toMillis(48); - RollbackManager rm = RollbackTestUtils.getRollbackManager(); + RollbackManager rm = RollbackUtils.getRollbackManager(); try { - RollbackTestUtils.adoptShellPermissionIdentity( + InstallUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, Manifest.permission.TEST_MANAGE_ROLLBACKS, @@ -398,24 +466,25 @@ public class RollbackTest { rm.reloadPersistedData(); // Install app A with rollback enabled - RollbackTestUtils.uninstall(TEST_APP_A); - RollbackTestUtils.install("RollbackTestAppAv1.apk", false); - RollbackTestUtils.install("RollbackTestAppAv2.apk", true); - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + Uninstall.packages(TestApp.A); + Install.single(TestApp.A1).commit(); + Install.single(TestApp.A2).setEnableRollback().commit(); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2); Thread.sleep(expirationTime / 2); // Install app B with rollback enabled - RollbackTestUtils.uninstall(TEST_APP_B); - RollbackTestUtils.install("RollbackTestAppBv1.apk", false); - RollbackTestUtils.install("RollbackTestAppBv2.apk", true); - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B)); + Uninstall.packages(TestApp.B); + Install.single(TestApp.B1).commit(); + Install.single(TestApp.B2).setEnableRollback().commit(); + assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2); + // 1 second buffer Thread.sleep(1000); try { // Change the time - RollbackTestUtils.forwardTimeBy(expirationTime); + RollbackUtils.forwardTimeBy(expirationTime); // 1 second buffer to allow Rollback Manager to handle time change before loading // persisted data @@ -427,24 +496,31 @@ public class RollbackTest { // Wait until rollback for app A has expired // This will trigger an expiration run that should expire app A but not B Thread.sleep(expirationTime / 2); - assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A)); + RollbackInfo rollback = + getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TestApp.A); + assertThat(rollback).isNull(); // Rollback for app B should not be expired - RollbackInfo rollback = getUniqueRollbackInfoForPackage( - rm.getAvailableRollbacks(), TEST_APP_B); - assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollback); + rollback = getUniqueRollbackInfoForPackage( + rm.getAvailableRollbacks(), TestApp.B); + assertThat(rollback).isNotNull(); + assertThat(rollback).packagesContainsExactly( + Rollback.from(TestApp.B2).to(TestApp.B1)); // Wait until rollback for app B has expired Thread.sleep(expirationTime / 2); - assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_B)); + rollback = getUniqueRollbackInfoForPackage( + rm.getAvailableRollbacks(), TestApp.B); + // Rollback should be expired by now + assertThat(rollback).isNull(); } finally { - RollbackTestUtils.forwardTimeBy(-expirationTime); + RollbackUtils.forwardTimeBy(-expirationTime); } } finally { DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT, RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS, Long.toString(defaultExpirationTime), false /* makeDefault*/); - RollbackTestUtils.dropShellPermissionIdentity(); + InstallUtils.dropShellPermissionIdentity(); } } @@ -455,30 +531,32 @@ public class RollbackTest { @Test public void testRollbackExpiration() throws Exception { try { - RollbackTestUtils.adoptShellPermissionIdentity( + InstallUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, Manifest.permission.TEST_MANAGE_ROLLBACKS); - RollbackManager rm = RollbackTestUtils.getRollbackManager(); - RollbackTestUtils.uninstall(TEST_APP_A); - RollbackTestUtils.install("RollbackTestAppAv1.apk", false); - RollbackTestUtils.install("RollbackTestAppAv2.apk", true); - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + RollbackManager rm = RollbackUtils.getRollbackManager(); + Uninstall.packages(TestApp.A); + Install.single(TestApp.A1).commit(); + Install.single(TestApp.A2).setEnableRollback().commit(); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2); // The app should now be available for rollback. RollbackInfo rollback = getUniqueRollbackInfoForPackage( - rm.getAvailableRollbacks(), TEST_APP_A); - assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback); + rm.getAvailableRollbacks(), TestApp.A); + assertThat(rollback).isNotNull(); + assertThat(rollback).packagesContainsExactly( + Rollback.from(TestApp.A2).to(TestApp.A1)); // Expire the rollback. - rm.expireRollbackForPackage(TEST_APP_A); + rm.expireRollbackForPackage(TestApp.A); // The rollback should no longer be available. - assertNull(getUniqueRollbackInfoForPackage( - rm.getAvailableRollbacks(), TEST_APP_A)); + assertThat(getUniqueRollbackInfoForPackage( + rm.getAvailableRollbacks(), TestApp.A)).isNull(); } finally { - RollbackTestUtils.dropShellPermissionIdentity(); + InstallUtils.dropShellPermissionIdentity(); } } @@ -488,24 +566,24 @@ public class RollbackTest { @Test public void testUserDataRollback() throws Exception { try { - RollbackTestUtils.adoptShellPermissionIdentity( + InstallUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, Manifest.permission.TEST_MANAGE_ROLLBACKS); - RollbackTestUtils.uninstall(TEST_APP_A); - RollbackTestUtils.install("RollbackTestAppAv1.apk", false); - processUserData(TEST_APP_A); - RollbackTestUtils.install("RollbackTestAppAv2.apk", true); - processUserData(TEST_APP_A); + Uninstall.packages(TestApp.A); + Install.single(TestApp.A1).commit(); + processUserData(TestApp.A); + Install.single(TestApp.A2).setEnableRollback().commit(); + processUserData(TestApp.A); - RollbackManager rm = RollbackTestUtils.getRollbackManager(); + RollbackManager rm = RollbackUtils.getRollbackManager(); RollbackInfo rollback = getUniqueRollbackInfoForPackage( - rm.getAvailableRollbacks(), TEST_APP_A); - RollbackTestUtils.rollback(rollback.getRollbackId()); - processUserData(TEST_APP_A); + rm.getAvailableRollbacks(), TestApp.A); + RollbackUtils.rollback(rollback.getRollbackId()); + processUserData(TestApp.A); } finally { - RollbackTestUtils.dropShellPermissionIdentity(); + InstallUtils.dropShellPermissionIdentity(); } } @@ -515,30 +593,26 @@ public class RollbackTest { @Test public void testRollbackWithSplits() throws Exception { try { - RollbackTestUtils.adoptShellPermissionIdentity( + InstallUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, Manifest.permission.TEST_MANAGE_ROLLBACKS); - RollbackTestUtils.uninstall(TEST_APP_A); - RollbackTestUtils.installSplit(false, - "RollbackTestAppASplitV1.apk", - "RollbackTestAppASplitV1_anydpi.apk"); - processUserData(TEST_APP_A); + Uninstall.packages(TestApp.A); + Install.single(TestApp.ASplit1).commit(); + processUserData(TestApp.A); - RollbackTestUtils.installSplit(true, - "RollbackTestAppASplitV2.apk", - "RollbackTestAppASplitV2_anydpi.apk"); - processUserData(TEST_APP_A); + Install.single(TestApp.ASplit2).setEnableRollback().commit(); + processUserData(TestApp.A); - RollbackManager rm = RollbackTestUtils.getRollbackManager(); + RollbackManager rm = RollbackUtils.getRollbackManager(); RollbackInfo rollback = getUniqueRollbackInfoForPackage( - rm.getAvailableRollbacks(), TEST_APP_A); - assertNotNull(rollback); - RollbackTestUtils.rollback(rollback.getRollbackId()); - processUserData(TEST_APP_A); + rm.getAvailableRollbacks(), TestApp.A); + assertThat(rollback).isNotNull(); + RollbackUtils.rollback(rollback.getRollbackId()); + processUserData(TestApp.A); } finally { - RollbackTestUtils.dropShellPermissionIdentity(); + InstallUtils.dropShellPermissionIdentity(); } } @@ -559,7 +633,7 @@ public class RollbackTest { // Confirm that we really haven't received the broadcast. // TODO: How long to wait for the expected timeout? - assertNull(broadcastReceiver.poll(5, TimeUnit.SECONDS)); + assertThat(broadcastReceiver.poll(5, TimeUnit.SECONDS)).isNull(); // TODO: Do we need to do this? Do we need to ensure this is always // called, even when the test fails? @@ -573,48 +647,52 @@ public class RollbackTest { @Test public void testMultipleRollbackAvailable() throws Exception { try { - RollbackTestUtils.adoptShellPermissionIdentity( + InstallUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, Manifest.permission.TEST_MANAGE_ROLLBACKS); - RollbackManager rm = RollbackTestUtils.getRollbackManager(); + RollbackManager rm = RollbackUtils.getRollbackManager(); // Prep installation of the test apps. - RollbackTestUtils.uninstall(TEST_APP_A); - RollbackTestUtils.install("RollbackTestAppAv1.apk", false); - RollbackTestUtils.install("RollbackTestAppAv2.apk", true); - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + Uninstall.packages(TestApp.A); + Install.single(TestApp.A1).commit(); + Install.single(TestApp.A2).setEnableRollback().commit(); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2); - RollbackTestUtils.uninstall(TEST_APP_B); - RollbackTestUtils.install("RollbackTestAppBv1.apk", false); - RollbackTestUtils.install("RollbackTestAppBv2.apk", true); - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B)); + Uninstall.packages(TestApp.B); + Install.single(TestApp.B1).commit(); + Install.single(TestApp.B2).setEnableRollback().commit(); + assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2); // Both test apps should now be available for rollback, and the // RollbackInfo returned for the rollbacks should be correct. RollbackInfo rollbackA = getUniqueRollbackInfoForPackage( - rm.getAvailableRollbacks(), TEST_APP_A); - assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA); + rm.getAvailableRollbacks(), TestApp.A); + assertThat(rollbackA).isNotNull(); + assertThat(rollbackA).packagesContainsExactly( + Rollback.from(TestApp.A2).to(TestApp.A1)); RollbackInfo rollbackB = getUniqueRollbackInfoForPackage( - rm.getAvailableRollbacks(), TEST_APP_B); - assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB); + rm.getAvailableRollbacks(), TestApp.B); + assertThat(rollbackB).isNotNull(); + assertThat(rollbackB).packagesContainsExactly( + Rollback.from(TestApp.B2).to(TestApp.B1)); // Executing rollback should roll back the correct package. - RollbackTestUtils.rollback(rollbackA.getRollbackId()); - assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B)); + RollbackUtils.rollback(rollbackA.getRollbackId()); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1); + assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2); - RollbackTestUtils.uninstall(TEST_APP_A); - RollbackTestUtils.install("RollbackTestAppAv1.apk", false); - RollbackTestUtils.install("RollbackTestAppAv2.apk", true); - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + Uninstall.packages(TestApp.A); + Install.single(TestApp.A1).commit(); + Install.single(TestApp.A2).setEnableRollback().commit(); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2); - RollbackTestUtils.rollback(rollbackB.getRollbackId()); - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); - assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B)); + RollbackUtils.rollback(rollbackB.getRollbackId()); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2); + assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1); } finally { - RollbackTestUtils.dropShellPermissionIdentity(); + InstallUtils.dropShellPermissionIdentity(); } } @@ -626,7 +704,7 @@ public class RollbackTest { public void testManageRollbacksPermission() throws Exception { // We shouldn't be allowed to call any of the RollbackManager APIs // without the MANAGE_ROLLBACKS permission. - RollbackManager rm = RollbackTestUtils.getRollbackManager(); + RollbackManager rm = RollbackUtils.getRollbackManager(); try { rm.getAvailableRollbacks(); @@ -659,7 +737,7 @@ public class RollbackTest { } try { - rm.expireRollbackForPackage(TEST_APP_A); + rm.expireRollbackForPackage(TestApp.A); fail("expected SecurityException"); } catch (SecurityException e) { // Expected. @@ -673,26 +751,27 @@ public class RollbackTest { @Test public void testEnableRollbackPermission() throws Exception { try { - RollbackTestUtils.adoptShellPermissionIdentity( + InstallUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES); - RollbackTestUtils.uninstall(TEST_APP_A); - RollbackTestUtils.install("RollbackTestAppAv1.apk", /* enableRollback */ false); - assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + Uninstall.packages(TestApp.A); + Install.single(TestApp.A1).commit(); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1); - RollbackTestUtils.install("RollbackTestAppAv2.apk", /* enableRollback */ true); + Install.single(TestApp.A2).setEnableRollback().commit(); // We expect v2 of the app was installed, but rollback has not // been enabled. - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2); - RollbackTestUtils.adoptShellPermissionIdentity( + InstallUtils.adoptShellPermissionIdentity( Manifest.permission.TEST_MANAGE_ROLLBACKS); - RollbackManager rm = RollbackTestUtils.getRollbackManager(); - assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A)); + RollbackManager rm = RollbackUtils.getRollbackManager(); + assertThat( + getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TestApp.A)).isNull(); } finally { - RollbackTestUtils.dropShellPermissionIdentity(); + InstallUtils.dropShellPermissionIdentity(); } } @@ -703,25 +782,26 @@ public class RollbackTest { @Test public void testNonModuleEnableRollback() throws Exception { try { - RollbackTestUtils.adoptShellPermissionIdentity( + InstallUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, Manifest.permission.MANAGE_ROLLBACKS); - RollbackTestUtils.uninstall(TEST_APP_A); - RollbackTestUtils.install("RollbackTestAppAv1.apk", /* enableRollback */ false); - assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + Uninstall.packages(TestApp.A); + Install.single(TestApp.A1).commit(); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1); - RollbackTestUtils.install("RollbackTestAppAv2.apk", /* enableRollback */ true); + Install.single(TestApp.A2).setEnableRollback().commit(); // We expect v2 of the app was installed, but rollback has not // been enabled because the test app is not a module. - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2); - RollbackManager rm = RollbackTestUtils.getRollbackManager(); - assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A)); + RollbackManager rm = RollbackUtils.getRollbackManager(); + assertThat( + getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TestApp.A)).isNull(); } finally { - RollbackTestUtils.dropShellPermissionIdentity(); + InstallUtils.dropShellPermissionIdentity(); } } @@ -731,54 +811,54 @@ public class RollbackTest { @Test public void testMultiPackage() throws Exception { try { - RollbackTestUtils.adoptShellPermissionIdentity( + InstallUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, Manifest.permission.TEST_MANAGE_ROLLBACKS); - RollbackManager rm = RollbackTestUtils.getRollbackManager(); + RollbackManager rm = RollbackUtils.getRollbackManager(); // Prep installation of the test apps. - RollbackTestUtils.uninstall(TEST_APP_A); - RollbackTestUtils.uninstall(TEST_APP_B); - RollbackTestUtils.installMultiPackage(false, - "RollbackTestAppAv1.apk", - "RollbackTestAppBv1.apk"); - processUserData(TEST_APP_A); - processUserData(TEST_APP_B); - RollbackTestUtils.installMultiPackage(true, - "RollbackTestAppAv2.apk", - "RollbackTestAppBv2.apk"); - processUserData(TEST_APP_A); - processUserData(TEST_APP_B); - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B)); + Uninstall.packages(TestApp.A, TestApp.B); + Install.multi(TestApp.A1, TestApp.B1).commit(); + processUserData(TestApp.A); + processUserData(TestApp.B); + Install.multi(TestApp.A2, TestApp.B2).setEnableRollback().commit(); + processUserData(TestApp.A); + processUserData(TestApp.B); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2); + assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2); - // TEST_APP_A should now be available for rollback. + // TestApp.A should now be available for rollback. RollbackInfo rollback = getUniqueRollbackInfoForPackage( - rm.getAvailableRollbacks(), TEST_APP_A); - assertRollbackInfoForAandB(rollback); + rm.getAvailableRollbacks(), TestApp.A); + assertThat(rollback).isNotNull(); + assertThat(rollback).packagesContainsExactly( + Rollback.from(TestApp.A2).to(TestApp.A1), + Rollback.from(TestApp.B2).to(TestApp.B1)); // Rollback the app. It should cause both test apps to be rolled // back. - RollbackTestUtils.rollback(rollback.getRollbackId()); - assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); - assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B)); + RollbackUtils.rollback(rollback.getRollbackId()); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1); + assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1); // We should see recent rollbacks listed for both A and B. Thread.sleep(1000); RollbackInfo rollbackA = getUniqueRollbackInfoForPackage( - rm.getRecentlyCommittedRollbacks(), TEST_APP_A); + rm.getRecentlyCommittedRollbacks(), TestApp.A); RollbackInfo rollbackB = getUniqueRollbackInfoForPackage( - rm.getRecentlyCommittedRollbacks(), TEST_APP_B); - assertRollbackInfoForAandB(rollbackB); + rm.getRecentlyCommittedRollbacks(), TestApp.B); + assertThat(rollback).packagesContainsExactly( + Rollback.from(TestApp.A2).to(TestApp.A1), + Rollback.from(TestApp.B2).to(TestApp.B1)); - assertEquals(rollbackA.getRollbackId(), rollbackB.getRollbackId()); + assertThat(rollbackA).hasRollbackId(rollbackB.getRollbackId()); - processUserData(TEST_APP_A); - processUserData(TEST_APP_B); + processUserData(TestApp.A); + processUserData(TestApp.B); } finally { - RollbackTestUtils.dropShellPermissionIdentity(); + InstallUtils.dropShellPermissionIdentity(); } } @@ -790,31 +870,27 @@ public class RollbackTest { @Test public void testMultiPackageEnableFail() throws Exception { try { - RollbackTestUtils.adoptShellPermissionIdentity( + InstallUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, Manifest.permission.TEST_MANAGE_ROLLBACKS); - RollbackManager rm = RollbackTestUtils.getRollbackManager(); - - RollbackTestUtils.uninstall(TEST_APP_A); - RollbackTestUtils.uninstall(TEST_APP_B); - RollbackTestUtils.install("RollbackTestAppAv1.apk", false); + RollbackManager rm = RollbackUtils.getRollbackManager(); + Uninstall.packages(TestApp.A, TestApp.B); + Install.single(TestApp.A1).commit(); // We should fail to enable rollback here because TestApp B is not // already installed. - RollbackTestUtils.installMultiPackage(true, - "RollbackTestAppAv2.apk", - "RollbackTestAppBv2.apk"); + Install.multi(TestApp.A2, TestApp.B2).setEnableRollback().commit(); - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B)); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2); + assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2); - assertNull(getUniqueRollbackInfoForPackage( - rm.getAvailableRollbacks(), TEST_APP_A)); - assertNull(getUniqueRollbackInfoForPackage( - rm.getAvailableRollbacks(), TEST_APP_B)); + assertThat(getUniqueRollbackInfoForPackage( + rm.getAvailableRollbacks(), TestApp.A)).isNull(); + assertThat(getUniqueRollbackInfoForPackage( + rm.getAvailableRollbacks(), TestApp.B)).isNull(); } finally { - RollbackTestUtils.dropShellPermissionIdentity(); + InstallUtils.dropShellPermissionIdentity(); } } @@ -825,30 +901,33 @@ public class RollbackTest { */ public void testSameVersionUpdate() throws Exception { try { - RollbackTestUtils.adoptShellPermissionIdentity( + InstallUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, Manifest.permission.TEST_MANAGE_ROLLBACKS); - RollbackManager rm = RollbackTestUtils.getRollbackManager(); + RollbackManager rm = RollbackUtils.getRollbackManager(); - RollbackTestUtils.uninstall(TEST_APP_A); - RollbackTestUtils.install("RollbackTestAppAv1.apk", false); - RollbackTestUtils.install("RollbackTestAppAv2.apk", true); - RollbackTestUtils.install("RollbackTestAppACrashingV2.apk", true); - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + Uninstall.packages(TestApp.A); + Install.single(TestApp.A1).commit(); + Install.single(TestApp.A2).setEnableRollback().commit(); + Install.single(TestApp.ACrashing2).setEnableRollback().commit(); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2); RollbackInfo rollback = getUniqueRollbackInfoForPackage( - rm.getAvailableRollbacks(), TEST_APP_A); - assertRollbackInfoEquals(TEST_APP_A, 2, 2, rollback); + rm.getAvailableRollbacks(), TestApp.A); + assertThat(rollback).isNotNull(); + assertThat(rollback).packagesContainsExactly( + Rollback.from(TestApp.A2).to(TestApp.A2)); - RollbackTestUtils.rollback(rollback.getRollbackId()); - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + RollbackUtils.rollback(rollback.getRollbackId()); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2); rollback = getUniqueRollbackInfoForPackage( - rm.getRecentlyCommittedRollbacks(), TEST_APP_A); - assertRollbackInfoEquals(TEST_APP_A, 2, 2, rollback); + rm.getRecentlyCommittedRollbacks(), TestApp.A); + assertThat(rollback).packagesContainsExactly( + Rollback.from(TestApp.A2).to(TestApp.A2)); } finally { - RollbackTestUtils.dropShellPermissionIdentity(); + InstallUtils.dropShellPermissionIdentity(); } } @@ -860,54 +939,55 @@ public class RollbackTest { BroadcastReceiver crashCountReceiver = null; Context context = InstrumentationRegistry.getContext(); try { - RollbackTestUtils.adoptShellPermissionIdentity( + InstallUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, Manifest.permission.MANAGE_ROLLBACKS, Manifest.permission.TEST_MANAGE_ROLLBACKS, Manifest.permission.KILL_BACKGROUND_PROCESSES, Manifest.permission.RESTART_PACKAGES); - RollbackManager rm = RollbackTestUtils.getRollbackManager(); + RollbackManager rm = RollbackUtils.getRollbackManager(); // Prep installation of the test apps. - RollbackTestUtils.uninstall(TEST_APP_A); - RollbackTestUtils.install("RollbackTestAppAv1.apk", false); - RollbackTestUtils.install("RollbackTestAppACrashingV2.apk", true); - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + Uninstall.packages(TestApp.A, TestApp.B); + Install.single(TestApp.A1).commit(); + Install.single(TestApp.ACrashing2).setEnableRollback().commit(); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2); - RollbackTestUtils.uninstall(TEST_APP_B); - RollbackTestUtils.install("RollbackTestAppBv1.apk", false); - RollbackTestUtils.install("RollbackTestAppBv2.apk", true); - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B)); + Install.single(TestApp.B1).commit(); + Install.single(TestApp.B2).setEnableRollback().commit(); + assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2); // Both test apps should now be available for rollback, and the // targetPackage returned for rollback should be correct. RollbackInfo rollbackA = getUniqueRollbackInfoForPackage( - rm.getAvailableRollbacks(), TEST_APP_A); - assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA); + rm.getAvailableRollbacks(), TestApp.A); + assertThat(rollbackA).packagesContainsExactly( + Rollback.from(TestApp.A2).to(TestApp.A1)); RollbackInfo rollbackB = getUniqueRollbackInfoForPackage( - rm.getAvailableRollbacks(), TEST_APP_B); - assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB); + rm.getAvailableRollbacks(), TestApp.B); + assertThat(rollbackB).packagesContainsExactly( + Rollback.from(TestApp.B2).to(TestApp.B1)); // Register rollback committed receiver RollbackBroadcastReceiver rollbackReceiver = new RollbackBroadcastReceiver(); - // Crash TEST_APP_A PackageWatchdog#TRIGGER_FAILURE_COUNT times to trigger rollback - crashCountReceiver = RollbackTestUtils.sendCrashBroadcast(context, TEST_APP_A, 5); + // Crash TestApp.A PackageWatchdog#TRIGGER_FAILURE_COUNT times to trigger rollback + crashCountReceiver = RollbackUtils.sendCrashBroadcast(context, TestApp.A, 5); // Verify we received a broadcast for the rollback. rollbackReceiver.take(); - // TEST_APP_A is automatically rolled back by the RollbackPackageHealthObserver - assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + // TestApp.A is automatically rolled back by the RollbackPackageHealthObserver + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1); // Instrumented app is still the package installer - String installer = context.getPackageManager().getInstallerPackageName(TEST_APP_A); - assertEquals(INSTRUMENTED_APP, installer); - // TEST_APP_B is untouched - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B)); + String installer = context.getPackageManager().getInstallerPackageName(TestApp.A); + assertThat(installer).isEqualTo(INSTRUMENTED_APP); + // TestApp.B is untouched + assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2); } finally { - RollbackTestUtils.dropShellPermissionIdentity(); + InstallUtils.dropShellPermissionIdentity(); if (crashCountReceiver != null) { context.unregisterReceiver(crashCountReceiver); } @@ -920,31 +1000,32 @@ public class RollbackTest { @Test public void testRollForwardRace() throws Exception { try { - RollbackTestUtils.adoptShellPermissionIdentity( + InstallUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, Manifest.permission.TEST_MANAGE_ROLLBACKS, Manifest.permission.MANAGE_ROLLBACKS); - RollbackManager rm = RollbackTestUtils.getRollbackManager(); + RollbackManager rm = RollbackUtils.getRollbackManager(); - RollbackTestUtils.uninstall(TEST_APP_A); - RollbackTestUtils.install("RollbackTestAppAv1.apk", false); - RollbackTestUtils.install("RollbackTestAppAv2.apk", true); - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + Uninstall.packages(TestApp.A); + Install.single(TestApp.A1).commit(); + Install.single(TestApp.A2).setEnableRollback().commit(); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2); RollbackInfo rollback = getUniqueRollbackInfoForPackage( - rm.getAvailableRollbacks(), TEST_APP_A); - assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback); + rm.getAvailableRollbacks(), TestApp.A); + assertThat(rollback).packagesContainsExactly( + Rollback.from(TestApp.A2).to(TestApp.A1)); // Install a new version of package A, then immediately rollback // the previous version. We expect the rollback to fail, because // it is no longer available. // There are a couple different ways this could fail depending on // thread interleaving, so don't ignore flaky failures. - RollbackTestUtils.install("RollbackTestAppAv3.apk", false); + Install.single(TestApp.A3).commit(); try { - RollbackTestUtils.rollback(rollback.getRollbackId()); + RollbackUtils.rollback(rollback.getRollbackId()); // Note: Don't ignore flaky failures here. fail("Expected rollback to fail, but it did not."); } catch (AssertionError e) { @@ -953,9 +1034,9 @@ public class RollbackTest { } // Note: Don't ignore flaky failures here. - assertEquals(3, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(3); } finally { - RollbackTestUtils.dropShellPermissionIdentity(); + InstallUtils.dropShellPermissionIdentity(); } } @@ -963,7 +1044,7 @@ public class RollbackTest { @Ignore("b/136605788") public void testEnableRollbackTimeoutFailsRollback() throws Exception { try { - RollbackTestUtils.adoptShellPermissionIdentity( + InstallUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, Manifest.permission.TEST_MANAGE_ROLLBACKS, @@ -973,36 +1054,27 @@ public class RollbackTest { //setting the timeout to a very short amount that will definitely be triggered DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK, PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS, - Long.toString(1), false /* makeDefault*/); - RollbackManager rm = RollbackTestUtils.getRollbackManager(); + Long.toString(0), false /* makeDefault*/); + RollbackManager rm = RollbackUtils.getRollbackManager(); - RollbackTestUtils.uninstall(TEST_APP_A); - RollbackTestUtils.install("RollbackTestAppAv1.apk", false); - RollbackTestUtils.install("RollbackTestAppAv2.apk", true); + Uninstall.packages(TestApp.A); + Install.single(TestApp.A1).commit(); - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + // Block the RollbackManager to make extra sure it will not be + // able to enable the rollback in time. + rm.blockRollbackManager(TimeUnit.SECONDS.toMillis(1)); + Install.single(TestApp.A2).setEnableRollback().commit(); - assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A)); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2); + + assertThat( + getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TestApp.A)).isNull(); } finally { //setting the timeout back to default DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK, PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS, null, false /* makeDefault*/); - RollbackTestUtils.dropShellPermissionIdentity(); - } - } - - // Helper function to test that the given rollback info is a rollback for - // the atomic set {A2, B2} -> {A1, B1}. - private void assertRollbackInfoForAandB(RollbackInfo rollback) { - assertNotNull(rollback); - assertEquals(2, rollback.getPackages().size()); - if (TEST_APP_A.equals(rollback.getPackages().get(0).getPackageName())) { - assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.getPackages().get(0)); - assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollback.getPackages().get(1)); - } else { - assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollback.getPackages().get(0)); - assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.getPackages().get(1)); + InstallUtils.dropShellPermissionIdentity(); } } } diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java deleted file mode 100644 index a9e20cdb191b4..0000000000000 --- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java +++ /dev/null @@ -1,547 +0,0 @@ -/* - * 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 com.android.tests.rollback; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; - -import android.app.ActivityManager; -import android.app.AlarmManager; -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageInstaller; -import android.content.pm.PackageManager; -import android.content.pm.VersionedPackage; -import android.content.rollback.PackageRollbackInfo; -import android.content.rollback.RollbackInfo; -import android.content.rollback.RollbackManager; -import android.os.Handler; -import android.os.HandlerThread; -import android.util.Log; - -import androidx.test.InstrumentationRegistry; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.SynchronousQueue; - -/** - * Utilities to facilitate testing rollbacks. - */ -class RollbackTestUtils { - - private static final String TAG = "RollbackTest"; - - static RollbackManager getRollbackManager() { - Context context = InstrumentationRegistry.getContext(); - RollbackManager rm = (RollbackManager) context.getSystemService(Context.ROLLBACK_SERVICE); - if (rm == null) { - throw new AssertionError("Failed to get RollbackManager"); - } - return rm; - } - - private static void setTime(long millis) { - Context context = InstrumentationRegistry.getContext(); - AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - am.setTime(millis); - } - - static void forwardTimeBy(long offsetMillis) { - setTime(System.currentTimeMillis() + offsetMillis); - Log.i(TAG, "Forwarded time on device by " + offsetMillis + " millis"); - } - - /** - * Returns the version of the given package installed on device. - * Returns -1 if the package is not currently installed. - */ - static long getInstalledVersion(String packageName) { - PackageInfo pi = getPackageInfo(packageName); - if (pi == null) { - return -1; - } else { - return pi.getLongVersionCode(); - } - } - - private static boolean isSystemAppWithoutUpdate(String packageName) { - PackageInfo pi = getPackageInfo(packageName); - if (pi == null) { - return false; - } else { - return ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) - && ((pi.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0); - } - } - - private static PackageInfo getPackageInfo(String packageName) { - Context context = InstrumentationRegistry.getContext(); - PackageManager pm = context.getPackageManager(); - try { - return pm.getPackageInfo(packageName, PackageManager.MATCH_APEX); - } catch (PackageManager.NameNotFoundException e) { - return null; - } - } - - private static void assertStatusSuccess(Intent result) { - int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS, - PackageInstaller.STATUS_FAILURE); - if (status == -1) { - throw new AssertionError("PENDING USER ACTION"); - } else if (status > 0) { - String message = result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE); - throw new AssertionError(message == null ? "UNKNOWN FAILURE" : message); - } - } - - /** - * Uninstalls the given package. - * Does nothing if the package is not installed. - * @throws AssertionError if package can't be uninstalled. - */ - static void uninstall(String packageName) throws InterruptedException, IOException { - // No need to uninstall if the package isn't installed or is installed on /system. - if (getInstalledVersion(packageName) == -1 || isSystemAppWithoutUpdate(packageName)) { - return; - } - - Context context = InstrumentationRegistry.getContext(); - PackageManager packageManager = context.getPackageManager(); - PackageInstaller packageInstaller = packageManager.getPackageInstaller(); - packageInstaller.uninstall(packageName, LocalIntentSender.getIntentSender()); - assertStatusSuccess(LocalIntentSender.getIntentSenderResult()); - } - - /** - * Commit the given rollback. - * @throws AssertionError if the rollback fails. - */ - static void rollback(int rollbackId, VersionedPackage... causePackages) - throws InterruptedException { - RollbackManager rm = getRollbackManager(); - rm.commitRollback(rollbackId, Arrays.asList(causePackages), - LocalIntentSender.getIntentSender()); - Intent result = LocalIntentSender.getIntentSenderResult(); - int status = result.getIntExtra(RollbackManager.EXTRA_STATUS, - RollbackManager.STATUS_FAILURE); - if (status != RollbackManager.STATUS_SUCCESS) { - String message = result.getStringExtra(RollbackManager.EXTRA_STATUS_MESSAGE); - throw new AssertionError(message); - } - } - - /** - * Installs the apk with the given name. - * - * @param resourceName name of class loader resource for the apk to - * install. - * @param enableRollback if rollback should be enabled. - * @throws AssertionError if the installation fails. - */ - static void install(String resourceName, boolean enableRollback) - throws InterruptedException, IOException { - installSplit(enableRollback, resourceName); - } - - /** - * Installs the apk with the given name and its splits. - * - * @param enableRollback if rollback should be enabled. - * @param resourceNames names of class loader resources for the apk and - * its splits to install. - * @throws AssertionError if the installation fails. - */ - static void installSplit(boolean enableRollback, String... resourceNames) - throws InterruptedException, IOException { - Context context = InstrumentationRegistry.getContext(); - PackageInstaller.Session session = null; - PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller(); - PackageInstaller.SessionParams params = new PackageInstaller.SessionParams( - PackageInstaller.SessionParams.MODE_FULL_INSTALL); - params.setEnableRollback(enableRollback); - int sessionId = packageInstaller.createSession(params); - session = packageInstaller.openSession(sessionId); - - ClassLoader loader = RollbackTest.class.getClassLoader(); - for (String resourceName : resourceNames) { - try (OutputStream packageInSession = session.openWrite(resourceName, 0, -1); - InputStream is = loader.getResourceAsStream(resourceName);) { - byte[] buffer = new byte[4096]; - int n; - while ((n = is.read(buffer)) >= 0) { - packageInSession.write(buffer, 0, n); - } - } - } - - // Commit the session (this will start the installation workflow). - session.commit(LocalIntentSender.getIntentSender()); - assertStatusSuccess(LocalIntentSender.getIntentSenderResult()); - } - - /** Launches {@code packageName} with {@link Intent#ACTION_MAIN}. */ - private static void launchPackage(String packageName) - throws InterruptedException, IOException { - Context context = InstrumentationRegistry.getContext(); - Intent intent = new Intent(Intent.ACTION_MAIN); - intent.setPackage(packageName); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.addCategory(Intent.CATEGORY_LAUNCHER); - context.startActivity(intent); - } - - /** - * Installs the APKs or APEXs with the given resource names as an atomic - * set. A resource is assumed to be an APEX if it has the .apex extension. - *

- * In case of staged installs, this function will return succesfully after - * the staged install has been committed and is ready for the device to - * reboot. - * - * @param staged if the rollback should be staged. - * @param enableRollback if rollback should be enabled. - * @param resourceNames names of the class loader resource for the apks to - * install. - * @throws AssertionError if the installation fails. - */ - private static void install(boolean staged, boolean enableRollback, - String... resourceNames) throws InterruptedException, IOException { - Context context = InstrumentationRegistry.getContext(); - PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller(); - - PackageInstaller.SessionParams multiPackageParams = new PackageInstaller.SessionParams( - PackageInstaller.SessionParams.MODE_FULL_INSTALL); - multiPackageParams.setMultiPackage(); - if (staged) { - multiPackageParams.setStaged(); - } - // TODO: Do we set this on the parent params, the child params, or - // both? - multiPackageParams.setEnableRollback(enableRollback); - int multiPackageId = packageInstaller.createSession(multiPackageParams); - PackageInstaller.Session multiPackage = packageInstaller.openSession(multiPackageId); - - for (String resourceName : resourceNames) { - PackageInstaller.Session session = null; - PackageInstaller.SessionParams params = new PackageInstaller.SessionParams( - PackageInstaller.SessionParams.MODE_FULL_INSTALL); - if (staged) { - params.setStaged(); - } - if (resourceName.endsWith(".apex")) { - params.setInstallAsApex(); - } - params.setEnableRollback(enableRollback); - int sessionId = packageInstaller.createSession(params); - session = packageInstaller.openSession(sessionId); - - ClassLoader loader = RollbackTest.class.getClassLoader(); - try (OutputStream packageInSession = session.openWrite(resourceName, 0, -1); - InputStream is = loader.getResourceAsStream(resourceName);) { - byte[] buffer = new byte[4096]; - int n; - while ((n = is.read(buffer)) >= 0) { - packageInSession.write(buffer, 0, n); - } - } - multiPackage.addChildSessionId(sessionId); - } - - // Commit the session (this will start the installation workflow). - multiPackage.commit(LocalIntentSender.getIntentSender()); - assertStatusSuccess(LocalIntentSender.getIntentSenderResult()); - - if (staged) { - waitForSessionReady(multiPackageId); - } - } - - /** - * Installs the apks with the given resource names as an atomic set. - * - * @param enableRollback if rollback should be enabled. - * @param resourceNames names of the class loader resource for the apks to - * install. - * @throws AssertionError if the installation fails. - */ - static void installMultiPackage(boolean enableRollback, String... resourceNames) - throws InterruptedException, IOException { - install(false, enableRollback, resourceNames); - } - - /** - * Installs the APKs or APEXs with the given resource names as a staged - * atomic set. A resource is assumed to be an APEX if it has the .apex - * extension. - * - * @param enableRollback if rollback should be enabled. - * @param resourceNames names of the class loader resource for the apks to - * install. - * @throws AssertionError if the installation fails. - */ - static void installStaged(boolean enableRollback, String... resourceNames) - throws InterruptedException, IOException { - install(true, enableRollback, resourceNames); - } - - static void adoptShellPermissionIdentity(String... permissions) { - InstrumentationRegistry - .getInstrumentation() - .getUiAutomation() - .adoptShellPermissionIdentity(permissions); - } - - static void dropShellPermissionIdentity() { - InstrumentationRegistry - .getInstrumentation() - .getUiAutomation() - .dropShellPermissionIdentity(); - } - - /** - * Returns the RollbackInfo with a given package in the list of rollbacks. - * Throws an assertion failure if there is more than one such rollback - * info. Returns null if there are no such rollback infos. - */ - static RollbackInfo getUniqueRollbackInfoForPackage(List rollbacks, - String packageName) { - RollbackInfo found = null; - for (RollbackInfo rollback : rollbacks) { - for (PackageRollbackInfo info : rollback.getPackages()) { - if (packageName.equals(info.getPackageName())) { - assertNull(found); - found = rollback; - break; - } - } - } - return found; - } - - /** - * Asserts that the given PackageRollbackInfo has the expected package - * name and versions. - */ - static void assertPackageRollbackInfoEquals(String packageName, - long versionRolledBackFrom, long versionRolledBackTo, - PackageRollbackInfo info) { - assertEquals(packageName, info.getPackageName()); - assertEquals(packageName, info.getVersionRolledBackFrom().getPackageName()); - assertEquals(versionRolledBackFrom, info.getVersionRolledBackFrom().getLongVersionCode()); - assertEquals(packageName, info.getVersionRolledBackTo().getPackageName()); - assertEquals(versionRolledBackTo, info.getVersionRolledBackTo().getLongVersionCode()); - } - - /** - * Asserts that the given RollbackInfo has the given packages with expected - * package names and all are rolled to and from the same given versions. - */ - static void assertRollbackInfoEquals(String[] packageNames, - long versionRolledBackFrom, long versionRolledBackTo, - RollbackInfo info, VersionedPackage... causePackages) { - assertNotNull(info); - assertEquals(packageNames.length, info.getPackages().size()); - int foundPackages = 0; - for (String packageName : packageNames) { - for (PackageRollbackInfo pkgRollbackInfo : info.getPackages()) { - if (packageName.equals(pkgRollbackInfo.getPackageName())) { - foundPackages++; - assertPackageRollbackInfoEquals(packageName, versionRolledBackFrom, - versionRolledBackTo, pkgRollbackInfo); - break; - } - } - } - assertEquals(packageNames.length, foundPackages); - assertEquals(causePackages.length, info.getCausePackages().size()); - for (int i = 0; i < causePackages.length; ++i) { - assertEquals(causePackages[i].getPackageName(), - info.getCausePackages().get(i).getPackageName()); - assertEquals(causePackages[i].getLongVersionCode(), - info.getCausePackages().get(i).getLongVersionCode()); - } - } - - /** - * Asserts that the given RollbackInfo has a single package with expected - * package name and versions. - */ - static void assertRollbackInfoEquals(String packageName, - long versionRolledBackFrom, long versionRolledBackTo, - RollbackInfo info, VersionedPackage... causePackages) { - String[] packageNames = {packageName}; - assertRollbackInfoEquals(packageNames, versionRolledBackFrom, versionRolledBackTo, info, - causePackages); - } - - /** - * Waits for the given session to be marked as ready. - * Throws an assertion if the session fails. - */ - static void waitForSessionReady(int sessionId) { - BlockingQueue sessionStatus = new LinkedBlockingQueue<>(); - BroadcastReceiver sessionUpdatedReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - PackageInstaller.SessionInfo info = - intent.getParcelableExtra(PackageInstaller.EXTRA_SESSION); - if (info != null && info.getSessionId() == sessionId) { - if (info.isStagedSessionReady() || info.isStagedSessionFailed()) { - try { - sessionStatus.put(info); - } catch (InterruptedException e) { - Log.e(TAG, "Failed to put session info.", e); - } - } - } - } - }; - IntentFilter sessionUpdatedFilter = - new IntentFilter(PackageInstaller.ACTION_SESSION_UPDATED); - - Context context = InstrumentationRegistry.getContext(); - context.registerReceiver(sessionUpdatedReceiver, sessionUpdatedFilter); - - PackageInstaller installer = context.getPackageManager().getPackageInstaller(); - PackageInstaller.SessionInfo info = installer.getSessionInfo(sessionId); - - try { - if (info.isStagedSessionReady() || info.isStagedSessionFailed()) { - sessionStatus.put(info); - } - - info = sessionStatus.take(); - context.unregisterReceiver(sessionUpdatedReceiver); - if (info.isStagedSessionFailed()) { - throw new AssertionError(info.getStagedSessionErrorMessage()); - } - } catch (InterruptedException e) { - throw new AssertionError(e); - } - } - - private static final String NO_RESPONSE = "NO RESPONSE"; - - /** - * Calls into the test app to process user data. - * Asserts if the user data could not be processed or was version - * incompatible with the previously processed user data. - */ - static void processUserData(String packageName) { - Intent intent = new Intent(); - intent.setComponent(new ComponentName(packageName, - "com.android.tests.rollback.testapp.ProcessUserData")); - Context context = InstrumentationRegistry.getContext(); - - HandlerThread handlerThread = new HandlerThread("RollbackTestHandlerThread"); - handlerThread.start(); - - // It can sometimes take a while after rollback before the app will - // receive this broadcast, so try a few times in a loop. - String result = NO_RESPONSE; - for (int i = 0; result.equals(NO_RESPONSE) && i < 5; ++i) { - BlockingQueue resultQueue = new LinkedBlockingQueue<>(); - context.sendOrderedBroadcast(intent, null, new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (getResultCode() == 1) { - resultQueue.add("OK"); - } else { - // If the test app doesn't receive the broadcast or - // fails to set the result data, then getResultData - // here returns the initial NO_RESPONSE data passed to - // the sendOrderedBroadcast call. - resultQueue.add(getResultData()); - } - } - }, new Handler(handlerThread.getLooper()), 0, NO_RESPONSE, null); - - try { - result = resultQueue.take(); - } catch (InterruptedException e) { - throw new AssertionError(e); - } - } - - handlerThread.quit(); - if (!"OK".equals(result)) { - fail(result); - } - } - - /** - * Return the rollback info for a recently committed rollback, by matching the rollback id, or - * return null if no matching rollback is found. - */ - static RollbackInfo getRecentlyCommittedRollbackInfoById(int getRollbackId) { - for (RollbackInfo info : getRollbackManager().getRecentlyCommittedRollbacks()) { - if (info.getRollbackId() == getRollbackId) { - return info; - } - } - return null; - } - - /** - * Send broadcast to crash {@code packageName} {@code count} times. If {@code count} is at least - * {@link PackageWatchdog#TRIGGER_FAILURE_COUNT}, watchdog crash detection will be triggered. - */ - static BroadcastReceiver sendCrashBroadcast(Context context, String packageName, int count) - throws InterruptedException, IOException { - BlockingQueue crashQueue = new SynchronousQueue<>(); - IntentFilter crashCountFilter = new IntentFilter(); - crashCountFilter.addAction("com.android.tests.rollback.CRASH"); - crashCountFilter.addCategory(Intent.CATEGORY_DEFAULT); - - BroadcastReceiver crashCountReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - try { - // Sleep long enough for packagewatchdog to be notified of crash - Thread.sleep(1000); - // Kill app and close AppErrorDialog - ActivityManager am = context.getSystemService(ActivityManager.class); - am.killBackgroundProcesses(packageName); - // Allow another package launch - crashQueue.put(intent.getIntExtra("count", 0)); - } catch (InterruptedException e) { - fail("Failed to communicate with test app"); - } - } - }; - context.registerReceiver(crashCountReceiver, crashCountFilter); - - do { - launchPackage(packageName); - } while(crashQueue.take() < count); - return crashCountReceiver; - } -} diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java index 1a29c4c114579..db8183124f59f 100644 --- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java +++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java @@ -16,26 +16,35 @@ package com.android.tests.rollback; -import static com.android.tests.rollback.RollbackTestUtils.assertRollbackInfoEquals; -import static com.android.tests.rollback.RollbackTestUtils.getUniqueRollbackInfoForPackage; +import static com.android.cts.rollback.lib.RollbackInfoSubject.assertThat; +import static com.android.cts.rollback.lib.RollbackUtils.getUniqueRollbackInfoForPackage; + +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.fail; import android.Manifest; +import android.annotation.Nullable; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.pm.VersionedPackage; +import android.content.pm.PackageInfo; +import android.content.pm.PackageInstaller; import android.content.rollback.RollbackInfo; import android.content.rollback.RollbackManager; +import android.text.TextUtils; import androidx.test.InstrumentationRegistry; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -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 com.android.cts.install.lib.Install; +import com.android.cts.install.lib.InstallUtils; +import com.android.cts.install.lib.LocalIntentSender; +import com.android.cts.install.lib.TestApp; +import com.android.cts.install.lib.Uninstall; +import com.android.cts.rollback.lib.Rollback; +import com.android.cts.rollback.lib.RollbackUtils; +import com.android.internal.R; import org.junit.After; import org.junit.Before; @@ -54,19 +63,17 @@ import org.junit.runners.JUnit4; @RunWith(JUnit4.class) public class StagedRollbackTest { - private static final String TAG = "RollbackTest"; - private static final String TEST_APP_A = "com.android.tests.rollback.testapp.A"; - private static final String TEST_APP_A_V1 = "RollbackTestAppAv1.apk"; - private static final String TEST_APP_A_CRASHING_V2 = "RollbackTestAppACrashingV2.apk"; private static final String NETWORK_STACK_CONNECTOR_CLASS = "android.net.INetworkStackConnector"; + private static final String MODULE_META_DATA_PACKAGE = getModuleMetadataPackageName(); + /** * Adopts common shell permissions needed for rollback tests. */ @Before public void adoptShellPermissions() { - RollbackTestUtils.adoptShellPermissionIdentity( + InstallUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, Manifest.permission.DELETE_PACKAGES, Manifest.permission.TEST_MANAGE_ROLLBACKS, @@ -78,7 +85,7 @@ public class StagedRollbackTest { */ @After public void dropShellPermissions() { - RollbackTestUtils.dropShellPermissionIdentity(); + InstallUtils.dropShellPermissionIdentity(); } /** @@ -87,14 +94,14 @@ public class StagedRollbackTest { */ @Test public void testBadApkOnlyEnableRollback() throws Exception { - RollbackTestUtils.uninstall(TEST_APP_A); - assertEquals(-1, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + Uninstall.packages(TestApp.A); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1); - RollbackTestUtils.install(TEST_APP_A_V1, false); - assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); - RollbackTestUtils.processUserData(TEST_APP_A); + Install.single(TestApp.A1).commit(); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1); + InstallUtils.processUserData(TestApp.A); - RollbackTestUtils.installStaged(true, TEST_APP_A_CRASHING_V2); + Install.single(TestApp.ACrashing2).setEnableRollback().setStaged().commit(); // At this point, the host test driver will reboot the device and run // testBadApkOnlyConfirmEnableRollback(). @@ -106,14 +113,16 @@ public class StagedRollbackTest { */ @Test public void testBadApkOnlyConfirmEnableRollback() throws Exception { - assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); - RollbackTestUtils.processUserData(TEST_APP_A); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2); + InstallUtils.processUserData(TestApp.A); - RollbackManager rm = RollbackTestUtils.getRollbackManager(); + RollbackManager rm = RollbackUtils.getRollbackManager(); RollbackInfo rollback = getUniqueRollbackInfoForPackage( - rm.getAvailableRollbacks(), TEST_APP_A); - assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback); - assertTrue(rollback.isStaged()); + rm.getAvailableRollbacks(), TestApp.A); + assertThat(rollback).isNotNull(); + assertThat(rollback).packagesContainsExactly( + Rollback.from(TestApp.A2).to(TestApp.A1)); + assertThat(rollback.isStaged()).isTrue(); // At this point, the host test driver will run // testBadApkOnlyTriggerRollback(). @@ -128,11 +137,10 @@ public class StagedRollbackTest { public void testBadApkOnlyTriggerRollback() throws Exception { BroadcastReceiver crashCountReceiver = null; Context context = InstrumentationRegistry.getContext(); - RollbackManager rm = RollbackTestUtils.getRollbackManager(); try { - // Crash TEST_APP_A PackageWatchdog#TRIGGER_FAILURE_COUNT times to trigger rollback - crashCountReceiver = RollbackTestUtils.sendCrashBroadcast(context, TEST_APP_A, 5); + // Crash TestApp.A PackageWatchdog#TRIGGER_FAILURE_COUNT times to trigger rollback + crashCountReceiver = RollbackUtils.sendCrashBroadcast(context, TestApp.A, 5); } finally { if (crashCountReceiver != null) { context.unregisterReceiver(crashCountReceiver); @@ -153,48 +161,80 @@ public class StagedRollbackTest { */ @Test public void testBadApkOnlyConfirmRollback() throws Exception { - assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); - RollbackTestUtils.processUserData(TEST_APP_A); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1); + InstallUtils.processUserData(TestApp.A); - RollbackManager rm = RollbackTestUtils.getRollbackManager(); + RollbackManager rm = RollbackUtils.getRollbackManager(); RollbackInfo rollback = getUniqueRollbackInfoForPackage( - rm.getRecentlyCommittedRollbacks(), TEST_APP_A); - assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback, new VersionedPackage(TEST_APP_A, 2)); - assertTrue(rollback.isStaged()); - assertNotEquals(-1, rollback.getCommittedSessionId()); + rm.getRecentlyCommittedRollbacks(), TestApp.A); + assertThat(rollback).isNotNull(); + assertThat(rollback).packagesContainsExactly( + Rollback.from(TestApp.A2).to(TestApp.A1)); + assertThat(rollback).causePackagesContainsExactly(TestApp.ACrashing2); + assertThat(rollback).isStaged(); + assertThat(rollback.getCommittedSessionId()).isNotEqualTo(-1); } @Test public void resetNetworkStack() throws Exception { - RollbackManager rm = RollbackTestUtils.getRollbackManager(); + RollbackManager rm = RollbackUtils.getRollbackManager(); String networkStack = getNetworkStackPackageName(); rm.expireRollbackForPackage(networkStack); - RollbackTestUtils.uninstall(networkStack); + Uninstall.packages(networkStack); - assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), - networkStack)); + assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), + networkStack)).isNull(); + } + + @Test + public void installModuleMetadataPackage() throws Exception { + resetModuleMetadataPackage(); + Context context = InstrumentationRegistry.getContext(); + PackageInfo metadataPackageInfo = context.getPackageManager().getPackageInfo( + MODULE_META_DATA_PACKAGE, 0); + String metadataApkPath = metadataPackageInfo.applicationInfo.sourceDir; + assertThat(metadataApkPath).isNotNull(); + assertThat(metadataApkPath).isNotEqualTo(""); + + runShellCommand("pm install " + + "-r --enable-rollback --staged --wait " + + metadataApkPath); } @Test public void assertNetworkStackRollbackAvailable() throws Exception { - RollbackManager rm = RollbackTestUtils.getRollbackManager(); - assertNotNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), - getNetworkStackPackageName())); + RollbackManager rm = RollbackUtils.getRollbackManager(); + assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), + getNetworkStackPackageName())).isNotNull(); } @Test public void assertNetworkStackRollbackCommitted() throws Exception { - RollbackManager rm = RollbackTestUtils.getRollbackManager(); - assertNotNull(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(), - getNetworkStackPackageName())); + RollbackManager rm = RollbackUtils.getRollbackManager(); + assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(), + getNetworkStackPackageName())).isNotNull(); } @Test public void assertNoNetworkStackRollbackCommitted() throws Exception { - RollbackManager rm = RollbackTestUtils.getRollbackManager(); - assertNull(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(), - getNetworkStackPackageName())); + RollbackManager rm = RollbackUtils.getRollbackManager(); + assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(), + getNetworkStackPackageName())).isNull(); + } + + @Test + public void assertModuleMetadataRollbackAvailable() throws Exception { + RollbackManager rm = RollbackUtils.getRollbackManager(); + assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), + MODULE_META_DATA_PACKAGE)).isNotNull(); + } + + @Test + public void assertModuleMetadataRollbackCommitted() throws Exception { + RollbackManager rm = RollbackUtils.getRollbackManager(); + assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(), + MODULE_META_DATA_PACKAGE)).isNotNull(); } private String getNetworkStackPackageName() { @@ -203,4 +243,65 @@ public class StagedRollbackTest { InstrumentationRegistry.getContext().getPackageManager(), 0); return comp.getPackageName(); } + + @Test + public void testPreviouslyAbandonedRollbacksEnableRollback() throws Exception { + Uninstall.packages(TestApp.A); + Install.single(TestApp.A1).commit(); + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1); + + int sessionId = Install.single(TestApp.A2).setStaged().setEnableRollback().commit(); + PackageInstaller pi = InstrumentationRegistry.getContext().getPackageManager() + .getPackageInstaller(); + pi.abandonSession(sessionId); + + // Remove the first intent sender result, so that the next staged install session does not + // erroneously think that it has itself been abandoned. + // TODO(b/136260017): Restructure LocalIntentSender to negate the need for this step. + LocalIntentSender.getIntentSenderResult(); + Install.single(TestApp.A2).setStaged().setEnableRollback().commit(); + } + + @Test + public void testPreviouslyAbandonedRollbacksCommitRollback() throws Exception { + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2); + InstallUtils.processUserData(TestApp.A); + + RollbackManager rm = RollbackUtils.getRollbackManager(); + RollbackInfo rollback = getUniqueRollbackInfoForPackage( + rm.getAvailableRollbacks(), TestApp.A); + RollbackUtils.rollback(rollback.getRollbackId()); + } + + @Test + public void testPreviouslyAbandonedRollbacksCheckUserdataRollback() throws Exception { + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1); + InstallUtils.processUserData(TestApp.A); + Uninstall.packages(TestApp.A); + } + + @Nullable + private static String getModuleMetadataPackageName() { + String packageName = InstrumentationRegistry.getContext().getResources().getString( + R.string.config_defaultModuleMetadataProvider); + if (TextUtils.isEmpty(packageName)) { + return null; + } + return packageName; + } + + private void resetModuleMetadataPackage() { + RollbackManager rm = RollbackUtils.getRollbackManager(); + + assertThat(MODULE_META_DATA_PACKAGE).isNotNull(); + rm.expireRollbackForPackage(MODULE_META_DATA_PACKAGE); + + assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), + MODULE_META_DATA_PACKAGE)).isNull(); + } + + private void runShellCommand(String cmd) { + InstrumentationRegistry.getInstrumentation().getUiAutomation() + .executeShellCommand(cmd); + } } diff --git a/tests/RollbackTest/SecondaryUserRollbackTest.xml b/tests/RollbackTest/SecondaryUserRollbackTest.xml new file mode 100644 index 0000000000000..6b3f05c429836 --- /dev/null +++ b/tests/RollbackTest/SecondaryUserRollbackTest.xml @@ -0,0 +1,29 @@ + + + + diff --git a/tests/RollbackTest/SecondaryUserRollbackTest/src/com/android/tests/rollback/host/SecondaryUserRollbackTest.java b/tests/RollbackTest/SecondaryUserRollbackTest/src/com/android/tests/rollback/host/SecondaryUserRollbackTest.java new file mode 100644 index 0000000000000..11a0fbb933669 --- /dev/null +++ b/tests/RollbackTest/SecondaryUserRollbackTest/src/com/android/tests/rollback/host/SecondaryUserRollbackTest.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2019 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.tests.rollback.host; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Runs rollback tests from a secondary user. + */ +@RunWith(DeviceJUnit4ClassRunner.class) +public class SecondaryUserRollbackTest extends BaseHostJUnit4Test { + private static final int SYSTEM_USER_ID = 0; + // The user that was running originally when the test starts. + private int mOriginalUser = SYSTEM_USER_ID; + private int mSecondaryUserId = -1; + private static final long SWITCH_USER_COMPLETED_NUMBER_OF_POLLS = 60; + private static final long SWITCH_USER_COMPLETED_POLL_INTERVAL_IN_MILLIS = 1000; + + + @After + public void tearDown() throws Exception { + getDevice().switchUser(mOriginalUser); + getDevice().executeShellCommand("pm uninstall com.android.cts.install.lib.testapp.A"); + getDevice().executeShellCommand("pm uninstall com.android.cts.install.lib.testapp.B"); + removeSecondaryUserIfNecessary(); + } + + @Before + public void setup() throws Exception { + createAndSwitchToSecondaryUserIfNecessary(); + installPackageAsUser("RollbackTest.apk", true, mSecondaryUserId, "--user current"); + } + + @Test + public void testBasic() throws Exception { + assertTrue(runDeviceTests("com.android.tests.rollback", + "com.android.tests.rollback.RollbackTest", + "testBasic")); + } + + private void removeSecondaryUserIfNecessary() throws Exception { + if (mSecondaryUserId != -1) { + getDevice().removeUser(mSecondaryUserId); + mSecondaryUserId = -1; + } + } + + private void createAndSwitchToSecondaryUserIfNecessary() throws Exception { + if (mSecondaryUserId == -1) { + mOriginalUser = getDevice().getCurrentUser(); + mSecondaryUserId = getDevice().createUser("SecondaryUserRollbackTest_User"); + assertTrue(getDevice().switchUser(mSecondaryUserId)); + // give time for user to be switched + waitForSwitchUserCompleted(mSecondaryUserId); + } + } + + private void waitForSwitchUserCompleted(int userId) throws Exception { + for (int i = 0; i < SWITCH_USER_COMPLETED_NUMBER_OF_POLLS; ++i) { + String logs = getDevice().executeAdbCommand("logcat", "-v", "brief", "-d", + "ActivityManager:D"); + if (logs.contains("Posting BOOT_COMPLETED user #" + userId)) { + return; + } + Thread.sleep(SWITCH_USER_COMPLETED_POLL_INTERVAL_IN_MILLIS); + } + fail("User switch to user " + userId + " timed out"); + } +} diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java index 98e066f541cc5..fb5534549e9bd 100644 --- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java +++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java @@ -35,6 +35,8 @@ import org.junit.runner.RunWith; */ @RunWith(DeviceJUnit4ClassRunner.class) public class StagedRollbackTest extends BaseHostJUnit4Test { + private static final int NATIVE_CRASHES_THRESHOLD = 5; + /** * Runs the given phase of a test by calling into the device. * Throws an exception if the test phase fails. @@ -86,6 +88,29 @@ public class StagedRollbackTest extends BaseHostJUnit4Test { runPhase("testBadApkOnlyConfirmRollback"); } + @Test + public void testNativeWatchdogTriggersRollback() throws Exception { + //Stage install ModuleMetadata package - this simulates a Mainline module update + runPhase("installModuleMetadataPackage"); + + // Reboot device to activate staged package + getDevice().reboot(); + getDevice().waitForDeviceAvailable(); + + runPhase("assertModuleMetadataRollbackAvailable"); + + // crash system_server enough times to trigger a rollback + crashProcess("system_server", NATIVE_CRASHES_THRESHOLD); + + // Rollback should be committed automatically now + // Give time for rollback to be committed + assertTrue(getDevice().waitForDeviceNotAvailable(60000)); + getDevice().waitForDeviceAvailable(); + + // verify rollback committed + runPhase("assertModuleMetadataRollbackCommitted"); + } + /** * Tests failed network health check triggers watchdog staged rollbacks. */ @@ -169,6 +194,32 @@ public class StagedRollbackTest extends BaseHostJUnit4Test { runPhase("assertNoNetworkStackRollbackCommitted"); } + /** + * Tests rolling back user data where there are multiple rollbacks for that package. + */ + @Test + public void testPreviouslyAbandonedRollbacks() throws Exception { + runPhase("testPreviouslyAbandonedRollbacksEnableRollback"); + getDevice().reboot(); + runPhase("testPreviouslyAbandonedRollbacksCommitRollback"); + getDevice().reboot(); + runPhase("testPreviouslyAbandonedRollbacksCheckUserdataRollback"); + } + + private void crashProcess(String processName, int numberOfCrashes) throws Exception { + String pid = ""; + String lastPid = "invalid"; + for (int i = 0; i < numberOfCrashes; ++i) { + // This condition makes sure before we kill the process, the process is running AND + // the last crash was finished. + while ("".equals(pid) || lastPid.equals(pid)) { + pid = getDevice().executeShellCommand("pidof " + processName); + } + getDevice().executeShellCommand("kill " + pid); + lastPid = pid; + } + } + private String getNetworkStackPath() throws DeviceNotAvailableException { // Find the NetworkStack path (can be NetworkStack.apk or NetworkStackNext.apk) return getDevice().executeShellCommand("ls /system/priv-app/NetworkStack*/*.apk"); diff --git a/tests/RollbackTest/TEST_MAPPING b/tests/RollbackTest/TEST_MAPPING index 6be93a0a199b6..7ae03e68decc4 100644 --- a/tests/RollbackTest/TEST_MAPPING +++ b/tests/RollbackTest/TEST_MAPPING @@ -5,6 +5,9 @@ }, { "name": "StagedRollbackTest" + }, + { + "name": "SecondaryUserRollbackTest" } ] } diff --git a/tests/RollbackTest/TestApp/ACrashingV2.xml b/tests/RollbackTest/TestApp/ACrashingV2.xml deleted file mode 100644 index 77bfd4e0f9a0a..0000000000000 --- a/tests/RollbackTest/TestApp/ACrashingV2.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/tests/RollbackTest/TestApp/Av1.xml b/tests/RollbackTest/TestApp/Av1.xml deleted file mode 100644 index 63729fbaaf281..0000000000000 --- a/tests/RollbackTest/TestApp/Av1.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/tests/RollbackTest/TestApp/Av2.xml b/tests/RollbackTest/TestApp/Av2.xml deleted file mode 100644 index f0e909feabf30..0000000000000 --- a/tests/RollbackTest/TestApp/Av2.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/tests/RollbackTest/TestApp/Av3.xml b/tests/RollbackTest/TestApp/Av3.xml deleted file mode 100644 index 9725c9f7cf9e5..0000000000000 --- a/tests/RollbackTest/TestApp/Av3.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/tests/RollbackTest/TestApp/Bv1.xml b/tests/RollbackTest/TestApp/Bv1.xml deleted file mode 100644 index ca9c2ec47a207..0000000000000 --- a/tests/RollbackTest/TestApp/Bv1.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/tests/RollbackTest/TestApp/Bv2.xml b/tests/RollbackTest/TestApp/Bv2.xml deleted file mode 100644 index bd3e6133f6f67..0000000000000 --- a/tests/RollbackTest/TestApp/Bv2.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/tests/RollbackTest/TestApp/res_v1/values-anydpi/values.xml b/tests/RollbackTest/TestApp/res_v1/values-anydpi/values.xml deleted file mode 100644 index 90d3da2565cca..0000000000000 --- a/tests/RollbackTest/TestApp/res_v1/values-anydpi/values.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - 1 - diff --git a/tests/RollbackTest/TestApp/res_v1/values/values.xml b/tests/RollbackTest/TestApp/res_v1/values/values.xml deleted file mode 100644 index 0447c74a79a68..0000000000000 --- a/tests/RollbackTest/TestApp/res_v1/values/values.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - 1 - 0 - diff --git a/tests/RollbackTest/TestApp/res_v2/values-anydpi/values.xml b/tests/RollbackTest/TestApp/res_v2/values-anydpi/values.xml deleted file mode 100644 index 9a1aa7fd8461f..0000000000000 --- a/tests/RollbackTest/TestApp/res_v2/values-anydpi/values.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - 2 - diff --git a/tests/RollbackTest/TestApp/res_v2/values/values.xml b/tests/RollbackTest/TestApp/res_v2/values/values.xml deleted file mode 100644 index fd988f597f61e..0000000000000 --- a/tests/RollbackTest/TestApp/res_v2/values/values.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - 2 - 0 - diff --git a/tests/RollbackTest/TestApp/res_v3/values-anydpi/values.xml b/tests/RollbackTest/TestApp/res_v3/values-anydpi/values.xml deleted file mode 100644 index f2d8992bee378..0000000000000 --- a/tests/RollbackTest/TestApp/res_v3/values-anydpi/values.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - 3 - diff --git a/tests/RollbackTest/TestApp/res_v3/values/values.xml b/tests/RollbackTest/TestApp/res_v3/values/values.xml deleted file mode 100644 index 968168a4bf063..0000000000000 --- a/tests/RollbackTest/TestApp/res_v3/values/values.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - 3 - 0 - diff --git a/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/CrashingMainActivity.java b/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/CrashingMainActivity.java deleted file mode 100644 index 97958acde21b8..0000000000000 --- a/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/CrashingMainActivity.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2019 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.tests.rollback.testapp; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.os.Bundle; - -/** - * A crashing test app for testing apk rollback support. - */ -public class CrashingMainActivity extends Activity { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - incrementCountAndBroadcast(); - throw new RuntimeException("Intended force crash"); - } - - private void incrementCountAndBroadcast() { - SharedPreferences preferences = getSharedPreferences("prefs", Context.MODE_PRIVATE); - SharedPreferences.Editor editor = preferences.edit(); - int count = preferences.getInt("crash_count", 0); - editor.putInt("crash_count", ++count).commit(); - - Intent intent = new Intent("com.android.tests.rollback.CRASH"); - intent.putExtra("count", count); - sendBroadcast(intent); - } -} diff --git a/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/MainActivity.java b/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/MainActivity.java deleted file mode 100644 index 9f1a0609d3f1d..0000000000000 --- a/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/MainActivity.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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 com.android.tests.rollback.testapp; - -import android.app.Activity; -import android.os.Bundle; - -/** - * A test app for testing apk rollback support. - */ -public class MainActivity extends Activity { - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - try { - new ProcessUserData().processUserData(this); - } catch (ProcessUserData.UserDataException e) { - throw new AssertionError("Failed to process app user data", e); - } - } -} diff --git a/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/ProcessUserData.java b/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/ProcessUserData.java deleted file mode 100644 index 38c658e795aa6..0000000000000 --- a/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/ProcessUserData.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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 com.android.tests.rollback.testapp; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.res.Resources; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.Scanner; - -/** - * A broadcast reciever to check for and update user app data version - * compatibility. - */ -public class ProcessUserData extends BroadcastReceiver { - - private static final String TAG = "RollbackTestApp"; - - /** - * Exception thrown in case of issue with user data. - */ - public static class UserDataException extends Exception { - public UserDataException(String message) { - super(message); - } - - public UserDataException(String message, Throwable cause) { - super(message, cause); - } - } - - @Override - public void onReceive(Context context, Intent intent) { - try { - processUserData(context); - setResultCode(1); - } catch (UserDataException e) { - setResultCode(0); - setResultData(e.getMessage()); - } - } - - /** - * Update the app's user data version to match the app version. - * - * @param context The application context. - * @throws UserDataException in case of problems with app user data. - */ - public void processUserData(Context context) throws UserDataException { - Resources res = context.getResources(); - String packageName = context.getPackageName(); - - int appVersionId = res.getIdentifier("app_version", "integer", packageName); - int appVersion = res.getInteger(appVersionId); - - int splitVersionId = res.getIdentifier("split_version", "integer", packageName); - int splitVersion = res.getInteger(splitVersionId); - - // Make sure the app version and split versions are compatible. - if (appVersion != splitVersion) { - throw new UserDataException("Split version " + splitVersion - + " does not match app version " + appVersion); - } - - // Read the version of the app's user data and ensure it is compatible - // with our version of the application. - File versionFile = new File(context.getFilesDir(), "version.txt"); - try { - Scanner s = new Scanner(versionFile); - int userDataVersion = s.nextInt(); - s.close(); - - if (userDataVersion > appVersion) { - throw new UserDataException("User data is from version " + userDataVersion - + ", which is not compatible with this version " + appVersion - + " of the RollbackTestApp"); - } - } catch (FileNotFoundException e) { - // No problem. This is a fresh install of the app or the user data - // has been wiped. - } - - // Record the current version of the app in the user data. - try { - PrintWriter pw = new PrintWriter(versionFile); - pw.println(appVersion); - pw.close(); - } catch (IOException e) { - throw new UserDataException("Unable to write user data.", e); - } - } -}