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

Commit 4859c973 authored by JW Wang's avatar JW Wang Committed by Android (Google) Code Review
Browse files

Merge changes I5d0eed9c,Iab1cd2bc

* changes:
  Clean up staging directories of abandoned sessions (4/n)
  Split abandon() (3/n)
parents f61b5b0d ec050f6a
Loading
Loading
Loading
Loading
+29 −16
Original line number Diff line number Diff line
@@ -2734,23 +2734,27 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
        }
    }

    @Override
    public void abandon() {
        if (hasParentSessionId()) {
            throw new IllegalStateException(
                    "Session " + sessionId + " is a child of multi-package session "
                            + getParentSessionId() +  " and may not be abandoned directly.");
    private void abandonNonStaged() {
        synchronized (mLock) {
            assertCallerIsOwnerOrRootLocked();
            if (mRelinquished) {
                if (LOGD) Slog.d(TAG, "Ignoring abandon after commit relinquished control");
                return;
            }
            destroyInternal();
        }
        dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
    }

    private void abandonStaged() {
        synchronized (mLock) {
            if (params.isStaged && mDestroyed) {
            if (mDestroyed) {
                // If a user abandons staged session in an unsafe state, then system will try to
                // abandon the destroyed staged session when it is safe on behalf of the user.
                assertCallerIsOwnerOrRootOrSystemLocked();
            } else {
                assertCallerIsOwnerOrRootLocked();
            }

            if (isStagedAndInTerminalState()) {
                // We keep the session in the database if it's in a finalized state. It will be
                // removed by PackageInstallerService when the last update time is old enough.
@@ -2758,23 +2762,32 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
                // do it now.
                return;
            }
            if (mCommitted && params.isStaged) {
            mDestroyed = true;
            if (mCommitted) {
                if (!mStagingManager.abortCommittedSessionLocked(this)) {
                    // Do not clean up the staged session from system. It is not safe yet.
                    mCallback.onStagedSessionChanged(this);
                    return;
                }
            }
            cleanStageDir(getChildSessionsLocked());
            destroyInternal();
        }
        dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
    }

            if (mRelinquished) {
                Slog.d(TAG, "Ignoring abandon after commit relinquished control");
                return;
    @Override
    public void abandon() {
        if (hasParentSessionId()) {
            throw new IllegalStateException(
                    "Session " + sessionId + " is a child of multi-package session "
                            + getParentSessionId() +  " and may not be abandoned directly.");
        }
            destroyInternal();
        if (params.isStaged) {
            abandonStaged();
        } else {
            abandonNonStaged();
        }
        dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
    }

    @Override
+12 −0
Original line number Diff line number Diff line
@@ -119,6 +119,18 @@ public class StagedInstallInternalTest {
        assertSessionReady(sessionId);
    }

    @Test
    public void testAbandonStagedSessionShouldCleanUp() throws Exception {
        int id1 = Install.single(TestApp.A1).setStaged().createSession();
        InstallUtils.getPackageInstaller().abandonSession(id1);
        int id2 = Install.multi(TestApp.A1).setStaged().createSession();
        InstallUtils.getPackageInstaller().abandonSession(id2);
        int id3 = Install.single(TestApp.A1).setStaged().commit();
        InstallUtils.getPackageInstaller().abandonSession(id3);
        int id4 = Install.multi(TestApp.A1).setStaged().commit();
        InstallUtils.getPackageInstaller().abandonSession(id4);
    }

    private static void assertSessionReady(int sessionId) {
        assertSessionState(sessionId,
                (session) -> assertThat(session.isStagedSessionReady()).isTrue());
+25 −0
Original line number Diff line number Diff line
@@ -41,6 +41,9 @@ import org.junit.Test;
import org.junit.runner.RunWith;

import java.io.File;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

@RunWith(DeviceJUnit4ClassRunner.class)
public class StagedInstallInternalTest extends BaseHostJUnit4Test {
@@ -200,6 +203,28 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
        assertThat(sessionIds.length).isEqualTo(3);
    }

    @Test
    public void testAbandonStagedSessionShouldCleanUp() throws Exception {
        List<String> before = getStagingDirectories();
        runPhase("testAbandonStagedSessionShouldCleanUp");
        List<String> after = getStagingDirectories();
        // The staging directories generated during the test should be deleted
        assertThat(after).isEqualTo(before);
    }

    private List<String> getStagingDirectories() {
        String baseDir = "/data/app-staging";
        try {
            return getDevice().getFileEntry(baseDir).getChildren(false)
                    .stream().filter(entry -> entry.getName().matches("session_\\d+"))
                    .map(entry -> entry.getName())
                    .collect(Collectors.toList());
        } catch (Exception e) {
            // Return an empty list if any error
            return Collections.EMPTY_LIST;
        }
    }

    private void restartSystemServer() throws Exception {
        // Restart the system server
        ProcessInfo oldPs = getDevice().getProcessByName("system_server");