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

Commit dcb7a951 authored by Christopher Tate's avatar Christopher Tate Committed by Android (Google) Code Review
Browse files

Merge "Always check restore against the latest backend metadata" into lmp-dev

parents dcfa7976 f7cbb1fc
Loading
Loading
Loading
Loading
+70 −91
Original line number Diff line number Diff line
@@ -6558,52 +6558,35 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
        private  void startRestore() {
            sendStartRestore(mAcceptSet.size());

            UnifiedRestoreState nextState = UnifiedRestoreState.RESTORE_FINISHED;
            try {
                // If we don't yet have PM metadata for this token, synthesize an
                // entry for the PM pseudopackage and make it the first to be
                // restored.
                String transportDir = mTransport.transportDirName();
                mStateDir = new File(mBaseStateDir, transportDir);
                File metadataDir = new File(mStateDir, "_metadata");
                metadataDir.mkdirs();
                File metadataFile = new File(metadataDir, Long.toHexString(mToken));
                try {
                    // PM info is cached in $BASE/transport/_metadata/$TOKEN
                    mPmAgent = new PackageManagerBackupAgent(metadataFile);
                } catch (IOException e) {
                    // Nope, we need to get it via restore
                    if (MORE_DEBUG) Slog.v(TAG, "Need to restore @pm@");

                // Fetch the current metadata from the dataset first
                PackageInfo pmPackage = new PackageInfo();
                pmPackage.packageName = PACKAGE_MANAGER_SENTINEL;
                mAcceptSet.add(0, pmPackage);
                }

                PackageInfo[] packages = mAcceptSet.toArray(new PackageInfo[0]);
                mStatus = mTransport.startRestore(mToken, packages);
                if (mStatus != BackupTransport.TRANSPORT_OK) {
                    Slog.e(TAG, "Transport error " + mStatus + "; no restore possible");
                    mStatus = BackupTransport.TRANSPORT_ERROR;
                    nextState = UnifiedRestoreState.FINAL;
                    executeNextState(UnifiedRestoreState.FINAL);
                    return;
                }

                if (mPmAgent == null) {
                    if (DEBUG) {
                        Slog.v(TAG, "Need to fetch metadata for token "
                                + Long.toHexString(mToken));
                    }
                RestoreDescription desc = mTransport.nextRestorePackage();
                if (desc == null) {
                    Slog.e(TAG, "No restore metadata available; halting");
                    mStatus = BackupTransport.TRANSPORT_ERROR;
                        nextState = UnifiedRestoreState.FINAL;
                    executeNextState(UnifiedRestoreState.FINAL);
                    return;
                }
                if (!PACKAGE_MANAGER_SENTINEL.equals(desc.getPackageName())) {
                    Slog.e(TAG, "Required metadata but got " + desc.getPackageName());
                    mStatus = BackupTransport.TRANSPORT_ERROR;
                        nextState = UnifiedRestoreState.FINAL;
                    executeNextState(UnifiedRestoreState.FINAL);
                    return;
                }

@@ -6617,58 +6600,35 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
                }
                initiateOneRestore(mCurrentPackage, 0);
                // The PM agent called operationComplete() already, because our invocation
                    // of it is process-local and therefore synchronous.  That means that a
                    // RUNNING_QUEUE message is already enqueued.  Only if we're unable to
                    // proceed with running the queue do we remove that pending message and
                    // jump straight to the FINAL state.
                // of it is process-local and therefore synchronous.  That means that the
                // next-state message (RUNNING_QUEUE) is already enqueued.  Only if we're
                // unable to proceed with running the queue do we remove that pending
                // message and jump straight to the FINAL state.

                // Verify that the backup set includes metadata.  If not, we can't do
                // signature/version verification etc, so we simply do not proceed with
                // the restore operation.
                if (!mPmAgent.hasMetadata()) {
                        Slog.e(TAG, "No restore metadata available, so not restoring settings");
                    Slog.e(TAG, "No restore metadata available, so not restoring");
                    EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
                            PACKAGE_MANAGER_SENTINEL,
                            "Package manager restore metadata missing");
                    mStatus = BackupTransport.TRANSPORT_ERROR;
                    mBackupHandler.removeMessages(MSG_BACKUP_RESTORE_STEP, this);
                        nextState = UnifiedRestoreState.FINAL;
                    executeNextState(UnifiedRestoreState.FINAL);
                    return;
                }

                // Success; cache the metadata and continue as expected with the
                    // RUNNING_QUEUE step already enqueued.
                    if (DEBUG) {
                        Slog.v(TAG, "Got metadata; caching and proceeding to restore");
                    }
                    try {
                        mPmAgent.saveToDisk(metadataFile);
                    } catch (IOException e) {
                        // Something bad; we need to abort
                        Slog.e(TAG, "Unable to write restored metadata");
                        EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
                                PACKAGE_MANAGER_SENTINEL,
                                "Unable to write restored metadata");
                        mStatus = BackupTransport.TRANSPORT_ERROR;
                        mBackupHandler.removeMessages(MSG_BACKUP_RESTORE_STEP, this);
                        nextState = UnifiedRestoreState.FINAL;
                        return;
                    }
                } else {
                    // We have the PMBA already, so we can proceed directly to
                    // the RUNNING_QUEUE state ourselves.
                    if (MORE_DEBUG) Slog.v(TAG, "PMBA from cache; proceeding to run queue");
                    nextState = UnifiedRestoreState.RUNNING_QUEUE;
                }
                // next state already enqueued

            } catch (RemoteException e) {
                // If we lost the transport at any time, halt
                Slog.e(TAG, "Unable to contact transport for restore");
                mStatus = BackupTransport.TRANSPORT_ERROR;
                mBackupHandler.removeMessages(MSG_BACKUP_RESTORE_STEP, this);
                nextState = UnifiedRestoreState.FINAL;
                executeNextState(UnifiedRestoreState.FINAL);
                return;
            } finally {
                executeNextState(nextState);
            }
        }

