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

Commit 3239fc9e authored by JW Wang's avatar JW Wang
Browse files

Pass correct install user when creating sessions

This CL passes the correct install user when creating sessions in
StagingManager and effectively reverts ag/6901350.

Add a test to ensure b/129397974 is not regressed as described in
b/158222747#comment11.

(Cherry-picked from 838dea54)

Fix: 129744602
Fix: 158222747
Test: atest MultiUserRollbackTest#testStagedRollback
Merged-In: I718992240aa76898ff9e4220ea6a769ee8cd61f5
Change-Id: I718992240aa76898ff9e4220ea6a769ee8cd61f5
parent 02c5ea67
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -743,7 +743,6 @@ public class StagingManager {
        PackageInstaller.SessionParams params = originalSession.params.copy();
        params.isStaged = false;
        params.installFlags |= PackageManager.INSTALL_STAGED;
        // TODO(b/129744602): use the userid from the original session.
        if (preReboot) {
            params.installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK;
            params.installFlags |= PackageManager.INSTALL_DRY_RUN;
@@ -753,7 +752,7 @@ public class StagingManager {
        try {
            int apkSessionId = mPi.createSession(
                    params, originalSession.getInstallerPackageName(),
                    0 /* UserHandle.SYSTEM */);
                    originalSession.userId);
            PackageInstallerSession apkSession = mPi.getSession(apkSessionId);
            apkSession.open();
            for (int i = 0, size = apkFilePaths.size(); i < size; i++) {
@@ -811,10 +810,9 @@ public class StagingManager {
            if (preReboot) {
                params.installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK;
            }
            // TODO(b/129744602): use the userid from the original session.
            final int apkParentSessionId = mPi.createSession(
                    params, session.getInstallerPackageName(),
                    0 /* UserHandle.SYSTEM */);
                    session.userId);
            final PackageInstallerSession apkParentSession = mPi.getSession(apkParentSessionId);
            try {
                apkParentSession.open();
+3 −0
Original line number Diff line number Diff line
@@ -48,6 +48,9 @@ java_test_host {
    name: "MultiUserRollbackTest",
    srcs: ["MultiUserRollbackTest/src/**/*.java"],
    libs: ["tradefed"],
    static_libs: [
        "frameworks-base-hostutils",
    ],
    test_suites: ["general-tests"],
    test_config: "MultiUserRollbackTest.xml",
}
+28 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

@@ -40,6 +41,9 @@ public class MultiUserRollbackTest extends BaseHostJUnit4Test {
    private static final long SWITCH_USER_COMPLETED_NUMBER_OF_POLLS = 60;
    private static final long SWITCH_USER_COMPLETED_POLL_INTERVAL_IN_MILLIS = 1000;

    @Rule
    public AbandonSessionsRule mHostTestRule = new AbandonSessionsRule(this);

    @After
    public void tearDown() throws Exception {
        removeSecondaryUserIfNecessary();
@@ -59,6 +63,30 @@ public class MultiUserRollbackTest extends BaseHostJUnit4Test {
        runPhaseForUsers("testBasic", mSecondaryUserId);
    }

    /**
     * Tests staged install/rollback works correctly on the 2nd user.
     */
    @Test
    public void testStagedRollback() throws Exception {
        runPhaseForUsers("testStagedRollback_Phase1", mSecondaryUserId);
        getDevice().reboot();

        // Need to unlock the user for device tests to run successfully
        getDevice().startUser(mSecondaryUserId);
        awaitUserUnlocked(mSecondaryUserId);
        runPhaseForUsers("testStagedRollback_Phase2", mSecondaryUserId);
        getDevice().reboot();

        getDevice().startUser(mSecondaryUserId);
        awaitUserUnlocked(mSecondaryUserId);
        runPhaseForUsers("testStagedRollback_Phase3", mSecondaryUserId);
        getDevice().reboot();

        getDevice().startUser(mSecondaryUserId);
        awaitUserUnlocked(mSecondaryUserId);
        runPhaseForUsers("testStagedRollback_Phase4", mSecondaryUserId);
    }

    @Test
    public void testMultipleUsers() throws Exception {
        runPhaseForUsers("testMultipleUsersInstallV1", mOriginalUserId, mSecondaryUserId);
+28 −0
Original line number Diff line number Diff line
@@ -115,4 +115,32 @@ public class MultiUserRollbackTest {
        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
        InstallUtils.processUserData(TestApp.A);
    }

    @Test
    public void testStagedRollback_Phase1() throws Exception {
        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
        Install.single(TestApp.A1).setStaged().commit();
        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
    }

    @Test
    public void testStagedRollback_Phase2() throws Exception {
        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
        Install.single(TestApp.A2).setStaged().setEnableRollback().commit();
        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
    }

    @Test
    public void testStagedRollback_Phase3() throws Exception {
        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
        RollbackInfo rollback = RollbackUtils.waitForAvailableRollback(TestApp.A);
        assertThat(rollback).packagesContainsExactly(Rollback.from(TestApp.A2).to(TestApp.A1));
        RollbackUtils.rollback(rollback.getRollbackId());
        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
    }

    @Test
    public void testStagedRollback_Phase4() {
        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
    }
}
+66 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.tests.rollback.host;

import com.android.ddmlib.Log;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;

import org.junit.rules.ExternalResource;

public final class AbandonSessionsRule extends ExternalResource {
    private static final String TAG = "AbandonSessionsRule";
    private final BaseHostJUnit4Test mHost;

    public AbandonSessionsRule(BaseHostJUnit4Test host) {
        mHost = host;
    }

    @Override
    protected void before() throws Throwable {
        abandonSessions(mHost.getDevice());
    }

    @Override
    protected void after() {
        try {
            abandonSessions(mHost.getDevice());
        } catch (Exception e) {
            mHost.getDevice().logOnDevice(TAG, Log.LogLevel.ERROR,
                    "%s", "Failed to abandon sessions");
        }
    }

    /**
     * Abandons all sessions to prevent interference in our tests.
     */
    private static void abandonSessions(ITestDevice device) throws Exception {
        // No point in abandoning applied or failed sessions. We care about ready sessions only.
        String cmdListReadySessions =
                "pm list staged-sessions --only-sessionid --only-parent --only-ready";
        String output = device.executeShellCommand(cmdListReadySessions);
        if (output.trim().isEmpty()) {
            // No sessions to abandon
            return;
        }
        // Ensure we have sufficient privilege to abandon sessions from other apps
        device.enableAdbRoot();
        device.executeShellCommand("for i in $(" + cmdListReadySessions
                + "); do pm install-abandon $i; done");
        device.disableAdbRoot();
    }
}