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

Commit bc04fb61 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Apply Android code style to RefactoredBackupManagerService."

parents 691685e2 21510f0b
Loading
Loading
Loading
Loading
+200 −127
Original line number Diff line number Diff line
@@ -77,6 +77,7 @@ import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.StringBuilderPrinter;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.backup.IBackupTransport;
import com.android.internal.util.DumpUtils;
@@ -103,6 +104,9 @@ import com.android.server.backup.params.RestoreParams;
import com.android.server.backup.restore.ActiveRestoreSession;
import com.android.server.backup.restore.PerformUnifiedRestoreTask;
import com.android.server.power.BatterySaverPolicy.ServiceType;

import libcore.io.IoUtils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
@@ -136,10 +140,10 @@ import java.util.Queue;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.CountDownLatch;

import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import libcore.io.IoUtils;

public class RefactoredBackupManagerService implements BackupManagerServiceInterface {

@@ -320,6 +324,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
    // implementation object on the fly without disturbing binders that have been
    // cached elsewhere in the system.
    static Trampoline sInstance;

    static Trampoline getInstance() {
        // Always constructed during system bringup, so no need to lazy-init
        return sInstance;
@@ -397,7 +402,8 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
     *
     * A BackupRestore task gets notified of ack/timeout for the operation via
     * BackupRestoreTask#handleCancel, BackupRestoreTask#operationComplete and notifyAll called
     * on the mCurrentOpLock. {@link RefactoredBackupManagerService#waitUntilOperationComplete(int)} is
     * on the mCurrentOpLock.
     * {@link RefactoredBackupManagerService#waitUntilOperationComplete(int)} is
     * used in various places to 'wait' for notifyAll and detect change of pending state of an
     * operation. So typically, an operation will be removed from this array by:
     *   - BackupRestoreTask#handleCancel and
@@ -446,7 +452,8 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
    private File mEverStored;
    private HashSet<String> mEverStoredApps = new HashSet<>();

    private static final int CURRENT_ANCESTRAL_RECORD_VERSION = 1;  // increment when the schema changes
    private static final int CURRENT_ANCESTRAL_RECORD_VERSION = 1;
            // increment when the schema changes
    private File mTokenFile;
    public Set<String> mAncestralPackages = null;
    public long mAncestralToken = 0;
@@ -767,8 +774,14 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
            } catch (IOException e) {
                Slog.e(TAG, "Error in processed file", e);
            } finally {
                try { if (temp != null) temp.close(); } catch (IOException e) {}
                try { if (in != null) in.close(); } catch (IOException e) {}
                try {
                    if (temp != null) temp.close();
                } catch (IOException e) {
                }
                try {
                    if (in != null) in.close();
                } catch (IOException e) {
                }
            }
        }

@@ -889,7 +902,8 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
    }

