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

Commit 77a2d78d authored by Christopher Tate's avatar Christopher Tate
Browse files

Don't enqueue allowBackup=false apps for full backup attempts

We are correctly refusing to actually process apps for backup if they have
declared android:allowBackup="false" in their manifests, but we're still
wasting bookkeeping & a certain amount of work in tracking them as part of
the full backup queue.  Fix that; now we recognize that they shouldn't be
in the queue in the first place.

When reinflating the queue at boot time we also re-verify the participation
of each mentioned app so that we properly drop ones that have been uninstalled
or altered such that they are no longer full-data backup candidates.

Finally, if an app previously implemented key/value backup, so we think
we'll be running it in that mode in a future backup pass, but has been
updated to use the full-data path instead, we don't want to go ahead and
run a key/value pass on it.  Added a backstop check and proceed gracefully
in this situation.

(Also add bit more debug-build logging to LocalTransport)

Bug 19462310

Change-Id: I07ab4f2e68e92766d9e8f2595fa763c91193d743
parent 9b98afca
Loading
Loading
Loading
Loading
+20 −2
Original line number Diff line number Diff line
@@ -369,6 +369,9 @@ public class LocalTransport extends BackupTransport {
                return TRANSPORT_ERROR;
            }
        }
        if (DEBUG) {
            Log.v(TAG, "   stored " + numBytes + " of data");
        }
        return TRANSPORT_OK;
    }

