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

Commit e97e807a authored by Christopher Tate's avatar Christopher Tate
Browse files

The rest of ever-backed-up tracking

When a package is uninstalled we now remove our notion of its having been backed
up, thereby forcing a backup pass if it is reinstalled at some point in the
future.  Removal from the log means rewriting it and doing an atomic rename to
the canonical version.  The temporary existence used during the rewrite is *not*
written synchronously; there's no need and it keeps the load on the flash part
much lower.

Because we might crash & reboot in the middle of the rewrite operation, there's
now code during init that sanity-checks the contents of the ever-backed-up log
and ensures that it's in a coherent state.
parent f3ea3e09
Loading
Loading
Loading
Loading
+71 −5
Original line number Original line Diff line number Diff line
@@ -285,27 +285,55 @@ class BackupManagerService extends IBackupManager.Stub {
    private void initPackageTracking() {
    private void initPackageTracking() {
        if (DEBUG) Log.v(TAG, "Initializing package tracking");
        if (DEBUG) Log.v(TAG, "Initializing package tracking");


        // Keep a log of what apps we've ever backed up
        // Keep a log of what apps we've ever backed up.  Because we might have
        // rebooted in the middle of an operation that was removing something from
        // this log, we sanity-check its contents here and reconstruct it.
        mEverStored = new File(mBaseStateDir, "processed");
        mEverStored = new File(mBaseStateDir, "processed");
        File tempProcessedFile = new File(mBaseStateDir, "processed.new");
        try {
        try {
            mEverStoredStream = new RandomAccessFile(mEverStored, "rwd");
            RandomAccessFile temp = new RandomAccessFile(tempProcessedFile, "rw");
            mEverStoredStream = new RandomAccessFile(mEverStored, "r");


            // parse its existing contents
            // parse its existing contents
            mEverStoredStream.seek(0);
            mEverStoredStream.seek(0);
            temp.seek(0);
            try {
            try {
                while (true) {
                while (true) {
                    PackageInfo info;
                    String pkg = mEverStoredStream.readUTF();
                    String pkg = mEverStoredStream.readUTF();
                    try {
                        info = mPackageManager.getPackageInfo(pkg, 0);
                        mEverStoredApps.add(pkg);
                        mEverStoredApps.add(pkg);
                        temp.writeUTF(pkg);
                        if (DEBUG) Log.v(TAG, "   + " + pkg);
                        if (DEBUG) Log.v(TAG, "   + " + pkg);
                    } catch (NameNotFoundException e) {
                        // nope, this package was uninstalled; don't include it
                        if (DEBUG) Log.v(TAG, "   - " + pkg);
                    }
                }
                }
            } catch (EOFException e) {
            } catch (EOFException e) {
                // now we're at EOF
                // now we're at EOF
            }
            }

            // Once we've rewritten the backup history log, atomically replace the
            // old one with the new one then reopen the file for continuing use.
            temp.close();
            mEverStoredStream.close();
            tempProcessedFile.renameTo(mEverStored);
            mEverStoredStream = new RandomAccessFile(mEverStored, "rwd");
        } catch (IOException e) {
        } catch (IOException e) {
            Log.e(TAG, "Unable to open known-stored file!");
            Log.e(TAG, "Unable to open known-stored file!");
            mEverStoredStream = null;
            mEverStoredStream = null;
        }
        }


        // If we were in the middle of removing something from the ever-backed-up
        // file, there might be a transient "processed.new" file still present.
        // We've reconstructed a coherent state at this point though, so we can
        // safely discard that file now.
        if (tempProcessedFile.exists()) {
            tempProcessedFile.delete();
        }

        // Register for broadcasts about package install, etc., so we can
        // Register for broadcasts about package install, etc., so we can
        // update the provider list.
        // update the provider list.
        IntentFilter filter = new IntentFilter();
        IntentFilter filter = new IntentFilter();
@@ -573,6 +601,7 @@ class BackupManagerService extends IBackupManager.Stub {
                    for (ApplicationInfo entry: set) {
                    for (ApplicationInfo entry: set) {
                        if (entry.packageName.equals(pkg.packageName)) {
                        if (entry.packageName.equals(pkg.packageName)) {
                            set.remove(entry);
                            set.remove(entry);
                            removeEverBackedUp(pkg.packageName);
                            break;
                            break;
                        }
                        }
                    }
                    }
@@ -618,7 +647,7 @@ class BackupManagerService extends IBackupManager.Stub {
    // Called from the backup thread: record that the given app has been successfully
    // Called from the backup thread: record that the given app has been successfully
    // backed up at least once
    // backed up at least once
    void logBackupComplete(String packageName) {
    void logBackupComplete(String packageName) {
        if (mEverStoredStream != null) {
        if (mEverStoredStream != null && !packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
            synchronized (mEverStoredApps) {
            synchronized (mEverStoredApps) {
                if (mEverStoredApps.add(packageName)) {
                if (mEverStoredApps.add(packageName)) {
                    try {
                    try {
@@ -637,6 +666,43 @@ class BackupManagerService extends IBackupManager.Stub {
        }
        }
    }
    }


    // Remove our awareness of having ever backed up the given package
    void removeEverBackedUp(String packageName) {
        if (DEBUG) Log.v(TAG, "Removing backed-up knowledge of " + packageName
                + ", new set:");

        if (mEverStoredStream != null) {
            synchronized (mEverStoredApps) {
                // Rewrite the file and rename to overwrite.  If we reboot in the middle,
                // we'll recognize on initialization time that the package no longer
                // exists and fix it up then.
                File tempKnownFile = new File(mBaseStateDir, "processed.new");
                try {
                    mEverStoredStream.close();
                    RandomAccessFile known = new RandomAccessFile(tempKnownFile, "rw");
                    mEverStoredApps.remove(packageName);
                    for (String s : mEverStoredApps) {
                        known.writeUTF(s);
                        if (DEBUG) Log.v(TAG, "    " + s);
                    }
                    known.close();
                    tempKnownFile.renameTo(mEverStored);
                    mEverStoredStream = new RandomAccessFile(mEverStored, "rwd");
                } catch (IOException e) {
                    // Bad: we couldn't create the new copy.  For safety's sake we
                    // abandon the whole process and remove all what's-backed-up
                    // state entirely, meaning we'll force a backup pass for every
                    // participant on the next boot or [re]install.
                    Log.w(TAG, "Error rewriting backed-up set; halting log");
                    mEverStoredStream = null;
                    mEverStoredApps.clear();
                    tempKnownFile.delete();
                    mEverStored.delete();
                }
            }
        }
    }

    // Return the given transport
    // Return the given transport
    private IBackupTransport getTransport(String transportName) {
    private IBackupTransport getTransport(String transportName) {
        synchronized (mTransports) {
        synchronized (mTransports) {