Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6712b72a authored by Ruslan Tkhakokhov's avatar Ruslan Tkhakokhov
Browse files

[Multi-user] Verfiy full backup/restore flow

Bug: 121198030
Test: 1) atest RunBackupFrameworksServicesRoboTests
2) atest $(find \
frameworks/base/services/tests/servicestests/src/com/android/server/backup \
-name '*Test.java')
3) atest CtsBackupTestCases
4) atest CtsBackupHostTestCases
5) atest GtsBackupTestCases
6) atest GtsBackupHostTestCases

Manual testing:
1. Start secondary user -> verify fb-schedule file is created, full backup queue initialised
2. Verify fullbackup of 1 package for system/secondary users, [package] only exists for current user:
  * bmgr --user [user-id] fullbackup [package]
  * Verify in logs that backup is successful
  * Uninstall/install [package]
  * Verify data is restored
3. Verify fullbackup of 1 package for secondary user, [package] eixtst for user 0:
  * bmgr fullbackup [package]
  * bmgr --user [user-id] fullbackup [package]
  * Verify in logs that backup is successful
  * Uninstall/install [package] for secondary user
  * bmgr --user [user-id] restore [token] [package]
  * Verify the data restored is different from system user data and belongs to [user-id]
3. Verify backup of all packages for system/secondary users:
  * bmgr --user [user-id] backupnow --all
  * Verify system packages (android, settings, wallpaper) are skipped for secondary user
  * Verify in logs that backup is successful
  * Uninstall/install [package]
  * Verify data is restored

Base -> Patchset 2: Update method calls to use asUser versions
Patchset 2 -> Patchset 3: Update opComplete callback to accept userId
Patchset 3 -> Patchset 4: Gate system packages from backup/restore for non-system users

Change-Id: Ic3986709ba4d46c0af9da45bb4dd682ee2aef3ce
parent a47310fd
Loading
Loading
Loading
Loading
+15 −5
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.app.backup;