@@ -7267,6 +7227,13 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF

            final UnifiedRestoreState nextState;
            switch (mState) {
                case INITIAL:
                    // We've just (manually) restored the PMBA.  It doesn't need the
                    // additional restore-finished callback so we bypass that and go
                    // directly to running the queue.
                    nextState = UnifiedRestoreState.RUNNING_QUEUE;
                    break;

                case RESTORE_KEYVALUE:
                case RESTORE_FULL: {
                    // Okay, we've just heard back from the agent that it's done with
@@ -8187,6 +8154,9 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
                pkg.packageName = packageName;

                mWakelock.acquire();
                if (MORE_DEBUG) {
                    Slog.d(TAG, "Restore at install of " + packageName);
                }
                Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
                msg.obj = new RestoreParams(transport, dirName, null,
                        restoreSet, pkg, token);
@@ -8368,6 +8338,9 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
                    if (token == mRestoreSets[i].token) {
                        long oldId = Binder.clearCallingIdentity();
                        mWakelock.acquire();
                        if (MORE_DEBUG) {
                            Slog.d(TAG, "restoreAll() kicking off");
                        }
                        Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
                        msg.obj = new RestoreParams(mRestoreTransport, dirName,
                                observer, token);
@@ -8439,6 +8412,9 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
                    if (token == mRestoreSets[i].token) {
                        long oldId = Binder.clearCallingIdentity();
                        mWakelock.acquire();
                        if (MORE_DEBUG) {
                            Slog.d(TAG, "restoreSome() of " + packages.length + " packages");
                        }
                        Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
                        msg.obj = new RestoreParams(mRestoreTransport, dirName, observer, token,
                                packages, packages.length > 1);
@@ -8518,6 +8494,9 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
            // Ready to go:  enqueue the restore request and claim success
            long oldId = Binder.clearCallingIdentity();
            mWakelock.acquire();
            if (MORE_DEBUG) {
                Slog.d(TAG, "restorePackage() : " + packageName);
            }
            Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
            msg.obj = new RestoreParams(mRestoreTransport, dirName,
                    observer, token, app, 0);
+0 −91
Original line number Diff line number Diff line
@@ -37,7 +37,6 @@ import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -48,9 +47,6 @@ import java.util.List;
import java.util.Set;

import java.util.Objects;
import java.util.Map.Entry;

import libcore.io.IoUtils;

/**
 * We back up the signatures of each package so that during a system restore,
@@ -132,93 +128,6 @@ public class PackageManagerBackupAgent extends BackupAgent {
        mStoredIncrementalVersion = Build.VERSION.INCREMENTAL;
    }

    /**
     * Reconstitute a PMBA from its on-disk format.  This is used for persistence
     * of the ancestral dataset's metadata.  See {@link #saveToDisk()} for
     * details of the file format.
     */
    PackageManagerBackupAgent(File cache) throws IOException {
        FileInputStream fin = new FileInputStream(cache);
        BufferedInputStream bin = new BufferedInputStream(fin, 32 * 1024);
        DataInputStream in = new DataInputStream(bin);

        int version = in.readInt();
        // We can currently only handle the initial version format
        if (version == ANCESTRAL_RECORD_VERSION) {
            mStoredSdkVersion = in.readInt();
            mStoredIncrementalVersion = in.readUTF();

            int nPackages = in.readInt();
            if (nPackages > 0) {
                HashMap<String, Metadata> restoredMetadata =
                        new HashMap<String, Metadata>(nPackages);
                ArrayList<byte[]> hashes = null;
                for (int pack = 0; pack < nPackages; pack++) {
                    final String name = in.readUTF();
                    final int versionCode = in.readInt();
                    final int nHashes = in.readInt();
                    if (nHashes > 0) {
                        hashes = new ArrayList<byte[]>(nHashes);
                        for (int i = 0; i < nHashes; i++) {
                            int len = in.readInt();
                            byte[] hash = new byte[len];
                            in.read(hash);
                            hashes.add(hash);
                        }
                    }
                    restoredMetadata.put(name, new Metadata(versionCode, hashes));
                }
                mRestoredSignatures = restoredMetadata;
            }
        }
    }

    public void saveToDisk(File cache) throws IOException {
        // On disk format is very similar to the key/value format:
        //
        // Int: disk format version, currently 1
        // Int: VERSION.SDK_INT of source device
        // UTF: VERSION.INCREMENTAL string, for reference
        //
        // Int: number of packages represented in this file
        //
        // Per package if number > 0:
        //     UTF: package name
        //     Int: versionCode of the package
        //     Int: number of signature hash blocks for this package
        //     Per signature hash block:
        //         Int: size of block
        //         byte[]: block itself if size of block > 0
        FileOutputStream of = new FileOutputStream(cache);
        BufferedOutputStream bout = new BufferedOutputStream(of, 32*1024);
        DataOutputStream out = new DataOutputStream(bout);

        out.writeInt(ANCESTRAL_RECORD_VERSION);
        out.writeInt(mStoredSdkVersion);
        out.writeUTF(mStoredIncrementalVersion);

        out.writeInt(mRestoredSignatures.size());
        if (mRestoredSignatures.size() > 0) {
            Set<Entry<String, Metadata>> entries = mRestoredSignatures.entrySet();
            for (Entry<String, Metadata> i : entries) {
                final Metadata m = i.getValue();
                final int nHashes = (m.sigHashes != null) ? m.sigHashes.size() : 0;
                out.writeUTF(i.getKey());
                out.writeInt(m.versionCode);
                out.writeInt(nHashes);
                for (int h = 0; h < nHashes; h++) {
                    byte[] hash = m.sigHashes.get(h);
                    out.writeInt(hash.length);
                    if (hash.length > 0) {
                        out.write(hash);
                    }
                }
            }
        }
        out.flush();
        IoUtils.closeQuietly(out);
    }

    // We will need to refresh our understanding of what is eligible for
    // backup periodically; this entry point serves that purpose.
    public void evaluateStorablePackages() {