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

Commit 87380366 authored by Winson's avatar Winson
Browse files

Defer post-install resource clean up for 5 seconds

There is an inherent problem with deleting files on disk while an
app is running, since it might still try to access code/resources
in the deleted files.

We cannot instantaneously update all application threads to the
new paths without blocking the world, so keep the old ones around
for an arbitrary amount of time.

As mentioned in the linked bug, if PackageManager boots with
duplicated app directories, it will automatically clean itself up,
so we are not concerned with the case where the deferred delete
message doesn't get executed in the current device boot cycle.

5 seconds was chosen with no reasoning beyond it feels safe.

Bug: 129291162

Test: manual reboot device with invalid dirs on disk
Test: manual dynamic feature delivery app with --dont-kill split

Change-Id: Id249a185a8556ebf133be3c36b1fec3f14b588ac
parent c91b915b
Loading
Loading
Loading
Loading
+26 −5
Original line number Diff line number Diff line
@@ -1319,6 +1319,9 @@ public class PackageManagerService extends IPackageManager.Stub
    static final int INSTANT_APP_RESOLUTION_PHASE_TWO = 20;
    static final int ENABLE_ROLLBACK_STATUS = 21;
    static final int ENABLE_ROLLBACK_TIMEOUT = 22;
    static final int DEFERRED_NO_KILL_POST_DELETE = 23;
    static final int DEFERRED_NO_KILL_POST_DELETE_DELAY_MS = 5 * 1000;
    static final int WRITE_SETTINGS_DELAY = 10*1000;  // 10 seconds
@@ -1525,6 +1528,12 @@ public class PackageManagerService extends IPackageManager.Stub
                    Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "postInstall", msg.arg1);
                } break;
                case DEFERRED_NO_KILL_POST_DELETE: {
                    synchronized (mInstallLock) {
                        InstallArgs args = (InstallArgs) msg.obj;
                        args.doPostDeleteLI(true);
                    }
                } break;
                case WRITE_SETTINGS: {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
                    synchronized (mPackages) {
@@ -2029,11 +2038,18 @@ public class PackageManagerService extends IPackageManager.Stub
                    getUnknownSourcesSettings());
            // Remove the replaced package's older resources safely now
            // We delete after a gc for applications  on sdcard.
            if (res.removedInfo != null && res.removedInfo.args != null) {
                Runtime.getRuntime().gc();
            InstallArgs args = res.removedInfo != null ? res.removedInfo.args : null;
            if (args != null) {
                if (!killApp) {
                    // If we didn't kill the app, defer the deletion of code/resource files, since
                    // they may still be in use by the running application. This mitigates problems
                    // in cases where resources or code is loaded by a new Activity before
                    // ApplicationInfo changes have propagated to all application threads.
                    scheduleDeferredNoKillPostDelete(args);
                } else {
                    synchronized (mInstallLock) {
                    res.removedInfo.args.doPostDeleteLI(true);
                        args.doPostDeleteLI(true);
                    }
                }
            } else {
                // Force a gc to clear up things. Ask for a background one, it's fine to go on
@@ -2068,6 +2084,11 @@ public class PackageManagerService extends IPackageManager.Stub
        }
    }
    private void scheduleDeferredNoKillPostDelete(InstallArgs args) {
        Message message = mHandler.obtainMessage(DEFERRED_NO_KILL_POST_DELETE, args);
        mHandler.sendMessageDelayed(message, DEFERRED_NO_KILL_POST_DELETE_DELAY_MS);
    }
    /**
     * Gets the type of the external storage a package is installed on.
     * @param packageVolume The storage volume of the package.