Loading core/java/android/content/pm/PackageManagerInternal.java +12 −0 Original line number Diff line number Diff line Loading @@ -793,6 +793,12 @@ public abstract class PackageManagerInternal { public static final String EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS = "android.content.pm.extra.ENABLE_ROLLBACK_INSTALL_FLAGS"; /** * Extra field name for the set of installed users for a given rollback package. */ public static final String EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS = "android.content.pm.extra.ENABLE_ROLLBACK_INSTALLED_USERS"; /** * Used as the {@code enableRollbackCode} argument for * {@link PackageManagerInternal#setEnableRollbackCode} to indicate that Loading Loading @@ -827,4 +833,10 @@ public abstract class PackageManagerInternal { * Ask the package manager to compile layouts in the given package. */ public abstract boolean compileLayouts(String packageName); /* * Inform the package manager that the pending package install identified by * {@code token} can be completed. */ public abstract void finishPackageInstall(int token, boolean didLaunch); } core/java/android/content/rollback/IRollbackManager.aidl +6 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,12 @@ interface IRollbackManager { void executeRollback(in RollbackInfo rollback, String callerPackageName, in IntentSender statusReceiver); // Exposed for use from the system server only. Callback from the package // manager during the install flow when user data can be restored for a given // package. void restoreUserData(String packageName, int userId, int appId, long ceDataInode, String seInfo, int token); // Exposed for test purposes only. void reloadPersistedData(); Loading services/core/java/com/android/server/pm/Installer.java +25 −0 Original line number Diff line number Diff line Loading @@ -611,6 +611,31 @@ public class Installer extends SystemService { } } public boolean snapshotAppData(String pkg, @UserIdInt int userId, int storageFlags) throws InstallerException { if (!checkBeforeRemote()) return false; try { mInstalld.snapshotAppData(null, pkg, userId, storageFlags); return true; } catch (Exception e) { throw InstallerException.from(e); } } public boolean restoreAppDataSnapshot(String pkg, @AppIdInt int appId, long ceDataInode, String seInfo, @UserIdInt int userId, int storageFlags) throws InstallerException { if (!checkBeforeRemote()) return false; try { mInstalld.restoreAppDataSnapshot(null, pkg, appId, ceDataInode, seInfo, userId, storageFlags); return true; } catch (Exception e) { throw InstallerException.from(e); } } private static void assertValidInstructionSet(String instructionSet) throws InstallerException { for (String abi : Build.SUPPORTED_ABIS) { Loading services/core/java/com/android/server/pm/PackageManagerService.java +42 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRAD import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED; import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED; import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET; import static android.content.pm.PackageManager.INSTALL_ALLOW_DOWNGRADE; import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS; import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE; import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION; Loading Loading @@ -201,6 +202,7 @@ import android.content.pm.VersionedPackage; import android.content.pm.dex.ArtManager; import android.content.pm.dex.DexMetadataHelper; import android.content.pm.dex.IArtManager; import android.content.rollback.IRollbackManager; import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.Bitmap; Loading Loading @@ -13872,6 +13874,38 @@ public class PackageManagerService extends IPackageManager.Stub } } // If this is an update to a package that might be potentially downgraded, then we // need to check with the rollback manager whether there's any userdata that might // need to be restored for the package. // // TODO(narayan): Get this working for cases where userId == UserHandle.USER_ALL. if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && !doRestore && update) { IRollbackManager rm = IRollbackManager.Stub.asInterface( ServiceManager.getService(Context.ROLLBACK_SERVICE)); final String packageName = res.pkg.applicationInfo.packageName; final String seInfo = res.pkg.applicationInfo.seInfo; final PackageSetting ps; int appId = -1; long ceDataInode = -1; synchronized (mSettings) { ps = mSettings.getPackageLPr(packageName); if (ps != null) { appId = ps.appId; ceDataInode = ps.getCeDataInode(userId); } } if (ps != null) { try { rm.restoreUserData(packageName, userId, appId, ceDataInode, seInfo, token); } catch (RemoteException re) { // Cannot happen, the RollbackManager is hosted in the same process. } doRestore = true; } } if (!doRestore) { // No restore possible, or the Backup Manager was mysteriously not // available -- just fire the post-install work request directly. Loading Loading @@ -14569,6 +14603,9 @@ public class PackageManagerService extends IPackageManager.Stub enableRollbackIntent.putExtra( PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS, installFlags); enableRollbackIntent.putExtra( PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS, resolveUserIds(args.user.getIdentifier())); enableRollbackIntent.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)), PACKAGE_MIME_TYPE); enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); Loading Loading @@ -23791,6 +23828,11 @@ public class PackageManagerService extends IPackageManager.Stub } return mArtManagerService.compileLayouts(pkg); } @Override public void finishPackageInstall(int token, boolean didLaunch) { PackageManagerService.this.finishPackageInstall(token, didLaunch); } } @GuardedBy("mPackages") services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +106 −42 Original line number Diff line number Diff line Loading @@ -43,10 +43,14 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.storage.StorageManager; import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.server.LocalServices; import com.android.server.pm.Installer; import com.android.server.pm.Installer.InstallerException; import com.android.server.pm.PackageManagerServiceUtils; import java.io.File; Loading @@ -56,12 +60,11 @@ import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; /** * Implementation of service that manages APK level rollbacks. Loading Loading @@ -103,9 +106,14 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { private final Context mContext; private final HandlerThread mHandlerThread; private final Installer mInstaller; RollbackManagerServiceImpl(Context context) { mContext = context; // Note that we're calling onStart here because this object is only constructed on // SystemService#onStart. mInstaller = new Installer(mContext); mInstaller.onStart(); mHandlerThread = new HandlerThread("RollbackManagerServiceHandler"); mHandlerThread.start(); Loading @@ -120,8 +128,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { // expiration. getHandler().post(() -> ensureRollbackDataLoaded()); PackageInstaller installer = mContext.getPackageManager().getPackageInstaller(); installer.registerSessionCallback(new SessionCallback(), getHandler()); PackageInstaller packageInstaller = mContext.getPackageManager().getPackageInstaller(); packageInstaller.registerSessionCallback(new SessionCallback(), getHandler()); IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_PACKAGE_REPLACED); Loading Loading @@ -158,10 +166,13 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN, -1); int installFlags = intent.getIntExtra( PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS, 0); int[] installedUsers = intent.getIntArrayExtra( PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS); File newPackageCodePath = new File(intent.getData().getPath()); getHandler().post(() -> { boolean success = enableRollback(installFlags, newPackageCodePath); boolean success = enableRollback(installFlags, newPackageCodePath, installedUsers); int ret = PackageManagerInternal.ENABLE_ROLLBACK_SUCCEEDED; if (!success) { ret = PackageManagerInternal.ENABLE_ROLLBACK_FAILED; Loading Loading @@ -356,10 +367,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { parentSession.addChildSessionId(sessionId); } final LocalIntentReceiver receiver = new LocalIntentReceiver(); parentSession.commit(receiver.getIntentSender()); Intent result = receiver.getResult(); final LocalIntentReceiver receiver = new LocalIntentReceiver( (Intent result) -> { int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE); if (status != PackageInstaller.STATUS_SUCCESS) { Loading @@ -378,6 +387,10 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { // TODO: This call emits the warning "Calling a method in the // system process without a qualified user". Fix that. mContext.sendBroadcast(broadcast); } ); parentSession.commit(receiver.getIntentSender()); } catch (IOException e) { Log.e(TAG, "Unable to roll back " + targetPackageName, e); sendFailure(statusReceiver, "IOException: " + e.toString()); Loading Loading @@ -620,12 +633,13 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { * staged for install with rollback enabled. Called before the package has * been installed. * * @param id the id of the enable rollback request * @param installFlags information about what is being installed. * @param newPackageCodePath path to the package about to be installed. * @param installedUsers the set of users for which a given package is installed. * @return true if enabling the rollback succeeds, false otherwise. */ private boolean enableRollback(int installFlags, File newPackageCodePath) { private boolean enableRollback(int installFlags, File newPackageCodePath, int[] installedUsers) { if ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) { Log.e(TAG, "Rollbacks not supported for instant app install"); return false; Loading Loading @@ -690,6 +704,25 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { PackageRollbackInfo.PackageVersion installedVersion = new PackageRollbackInfo.PackageVersion(installedPackage.getLongVersionCode()); for (int user : installedUsers) { final int storageFlags; if (StorageManager.isFileEncryptedNativeOrEmulated() && !StorageManager.isUserKeyUnlocked(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.e(TAG, "User: " + user + " isn't unlocked, skipping CE userdata backup."); storageFlags = Installer.FLAG_STORAGE_DE; } else { storageFlags = Installer.FLAG_STORAGE_CE | Installer.FLAG_STORAGE_DE; } try { mInstaller.snapshotAppData(packageName, user, storageFlags); } catch (InstallerException ie) { Log.e(TAG, "Unable to create app data snapshot for: " + packageName, ie); } } PackageRollbackInfo info = new PackageRollbackInfo( packageName, newVersion, installedVersion); Loading Loading @@ -722,33 +755,64 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { return true; } // TODO: Don't copy this from PackageManagerShellCommand like this? private static class LocalIntentReceiver { private final LinkedBlockingQueue<Intent> mResult = new LinkedBlockingQueue<>(); @Override public void restoreUserData(String packageName, int userId, int appId, long ceDataInode, String seInfo, int token) { if (Binder.getCallingUid() != Process.SYSTEM_UID) { throw new SecurityException("restoureUserData may only be called by the system."); } getHandler().post(() -> { PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class); // TODO(narayan): Should we make sure we're in the middle of a session commit for a // a package with this package name ? Otherwise it's possible we may roll back data // for some other downgrade. if (getRollbackForPackage(packageName) == null) { pmi.finishPackageInstall(token, false); return; } final int storageFlags; if (StorageManager.isFileEncryptedNativeOrEmulated() && !StorageManager.isUserKeyUnlocked(userId)) { // 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.e(TAG, "User: " + userId + " isn't unlocked, skipping CE userdata restore."); storageFlags = Installer.FLAG_STORAGE_DE; } else { storageFlags = Installer.FLAG_STORAGE_CE | Installer.FLAG_STORAGE_DE; } try { mInstaller.restoreAppDataSnapshot(packageName, appId, ceDataInode, seInfo, userId, storageFlags); } catch (InstallerException ie) { Log.e(TAG, "Unable to restore app data snapshot: " + packageName, ie); } pmi.finishPackageInstall(token, false); }); } private class LocalIntentReceiver { final Consumer<Intent> mConsumer; LocalIntentReceiver(Consumer<Intent> consumer) { mConsumer = consumer; } private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() { @Override public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken, IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) { try { mResult.offer(intent, 5, TimeUnit.SECONDS); } catch (InterruptedException e) { throw new RuntimeException(e); } getHandler().post(() -> mConsumer.accept(intent)); } }; public IntentSender getIntentSender() { return new IntentSender((IIntentSender) mLocalSender); } public Intent getResult() { try { return mResult.take(); } catch (InterruptedException e) { throw new RuntimeException(e); } } } /** Loading Loading
core/java/android/content/pm/PackageManagerInternal.java +12 −0 Original line number Diff line number Diff line Loading @@ -793,6 +793,12 @@ public abstract class PackageManagerInternal { public static final String EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS = "android.content.pm.extra.ENABLE_ROLLBACK_INSTALL_FLAGS"; /** * Extra field name for the set of installed users for a given rollback package. */ public static final String EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS = "android.content.pm.extra.ENABLE_ROLLBACK_INSTALLED_USERS"; /** * Used as the {@code enableRollbackCode} argument for * {@link PackageManagerInternal#setEnableRollbackCode} to indicate that Loading Loading @@ -827,4 +833,10 @@ public abstract class PackageManagerInternal { * Ask the package manager to compile layouts in the given package. */ public abstract boolean compileLayouts(String packageName); /* * Inform the package manager that the pending package install identified by * {@code token} can be completed. */ public abstract void finishPackageInstall(int token, boolean didLaunch); }
core/java/android/content/rollback/IRollbackManager.aidl +6 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,12 @@ interface IRollbackManager { void executeRollback(in RollbackInfo rollback, String callerPackageName, in IntentSender statusReceiver); // Exposed for use from the system server only. Callback from the package // manager during the install flow when user data can be restored for a given // package. void restoreUserData(String packageName, int userId, int appId, long ceDataInode, String seInfo, int token); // Exposed for test purposes only. void reloadPersistedData(); Loading
services/core/java/com/android/server/pm/Installer.java +25 −0 Original line number Diff line number Diff line Loading @@ -611,6 +611,31 @@ public class Installer extends SystemService { } } public boolean snapshotAppData(String pkg, @UserIdInt int userId, int storageFlags) throws InstallerException { if (!checkBeforeRemote()) return false; try { mInstalld.snapshotAppData(null, pkg, userId, storageFlags); return true; } catch (Exception e) { throw InstallerException.from(e); } } public boolean restoreAppDataSnapshot(String pkg, @AppIdInt int appId, long ceDataInode, String seInfo, @UserIdInt int userId, int storageFlags) throws InstallerException { if (!checkBeforeRemote()) return false; try { mInstalld.restoreAppDataSnapshot(null, pkg, appId, ceDataInode, seInfo, userId, storageFlags); return true; } catch (Exception e) { throw InstallerException.from(e); } } private static void assertValidInstructionSet(String instructionSet) throws InstallerException { for (String abi : Build.SUPPORTED_ABIS) { Loading
services/core/java/com/android/server/pm/PackageManagerService.java +42 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRAD import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED; import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED; import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET; import static android.content.pm.PackageManager.INSTALL_ALLOW_DOWNGRADE; import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS; import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE; import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION; Loading Loading @@ -201,6 +202,7 @@ import android.content.pm.VersionedPackage; import android.content.pm.dex.ArtManager; import android.content.pm.dex.DexMetadataHelper; import android.content.pm.dex.IArtManager; import android.content.rollback.IRollbackManager; import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.Bitmap; Loading Loading @@ -13872,6 +13874,38 @@ public class PackageManagerService extends IPackageManager.Stub } } // If this is an update to a package that might be potentially downgraded, then we // need to check with the rollback manager whether there's any userdata that might // need to be restored for the package. // // TODO(narayan): Get this working for cases where userId == UserHandle.USER_ALL. if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && !doRestore && update) { IRollbackManager rm = IRollbackManager.Stub.asInterface( ServiceManager.getService(Context.ROLLBACK_SERVICE)); final String packageName = res.pkg.applicationInfo.packageName; final String seInfo = res.pkg.applicationInfo.seInfo; final PackageSetting ps; int appId = -1; long ceDataInode = -1; synchronized (mSettings) { ps = mSettings.getPackageLPr(packageName); if (ps != null) { appId = ps.appId; ceDataInode = ps.getCeDataInode(userId); } } if (ps != null) { try { rm.restoreUserData(packageName, userId, appId, ceDataInode, seInfo, token); } catch (RemoteException re) { // Cannot happen, the RollbackManager is hosted in the same process. } doRestore = true; } } if (!doRestore) { // No restore possible, or the Backup Manager was mysteriously not // available -- just fire the post-install work request directly. Loading Loading @@ -14569,6 +14603,9 @@ public class PackageManagerService extends IPackageManager.Stub enableRollbackIntent.putExtra( PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS, installFlags); enableRollbackIntent.putExtra( PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS, resolveUserIds(args.user.getIdentifier())); enableRollbackIntent.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)), PACKAGE_MIME_TYPE); enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); Loading Loading @@ -23791,6 +23828,11 @@ public class PackageManagerService extends IPackageManager.Stub } return mArtManagerService.compileLayouts(pkg); } @Override public void finishPackageInstall(int token, boolean didLaunch) { PackageManagerService.this.finishPackageInstall(token, didLaunch); } } @GuardedBy("mPackages")
services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +106 −42 Original line number Diff line number Diff line Loading @@ -43,10 +43,14 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.storage.StorageManager; import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.server.LocalServices; import com.android.server.pm.Installer; import com.android.server.pm.Installer.InstallerException; import com.android.server.pm.PackageManagerServiceUtils; import java.io.File; Loading @@ -56,12 +60,11 @@ import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; /** * Implementation of service that manages APK level rollbacks. Loading Loading @@ -103,9 +106,14 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { private final Context mContext; private final HandlerThread mHandlerThread; private final Installer mInstaller; RollbackManagerServiceImpl(Context context) { mContext = context; // Note that we're calling onStart here because this object is only constructed on // SystemService#onStart. mInstaller = new Installer(mContext); mInstaller.onStart(); mHandlerThread = new HandlerThread("RollbackManagerServiceHandler"); mHandlerThread.start(); Loading @@ -120,8 +128,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { // expiration. getHandler().post(() -> ensureRollbackDataLoaded()); PackageInstaller installer = mContext.getPackageManager().getPackageInstaller(); installer.registerSessionCallback(new SessionCallback(), getHandler()); PackageInstaller packageInstaller = mContext.getPackageManager().getPackageInstaller(); packageInstaller.registerSessionCallback(new SessionCallback(), getHandler()); IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_PACKAGE_REPLACED); Loading Loading @@ -158,10 +166,13 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN, -1); int installFlags = intent.getIntExtra( PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS, 0); int[] installedUsers = intent.getIntArrayExtra( PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS); File newPackageCodePath = new File(intent.getData().getPath()); getHandler().post(() -> { boolean success = enableRollback(installFlags, newPackageCodePath); boolean success = enableRollback(installFlags, newPackageCodePath, installedUsers); int ret = PackageManagerInternal.ENABLE_ROLLBACK_SUCCEEDED; if (!success) { ret = PackageManagerInternal.ENABLE_ROLLBACK_FAILED; Loading Loading @@ -356,10 +367,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { parentSession.addChildSessionId(sessionId); } final LocalIntentReceiver receiver = new LocalIntentReceiver(); parentSession.commit(receiver.getIntentSender()); Intent result = receiver.getResult(); final LocalIntentReceiver receiver = new LocalIntentReceiver( (Intent result) -> { int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE); if (status != PackageInstaller.STATUS_SUCCESS) { Loading @@ -378,6 +387,10 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { // TODO: This call emits the warning "Calling a method in the // system process without a qualified user". Fix that. mContext.sendBroadcast(broadcast); } ); parentSession.commit(receiver.getIntentSender()); } catch (IOException e) { Log.e(TAG, "Unable to roll back " + targetPackageName, e); sendFailure(statusReceiver, "IOException: " + e.toString()); Loading Loading @@ -620,12 +633,13 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { * staged for install with rollback enabled. Called before the package has * been installed. * * @param id the id of the enable rollback request * @param installFlags information about what is being installed. * @param newPackageCodePath path to the package about to be installed. * @param installedUsers the set of users for which a given package is installed. * @return true if enabling the rollback succeeds, false otherwise. */ private boolean enableRollback(int installFlags, File newPackageCodePath) { private boolean enableRollback(int installFlags, File newPackageCodePath, int[] installedUsers) { if ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) { Log.e(TAG, "Rollbacks not supported for instant app install"); return false; Loading Loading @@ -690,6 +704,25 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { PackageRollbackInfo.PackageVersion installedVersion = new PackageRollbackInfo.PackageVersion(installedPackage.getLongVersionCode()); for (int user : installedUsers) { final int storageFlags; if (StorageManager.isFileEncryptedNativeOrEmulated() && !StorageManager.isUserKeyUnlocked(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.e(TAG, "User: " + user + " isn't unlocked, skipping CE userdata backup."); storageFlags = Installer.FLAG_STORAGE_DE; } else { storageFlags = Installer.FLAG_STORAGE_CE | Installer.FLAG_STORAGE_DE; } try { mInstaller.snapshotAppData(packageName, user, storageFlags); } catch (InstallerException ie) { Log.e(TAG, "Unable to create app data snapshot for: " + packageName, ie); } } PackageRollbackInfo info = new PackageRollbackInfo( packageName, newVersion, installedVersion); Loading Loading @@ -722,33 +755,64 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { return true; } // TODO: Don't copy this from PackageManagerShellCommand like this? private static class LocalIntentReceiver { private final LinkedBlockingQueue<Intent> mResult = new LinkedBlockingQueue<>(); @Override public void restoreUserData(String packageName, int userId, int appId, long ceDataInode, String seInfo, int token) { if (Binder.getCallingUid() != Process.SYSTEM_UID) { throw new SecurityException("restoureUserData may only be called by the system."); } getHandler().post(() -> { PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class); // TODO(narayan): Should we make sure we're in the middle of a session commit for a // a package with this package name ? Otherwise it's possible we may roll back data // for some other downgrade. if (getRollbackForPackage(packageName) == null) { pmi.finishPackageInstall(token, false); return; } final int storageFlags; if (StorageManager.isFileEncryptedNativeOrEmulated() && !StorageManager.isUserKeyUnlocked(userId)) { // 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.e(TAG, "User: " + userId + " isn't unlocked, skipping CE userdata restore."); storageFlags = Installer.FLAG_STORAGE_DE; } else { storageFlags = Installer.FLAG_STORAGE_CE | Installer.FLAG_STORAGE_DE; } try { mInstaller.restoreAppDataSnapshot(packageName, appId, ceDataInode, seInfo, userId, storageFlags); } catch (InstallerException ie) { Log.e(TAG, "Unable to restore app data snapshot: " + packageName, ie); } pmi.finishPackageInstall(token, false); }); } private class LocalIntentReceiver { final Consumer<Intent> mConsumer; LocalIntentReceiver(Consumer<Intent> consumer) { mConsumer = consumer; } private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() { @Override public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken, IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) { try { mResult.offer(intent, 5, TimeUnit.SECONDS); } catch (InterruptedException e) { throw new RuntimeException(e); } getHandler().post(() -> mConsumer.accept(intent)); } }; public IntentSender getIntentSender() { return new IntentSender((IIntentSender) mLocalSender); } public Intent getResult() { try { return mResult.take(); } catch (InterruptedException e) { throw new RuntimeException(e); } } } /** Loading