@@ -431,6 +434,10 @@ public class LocalTransport extends BackupTransport {

    @Override
    public RestoreDescription nextRestorePackage() {
        if (DEBUG) {
            Log.v(TAG, "nextRestorePackage() : mRestorePackage=" + mRestorePackage
                    + " length=" + mRestorePackages.length);
        }
        if (mRestorePackages == null) throw new IllegalStateException("startRestore not called");

        boolean found = false;
@@ -441,7 +448,10 @@ public class LocalTransport extends BackupTransport {
            // skip packages where we have a data dir but no actual contents
            String[] contents = (new File(mRestoreSetIncrementalDir, name)).list();
            if (contents != null && contents.length > 0) {
                if (DEBUG) Log.v(TAG, "  nextRestorePackage(TYPE_KEY_VALUE) = " + name);
                if (DEBUG) {
                    Log.v(TAG, "  nextRestorePackage(TYPE_KEY_VALUE) @ "
                        + mRestorePackage + " = " + name);
                }
                mRestoreType = RestoreDescription.TYPE_KEY_VALUE;
                found = true;
            }
@@ -450,7 +460,10 @@ public class LocalTransport extends BackupTransport {
                // No key/value data; check for [non-empty] full data
                File maybeFullData = new File(mRestoreSetFullDir, name);
                if (maybeFullData.length() > 0) {
                    if (DEBUG) Log.v(TAG, "  nextRestorePackage(TYPE_FULL_STREAM) = " + name);
                    if (DEBUG) {
                        Log.v(TAG, "  nextRestorePackage(TYPE_FULL_STREAM) @ "
                                + mRestorePackage + " = " + name);
                    }
                    mRestoreType = RestoreDescription.TYPE_FULL_STREAM;
                    mCurFullRestoreStream = null;   // ensure starting from the ground state
                    found = true;
@@ -460,6 +473,11 @@ public class LocalTransport extends BackupTransport {
            if (found) {
                return new RestoreDescription(name, mRestoreType);
            }

            if (DEBUG) {
                Log.v(TAG, "  ... package @ " + mRestorePackage + " = " + name
                        + " has no data; skipping");
            }
        }

        if (DEBUG) Log.v(TAG, "  no more packages to restore");
+38 −9
Original line number Diff line number Diff line
@@ -601,7 +601,7 @@ public class BackupManagerService {
        return token;
    }

    // High level policy: apps are ineligible for backup if certain conditions apply
    // High level policy: apps are generally ineligible for backup if certain conditions apply
    public static boolean appIsEligibleForBackup(ApplicationInfo app) {
        // 1. their manifest states android:allowBackup="false"
        if ((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) {
@@ -628,7 +628,7 @@ public class BackupManagerService {
            return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FULL_BACKUP_ONLY) != 0;
        }

        // No agent means we do full backups for it
        // No agent or fullBackupOnly="true" means we do indeed perform full-data backups for it
        return true;
    }

@@ -1266,7 +1266,23 @@ public class BackupManagerService {
                    for (int i = 0; i < N; i++) {
                        String pkgName = in.readUTF();
                        long lastBackup = in.readLong();
                        try {
                            PackageInfo pkg = mPackageManager.getPackageInfo(pkgName, 0);
                            if (appGetsFullBackup(pkg)
                                    && appIsEligibleForBackup(pkg.applicationInfo)) {
                                schedule.add(new FullBackupEntry(pkgName, lastBackup));
                            } else {
                                if (DEBUG) {
                                    Slog.i(TAG, "Package " + pkgName
                                            + " no longer eligible for full backup");
                                }
                            }
                        } catch (NameNotFoundException e) {
                            if (DEBUG) {
                                Slog.i(TAG, "Package " + pkgName
                                        + " not installed; dropping from full backup");
                            }
                        }
                    }
                    Collections.sort(schedule);
                } catch (Exception e) {
@@ -1289,7 +1305,7 @@ public class BackupManagerService {
                schedule = new ArrayList<FullBackupEntry>(N);
                for (int i = 0; i < N; i++) {
                    PackageInfo info = apps.get(i);
                    if (appGetsFullBackup(info)) {
                    if (appGetsFullBackup(info) && appIsEligibleForBackup(info.applicationInfo)) {
                        schedule.add(new FullBackupEntry(info.packageName, 0));
                    }
                }
@@ -1761,11 +1777,11 @@ public class BackupManagerService {
                    addPackageParticipantsLocked(pkgList);
                }
                // If they're full-backup candidates, add them there instead
                final long now = System.currentTimeMillis();
                for (String packageName : pkgList) {
                    try {
                        PackageInfo app = mPackageManager.getPackageInfo(packageName, 0);
                        long now = System.currentTimeMillis();
                        if (appGetsFullBackup(app)) {
                        if (appGetsFullBackup(app) && appIsEligibleForBackup(app.applicationInfo)) {
                            enqueueFullBackup(packageName, now);
                            scheduleNextFullBackupJob();
                        }
@@ -2462,7 +2478,7 @@ public class BackupManagerService {
            BackupRequest request = mQueue.get(0);
            mQueue.remove(0);

            Slog.d(TAG, "starting agent for backup of " + request);
            Slog.d(TAG, "starting key/value backup of " + request);
            addBackupTrace("launch agent for " + request.packageName);

            // Verify that the requested app exists; it might be something that
@@ -2473,13 +2489,24 @@ public class BackupManagerService {
            try {
                mCurrentPackage = mPackageManager.getPackageInfo(request.packageName,
                        PackageManager.GET_SIGNATURES);
                if (mCurrentPackage.applicationInfo.backupAgentName == null) {
                if (!appIsEligibleForBackup(mCurrentPackage.applicationInfo)) {
                    // The manifest has changed but we had a stale backup request pending.
                    // This won't happen again because the app won't be requesting further
                    // backups.
                    Slog.i(TAG, "Package " + request.packageName
                            + " no longer supports backup; skipping");
                    addBackupTrace("skipping - no agent, completion is noop");
                    addBackupTrace("skipping - not eligible, completion is noop");
                    executeNextState(BackupState.RUNNING_QUEUE);
                    return;
                }

                if (appGetsFullBackup(mCurrentPackage)) {
                    // It's possible that this app *formerly* was enqueued for key/value backup,
                    // but has since been updated and now only supports the full-data path.
                    // Don't proceed with a key/value backup for it in this case.
                    Slog.i(TAG, "Package " + request.packageName
                            + " requests full-data rather than key/value; skipping");
                    addBackupTrace("skipping - fullBackupOnly, completion is noop");
                    executeNextState(BackupState.RUNNING_QUEUE);
                    return;
                }
@@ -9161,6 +9188,8 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
            // check whether there is data for it in the current dataset, falling back
            // to the ancestral dataset if not.
            long token = getAvailableRestoreToken(packageName);
            if (DEBUG) Slog.v(TAG, "restorePackage pkg=" + packageName
                    + " token=" + Long.toHexString(token));

            // If we didn't come up with a place to look -- no ancestral dataset and
            // the app has never been backed up from this device -- there's nothing