import android.annotation.Nullable;
import android.app.IBackupAgent;
import android.app.QueuedWork;
import android.app.backup.FullBackup.BackupScheme.PathWithRequiredFlags;
@@ -181,6 +182,8 @@ public abstract class BackupAgent extends ContextWrapper {

    Handler mHandler = null;

    @Nullable private UserHandle mUser;

    Handler getHandler() {
        if (mHandler == null) {
            mHandler = new Handler(Looper.getMainLooper());
@@ -232,6 +235,8 @@ public abstract class BackupAgent extends ContextWrapper {
     */
    public void onCreate(UserHandle user) {
        onCreate();

        mUser = user;
    }

    /**
@@ -528,6 +533,10 @@ public abstract class BackupAgent extends ContextWrapper {
    public void onQuotaExceeded(long backupDataBytes, long quotaBytes) {
    }

    private int getBackupUserId() {
        return mUser == null ? super.getUserId() : mUser.getIdentifier();
    }

    /**
     * Check whether the xml yielded any <include/> tag for the provided <code>domainToken</code>.
     * If so, perform a {@link #fullBackupFileTree} which backs up the file or recurses if the path
@@ -1033,7 +1042,7 @@ public abstract class BackupAgent extends ContextWrapper {

                Binder.restoreCallingIdentity(ident);
                try {
                    callbackBinder.opComplete(token, 0);
                    callbackBinder.opCompleteForUser(getBackupUserId(), token, 0);
                } catch (RemoteException e) {
                    // we'll time out anyway, so we're safe
                }
@@ -1082,7 +1091,7 @@ public abstract class BackupAgent extends ContextWrapper {

                Binder.restoreCallingIdentity(ident);
                try {
                    callbackBinder.opComplete(token, 0);
                    callbackBinder.opCompleteForUser(getBackupUserId(), token, 0);
                } catch (RemoteException e) {
                    // we'll time out anyway, so we're safe
                }
@@ -1112,7 +1121,8 @@ public abstract class BackupAgent extends ContextWrapper {
            } finally {
                Binder.restoreCallingIdentity(ident);
                try {
                    callbackBinder.opComplete(token, measureOutput.getSize());
                    callbackBinder.opCompleteForUser(getBackupUserId(), token,
                            measureOutput.getSize());
                } catch (RemoteException e) {
                    // timeout, so we're safe
                }
@@ -1137,7 +1147,7 @@ public abstract class BackupAgent extends ContextWrapper {

                Binder.restoreCallingIdentity(ident);
                try {
                    callbackBinder.opComplete(token, 0);
                    callbackBinder.opCompleteForUser(getBackupUserId(), token, 0);
                } catch (RemoteException e) {
                    // we'll time out anyway, so we're safe
                }
@@ -1162,7 +1172,7 @@ public abstract class BackupAgent extends ContextWrapper {

                Binder.restoreCallingIdentity(ident);
                try {
                    callbackBinder.opComplete(token, 0);
                    callbackBinder.opCompleteForUser(getBackupUserId(), token, 0);
                } catch (RemoteException e) {
                    // we'll time out anyway, so we're safe
                }
+13 −0
Original line number Diff line number Diff line
@@ -547,6 +547,19 @@ interface IBackupManager {
     */
    IRestoreSession beginRestoreSessionForUser(int userId, String packageName, String transportID);

    /**
     * Notify the backup manager that a BackupAgent has completed the operation
     * corresponding to the given token and user id.
     *
     * @param userId User id for which the operation has been completed.
     * @param token The transaction token passed to the BackupAgent method being
     *        invoked.
     * @param result In the case of a full backup measure operation, the estimated
     *        total file size that would result from the operation. Unused in all other
     *        cases.
     */
    void opCompleteForUser(int userId, int token, long result);

    /**
     * Notify the backup manager that a BackupAgent has completed the operation
     * corresponding to the given token.
+1 −1
Original line number Diff line number Diff line
@@ -164,7 +164,7 @@ public class PackageManagerBackupAgent extends BackupAgent {
        int N = pkgs.size();
        for (int a = N-1; a >= 0; a--) {
            PackageInfo pkg = pkgs.get(a);
            if (!AppBackupUtils.appIsEligibleForBackup(pkg.applicationInfo, pm)) {
            if (!AppBackupUtils.appIsEligibleForBackup(pkg.applicationInfo, userId)) {
                pkgs.remove(a);
            }
        }
+7 −3
Original line number Diff line number Diff line
@@ -636,11 +636,15 @@ public class Trampoline extends IBackupManager.Stub {
    }

    @Override
    public void opComplete(int token, long result) throws RemoteException {
        int userId = binderGetCallingUserId();
    public void opCompleteForUser(int userId, int token, long result) throws RemoteException {
        if (isUserReadyForBackup(userId)) {
            mService.opComplete(binderGetCallingUserId(), token, result);
            mService.opComplete(userId, token, result);
        }
    }

    @Override
    public void opComplete(int token, long result) throws RemoteException {
        opCompleteForUser(binderGetCallingUserId(), token, result);
    }

    @Override
+13 −13
Original line number Diff line number Diff line
@@ -804,7 +804,7 @@ public class UserBackupManagerService {
    public BackupAgent makeMetadataAgent() {
        PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(mPackageManager, mUserId);
        pmAgent.attach(mContext);
        pmAgent.onCreate();
        pmAgent.onCreate(UserHandle.of(mUserId));
        return pmAgent;
    }

@@ -815,7 +815,7 @@ public class UserBackupManagerService {
        PackageManagerBackupAgent pmAgent =
                new PackageManagerBackupAgent(mPackageManager, packages, mUserId);
        pmAgent.attach(mContext);
        pmAgent.onCreate();
        pmAgent.onCreate(UserHandle.of(mUserId));
        return pmAgent;
    }

@@ -910,10 +910,10 @@ public class UserBackupManagerService {
                    long lastBackup = in.readLong();
                    foundApps.add(pkgName); // all apps that we've addressed already
                    try {
                        PackageInfo pkg = mPackageManager.getPackageInfo(pkgName, 0);
                        PackageInfo pkg = mPackageManager.getPackageInfoAsUser(pkgName, 0, mUserId);
                        if (AppBackupUtils.appGetsFullBackup(pkg)
                                && AppBackupUtils.appIsEligibleForBackup(
                                pkg.applicationInfo, mPackageManager)) {
                                && AppBackupUtils.appIsEligibleForBackup(pkg.applicationInfo,
                                mUserId)) {
                            schedule.add(new FullBackupEntry(pkgName, lastBackup));
                        } else {
                            if (DEBUG) {
@@ -933,8 +933,8 @@ public class UserBackupManagerService {
                // scan to make sure that we're tracking all full-backup candidates properly
                for (PackageInfo app : apps) {
                    if (AppBackupUtils.appGetsFullBackup(app)
                            && AppBackupUtils.appIsEligibleForBackup(
                            app.applicationInfo, mPackageManager)) {
                            && AppBackupUtils.appIsEligibleForBackup(app.applicationInfo,
                            mUserId)) {
                        if (!foundApps.contains(app.packageName)) {
                            if (MORE_DEBUG) {
                                Slog.i(TAG, "New full backup app " + app.packageName + " found");
@@ -960,7 +960,7 @@ public class UserBackupManagerService {
            schedule = new ArrayList<>(apps.size());
            for (PackageInfo info : apps) {
                if (AppBackupUtils.appGetsFullBackup(info) && AppBackupUtils.appIsEligibleForBackup(
                        info.applicationInfo, mPackageManager)) {
                        info.applicationInfo, mUserId)) {
                    schedule.add(new FullBackupEntry(info.packageName, 0));
                }
            }
@@ -1222,8 +1222,8 @@ public class UserBackupManagerService {
                                mPackageManager.getPackageInfoAsUser(
                                        packageName, /* flags */ 0, mUserId);
                        if (AppBackupUtils.appGetsFullBackup(app)
                                && AppBackupUtils.appIsEligibleForBackup(
                                app.applicationInfo, mPackageManager)) {
                                && AppBackupUtils.appIsEligibleForBackup(app.applicationInfo,
                                mUserId)) {
                            enqueueFullBackup(packageName, now);
                            scheduleNextFullBackupJob(0);
                        } else {
@@ -1618,8 +1618,7 @@ public class UserBackupManagerService {
            try {
                PackageInfo packageInfo = mPackageManager.getPackageInfoAsUser(packageName,
                        PackageManager.GET_SIGNING_CERTIFICATES, mUserId);
                if (!AppBackupUtils.appIsEligibleForBackup(packageInfo.applicationInfo,
                        mPackageManager)) {
                if (!AppBackupUtils.appIsEligibleForBackup(packageInfo.applicationInfo, mUserId)) {
                    BackupObserverUtils.sendBackupOnPackageResult(observer, packageName,
                            BackupManager.ERROR_BACKUP_NOT_ALLOWED);
                    continue;
@@ -2095,7 +2094,8 @@ public class UserBackupManagerService {
                    }

                    try {
                        PackageInfo appInfo = mPackageManager.getPackageInfo(entry.packageName, 0);
                        PackageInfo appInfo = mPackageManager.getPackageInfoAsUser(
                                entry.packageName, 0, mUserId);
                        if (!AppBackupUtils.appGetsFullBackup(appInfo)) {
                            // The head app isn't supposed to get full-data backups [any more];
                            // so we cull it and force a loop around to consider the new head
Loading