    private Runnable mFullBackupScheduleWriter = new Runnable() {
        @Override public void run() {
        @Override
        public void run() {
            synchronized (mQueueLock) {
                try {
                    ByteArrayOutputStream bufStream = new ByteArrayOutputStream(4096);
@@ -954,7 +968,10 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
                    Slog.e(TAG, "Can't read " + f, e);
                } finally {
                    // close/delete the file
                    try { if (in != null) in.close(); } catch (IOException e) {}
                    try {
                        if (in != null) in.close();
                    } catch (IOException e) {
                    }
                    f.delete();
                }
            }
@@ -1033,7 +1050,8 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
        } else {
            // hash the stated current pw and compare to the stored one
            if (candidatePw != null && candidatePw.length() > 0) {
                String currentPwHash = buildPasswordHash(algorithm, candidatePw, mPasswordSalt, rounds);
                String currentPwHash = buildPasswordHash(algorithm, candidatePw, mPasswordSalt,
                        rounds);
                if (mPasswordHash.equalsIgnoreCase(currentPwHash)) {
                    // candidate hash matches the stored hash -- the password matches
                    return true;
@@ -1148,8 +1166,10 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
    // Maintain persistent state around whether need to do an initialize operation.
    // Must be called with the queue lock held.
    public void recordInitPendingLocked(boolean isPending, String transportName) {
        if (MORE_DEBUG) Slog.i(TAG, "recordInitPendingLocked: " + isPending
        if (MORE_DEBUG) {
            Slog.i(TAG, "recordInitPendingLocked: " + isPending
                    + " on transport " + transportName);
        }
        mBackupHandler.removeMessages(MSG_RETRY_INIT);

        try {
@@ -1429,8 +1449,10 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
            return;
        }

        if (MORE_DEBUG) Slog.v(TAG, "removePackageParticipantsLocked: uid=" + oldUid
        if (MORE_DEBUG) {
            Slog.v(TAG, "removePackageParticipantsLocked: uid=" + oldUid
                    + " #" + packageNames.length);
        }
        for (String pkg : packageNames) {
            // Known previous UID, so we know which package set to check
            HashSet<String> set = mBackupParticipants.get(oldUid);
@@ -1473,8 +1495,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
                        || app.backupAgentName == null
                        || (app.flags & ApplicationInfo.FLAG_FULL_BACKUP_ONLY) != 0) {
                    packages.remove(a);
                }
                else {
                } else {
                    // we will need the shared library path, so look that up and store it here.
                    // This is used implicitly when we pass the PackageInfo object off to
                    // the Activity Manager to launch the app for backup/restore purposes.
@@ -1506,7 +1527,10 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
            } catch (IOException e) {
                Slog.e(TAG, "Can't log backup of " + packageName + " to " + mEverStored);
            } finally {
                try { if (out != null) out.close(); } catch (IOException e) {}
                try {
                    if (out != null) out.close();
                } catch (IOException e) {
                }
            }
        }
    }
@@ -1544,7 +1568,10 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
                tempKnownFile.delete();
                mEverStored.delete();
            } finally {
                try { if (known != null) known.close(); } catch (IOException e) {}
                try {
                    if (known != null) known.close();
                } catch (IOException e) {
                }
            }
        }
    }
@@ -1643,8 +1670,10 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
        try {
            PackageInfo info = mPackageManager.getPackageInfo(packageName, 0);
            if ((info.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) == 0) {
                if (MORE_DEBUG) Slog.i(TAG, "allowClearUserData=false so not wiping "
                if (MORE_DEBUG) {
                    Slog.i(TAG, "allowClearUserData=false so not wiping "
                            + packageName);
                }
                return;
            }
        } catch (NameNotFoundException e) {
@@ -1750,7 +1779,8 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
                fullBackupList.size());
        if (MORE_DEBUG) {
            Slog.i(TAG, "Backup requested for " + packages.length + " packages, of them: " +
                fullBackupList.size() + " full backups, " + kvBackupList.size() + " k/v backups");
                    fullBackupList.size() + " full backups, " + kvBackupList.size()
                    + " k/v backups");
        }

        String dirName;
@@ -1810,8 +1840,10 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
                    Integer.toHexString(token) + " of type " + operationType);
            return;
        }
        if (MORE_DEBUG) Slog.v(TAG, "starting timeout: token=" + Integer.toHexString(token)
        if (MORE_DEBUG) {
            Slog.v(TAG, "starting timeout: token=" + Integer.toHexString(token)
                    + " interval=" + interval + " callback=" + callback);
        }

        synchronized (mCurrentOpLock) {
            mCurrentOperations.put(token, new Operation(OP_PENDING, callback, operationType));
@@ -1850,8 +1882,10 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
    // synchronous waiter case
    @Override
    public boolean waitUntilOperationComplete(int token) {
        if (MORE_DEBUG) Slog.i(TAG, "Blocking until operation complete for "
        if (MORE_DEBUG) {
            Slog.i(TAG, "Blocking until operation complete for "
                    + Integer.toHexString(token));
        }
        int finalState = OP_PENDING;
        Operation op = null;
        synchronized (mCurrentOpLock) {
@@ -1884,8 +1918,10 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
        if (op != null) {
            mBackupHandler.removeMessages(getMessageIdForOperationType(op.type));
        }
        if (MORE_DEBUG) Slog.v(TAG, "operation " + Integer.toHexString(token)
        if (MORE_DEBUG) {
            Slog.v(TAG, "operation " + Integer.toHexString(token)
                    + " complete: finalState=" + finalState);
        }
        return finalState == OP_ACKNOWLEDGED;
    }

@@ -1895,9 +1931,11 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
        synchronized (mCurrentOpLock) {
            op = mCurrentOperations.get(token);
            if (MORE_DEBUG) {
                if (op == null) Slog.w(TAG, "Cancel of token " + Integer.toHexString(token)
                if (op == null) {
                    Slog.w(TAG, "Cancel of token " + Integer.toHexString(token)
                            + " but no op found");
                }
            }
            int state = (op != null) ? op.state : OP_TIMEOUT;
            if (state == OP_ACKNOWLEDGED) {
                // The operation finished cleanly, so we have nothing more to do.
@@ -2075,7 +2113,8 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
                        ? (MIN_FULL_BACKUP_INTERVAL - timeSinceLast) : 0;
                final long latency = Math.max(transportMinLatency, appLatency);
                Runnable r = new Runnable() {
                    @Override public void run() {
                    @Override
                    public void run() {
                        FullBackupJob.schedule(mContext, latency);
                    }
                };
@@ -2305,7 +2344,8 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
                }
                final long deferTime = latency;     // pin for the closure
                mBackupHandler.post(new Runnable() {
                    @Override public void run() {
                    @Override
                    public void run() {
                        FullBackupJob.schedule(mContext, deferTime);
                    }
                });
@@ -2354,15 +2394,20 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
        // partition will be signed with the device's platform certificate, so on
        // different phones the same system app will have different signatures.)
        if ((target.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
            if (MORE_DEBUG) Slog.v(TAG, "System app " + target.packageName + " - skipping sig check");
            if (MORE_DEBUG) {
                Slog.v(TAG,
                        "System app " + target.packageName + " - skipping sig check");
            }
            return true;
        }

        // Allow unsigned apps, but not signed on one device and unsigned on the other
        // !!! TODO: is this the right policy?
        Signature[] deviceSigs = target.signatures;
        if (MORE_DEBUG) Slog.v(TAG, "signaturesMatch(): stored=" + storedSigs
        if (MORE_DEBUG) {
            Slog.v(TAG, "signaturesMatch(): stored=" + storedSigs
                    + " device=" + deviceSigs);
        }
        if ((storedSigs == null || storedSigs.length == 0)
                && (deviceSigs == null || deviceSigs.length == 0)) {
            return true;
@@ -2482,7 +2527,10 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
            Slog.e(TAG, "Can't write " + str + " to backup journal", e);
            mJournal = null;
        } finally {
            try { if (out != null) out.close(); } catch (IOException e) {}
            try {
                if (out != null) out.close();
            } catch (IOException e) {
            }
        }
    }

@@ -2647,9 +2695,11 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
                return;
            }

            if (DEBUG) Slog.v(TAG, "Requesting backup: apks=" + includeApks + " obb=" + includeObbs
            if (DEBUG) {
                Slog.v(TAG, "Requesting backup: apks=" + includeApks + " obb=" + includeObbs
                        + " shared=" + includeShared + " all=" + doAllApps + " system="
                        + includeSystem + " includekeyvalue=" + doKeyValue + " pkgs=" + pkgList);
            }
            Slog.i(TAG, "Beginning adb backup...");

            AdbBackupParams params = new AdbBackupParams(fd, includeApks, includeObbs,
@@ -2813,8 +2863,10 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
    }

    private void startConfirmationTimeout(int token, AdbParams params) {
        if (MORE_DEBUG) Slog.d(TAG, "Posting conf timeout msg after "
        if (MORE_DEBUG) {
            Slog.d(TAG, "Posting conf timeout msg after "
                    + TIMEOUT_FULL_CONFIRMATION + " millis");
        }
        Message msg = mBackupHandler.obtainMessage(MSG_FULL_CONFIRMATION_TIMEOUT,
                token, 0, params);
        mBackupHandler.sendMessageDelayed(msg, TIMEOUT_FULL_CONFIRMATION);
@@ -2842,12 +2894,15 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
    @Override
    public void acknowledgeAdbBackupOrRestore(int token, boolean allow,
            String curPassword, String encPpassword, IFullBackupRestoreObserver observer) {
        if (DEBUG) Slog.d(TAG, "acknowledgeAdbBackupOrRestore : token=" + token
        if (DEBUG) {
            Slog.d(TAG, "acknowledgeAdbBackupOrRestore : token=" + token
                    + " allow=" + allow);
        }

        // TODO: possibly require not just this signature-only permission, but even
        // require that the specific designated confirmation-UI app uid is the caller?
        mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "acknowledgeAdbBackupOrRestore");
        mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
                "acknowledgeAdbBackupOrRestore");

        long oldId = Binder.clearCallingIdentity();
        try {
@@ -3020,7 +3075,8 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
    // Report whether the backup mechanism is currently enabled
    @Override
    public boolean isBackupEnabled() {
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "isBackupEnabled");
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                "isBackupEnabled");
        return mEnabled;    // no need to synchronize just to read it
    }

@@ -3037,7 +3093,8 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
    // Report all known, available backup transports
    @Override
    public String[] listAllTransports() {
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "listAllTransports");
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                "listAllTransports");

        return mTransportManager.getBoundTransportNames();
    }
@@ -3133,8 +3190,10 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
        if (transport != null) {
            try {
                final Intent intent = transport.configurationIntent();
                if (MORE_DEBUG) Slog.d(TAG, "getConfigurationIntent() returning config intent "
                if (MORE_DEBUG) {
                    Slog.d(TAG, "getConfigurationIntent() returning config intent "
                            + intent);
                }
                return intent;
            } catch (Exception e) {
                /* fall through to return null */
@@ -3180,8 +3239,10 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
        if (transport != null) {
            try {
                final Intent intent = transport.dataManagementIntent();
                if (MORE_DEBUG) Slog.d(TAG, "getDataManagementIntent() returning intent "
                if (MORE_DEBUG) {
                    Slog.d(TAG, "getDataManagementIntent() returning intent "
                            + intent);
                }
                return intent;
            } catch (Exception e) {
                /* fall through to return null */
@@ -3263,9 +3324,11 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
        boolean skip = false;

        long restoreSet = getAvailableRestoreToken(packageName);
        if (DEBUG) Slog.v(TAG, "restoreAtInstall pkg=" + packageName
        if (DEBUG) {
            Slog.v(TAG, "restoreAtInstall pkg=" + packageName
                    + " token=" + Integer.toHexString(token)
                    + " restoreSet=" + Long.toHexString(restoreSet));
        }
        if (restoreSet == 0) {
            if (MORE_DEBUG) Slog.i(TAG, "No restore set");
            skip = true;
@@ -3322,8 +3385,10 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
    // Hand off a restore session
    @Override
    public IRestoreSession beginRestoreSession(String packageName, String transport) {
        if (DEBUG) Slog.v(TAG, "beginRestoreSession: pkg=" + packageName
        if (DEBUG) {
            Slog.v(TAG, "beginRestoreSession: pkg=" + packageName
                    + " transport=" + transport);
        }

        boolean needPermission = true;
        if (transport == null) {
@@ -3493,8 +3558,10 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
        pw.println("Defined backup agents:");
        for (PackageInfo pkg : agentPackages) {
            pw.print("  ");
            pw.print(pkg.packageName); pw.println(':');
            pw.print("      "); pw.println(pkg.applicationInfo.backupAgentName);
            pw.print(pkg.packageName);
            pw.println(':');
            pw.print("      ");
            pw.println(pkg.applicationInfo.backupAgentName);
        }
    }

@@ -3519,14 +3586,16 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
            final String[] transports = listAllTransports();
            if (transports != null) {
                for (String t : listAllTransports()) {
                    pw.println((t.equals(mTransportManager.getCurrentTransportName()) ? "  * " : "    ") + t);
                    pw.println((t.equals(mTransportManager.getCurrentTransportName()) ? "  * "
                            : "    ") + t);
                    try {
                        IBackupTransport transport = mTransportManager.getTransportBinder(t);
                        File dir = new File(mBaseStateDir, transport.transportDirName());
                        pw.println("       destination: " + transport.currentDestinationString());
                        pw.println("       intent: " + transport.configurationIntent());
                        for (File f : dir.listFiles()) {
                            pw.println("       " + f.getName() + " - " + f.length() + " state bytes");
                            pw.println(
                                    "       " + f.getName() + " - " + f.length() + " state bytes");
                        }
                    } catch (Exception e) {
                        Slog.e(TAG, "Error in transport", e);
@@ -3551,8 +3620,10 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
                }
            }

            pw.print("Ancestral: "); pw.println(Long.toHexString(mAncestralToken));
            pw.print("Current:   "); pw.println(Long.toHexString(mCurrentToken));
            pw.print("Ancestral: ");
            pw.println(Long.toHexString(mAncestralToken));
            pw.print("Current:   ");
            pw.println(Long.toHexString(mCurrentToken));

            int N = mBackupParticipants.size();
            pw.println("Participants:");
@@ -3586,8 +3657,10 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter

            pw.println("Full backup queue:" + mFullBackupQueue.size());
            for (FullBackupEntry entry : mFullBackupQueue) {
                pw.print("    "); pw.print(entry.lastBackup);
                pw.print(" : "); pw.println(entry.packageName);
                pw.print("    ");
                pw.print(entry.lastBackup);
                pw.print(" : ");
                pw.println(entry.packageName);
            }
        }
    }
+65 −46

File changed.

Preview size limit exceeded, changes collapsed.

+23 −17
Original line number Diff line number Diff line
@@ -26,8 +26,10 @@ import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.UserHandle;
import android.util.Slog;

import com.android.internal.backup.IObbBackupService;
import com.android.server.backup.RefactoredBackupManagerService;

import java.io.IOException;
import java.io.OutputStream;

@@ -65,9 +67,11 @@ public class FullBackupObbConnection implements ServiceConnection {
            pipes = ParcelFileDescriptor.createPipe();
            int token = backupManagerService.generateRandomIntegerToken();
            backupManagerService
                .prepareOperationTimeout(token, RefactoredBackupManagerService.TIMEOUT_FULL_BACKUP_INTERVAL,
                    .prepareOperationTimeout(token,
                            RefactoredBackupManagerService.TIMEOUT_FULL_BACKUP_INTERVAL,
                            null, RefactoredBackupManagerService.OP_TYPE_BACKUP_WAIT);
            mService.backupObbs(pkg.packageName, pipes[1], token, backupManagerService.mBackupManagerBinder);
            mService.backupObbs(pkg.packageName, pipes[1], token,
                    backupManagerService.mBackupManagerBinder);
            RefactoredBackupManagerService.routeSocketDataToOutput(pipes[0], out);
            success = backupManagerService.waitUntilOperationComplete(token);
        } catch (Exception e) {
@@ -107,7 +111,8 @@ public class FullBackupObbConnection implements ServiceConnection {
        synchronized (this) {
            while (mService == null) {
                if (RefactoredBackupManagerService.MORE_DEBUG) {
                  Slog.i(RefactoredBackupManagerService.TAG, "...waiting for OBB service binding...");
                    Slog.i(RefactoredBackupManagerService.TAG,
                            "...waiting for OBB service binding...");
                }
                try {
                    this.wait();
@@ -136,7 +141,8 @@ public class FullBackupObbConnection implements ServiceConnection {
        synchronized (this) {
            mService = null;
            if (RefactoredBackupManagerService.MORE_DEBUG) {
              Slog.i(RefactoredBackupManagerService.TAG, "OBB service connection disconnected on " + this);
                Slog.i(RefactoredBackupManagerService.TAG,
                        "OBB service connection disconnected on " + this);
            }
            this.notifyAll();
        }
+7 −3
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.backup.fullbackup;
import android.app.backup.IFullBackupRestoreObserver;
import android.os.RemoteException;
import android.util.Slog;

import com.android.server.backup.RefactoredBackupManagerService;

/**
@@ -38,7 +39,8 @@ public abstract class FullBackupTask implements Runnable {
            try {
                mObserver.onStartBackup();
            } catch (RemoteException e) {
                Slog.w(RefactoredBackupManagerService.TAG, "full backup observer went away: startBackup");
                Slog.w(RefactoredBackupManagerService.TAG,
                        "full backup observer went away: startBackup");
                mObserver = null;
            }
        }
@@ -50,7 +52,8 @@ public abstract class FullBackupTask implements Runnable {
                // TODO: use a more user-friendly name string
                mObserver.onBackupPackage(name);
            } catch (RemoteException e) {
                Slog.w(RefactoredBackupManagerService.TAG, "full backup observer went away: backupPackage");
                Slog.w(RefactoredBackupManagerService.TAG,
                        "full backup observer went away: backupPackage");
                mObserver = null;
            }
        }
@@ -61,7 +64,8 @@ public abstract class FullBackupTask implements Runnable {
            try {
                mObserver.onEndBackup();
            } catch (RemoteException e) {
                Slog.w(RefactoredBackupManagerService.TAG, "full backup observer went away: endBackup");
                Slog.w(RefactoredBackupManagerService.TAG,
                        "full backup observer went away: endBackup");
                mObserver = null;
            }
        }
+63 −45

File changed.

Preview size limit exceeded, changes collapsed.

Loading