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

Commit 6a496f11 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "[PM] Restore the PackageSetting value correctly" into main

parents 92ab503d 2c94851d
Loading
Loading
Loading
Loading
+7 −0
Original line number Original line Diff line number Diff line
@@ -1452,6 +1452,13 @@ public class PackageManagerServiceUtils {
            }
            }


            if (!ArrayUtils.isEmpty(after.splitNames)) {
            if (!ArrayUtils.isEmpty(after.splitNames)) {
                if (beforeSplitNames.length != beforeSplitRevisionCodes.length) {
                    throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
                            "Current split names and the split revision codes are not 1:1 mapping."
                                    + "This indicates that the package info data has been"
                                    + " corrupted.");
                }

                for (int i = 0; i < after.splitNames.length; i++) {
                for (int i = 0; i < after.splitNames.length; i++) {
                    final String splitName = after.splitNames[i];
                    final String splitName = after.splitNames[i];
                    final int j = ArrayUtils.indexOf(beforeSplitNames, splitName);
                    final int j = ArrayUtils.indexOf(beforeSplitNames, splitName);
+16 −2
Original line number Original line Diff line number Diff line
@@ -4489,10 +4489,24 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
        String splitName = parser.getAttributeValue(null, ATTR_NAME);
        String splitName = parser.getAttributeValue(null, ATTR_NAME);
        int splitRevision = parser.getAttributeInt(null, ATTR_VERSION, -1);
        int splitRevision = parser.getAttributeInt(null, ATTR_VERSION, -1);
        if (splitName != null && splitRevision >= 0) {
        if (splitName != null && splitRevision >= 0) {
            final int beforeSplitNamesLength = outPs.getSplitNames().length;
            // If the split name already exists in the outPs#getSplitNames, don't add it
            // into the array and update its revision code below
            outPs.setSplitNames(ArrayUtils.appendElement(String.class,
            outPs.setSplitNames(ArrayUtils.appendElement(String.class,
                    outPs.getSplitNames(), splitName));
                    outPs.getSplitNames(), splitName));

            // If the same split name has already been added before, update the latest
            // revision code
            final int afterSplitNamesLength = outPs.getSplitNames().length;
            if (beforeSplitNamesLength == afterSplitNamesLength) {
                final int index = ArrayUtils.indexOf(outPs.getSplitNames(), splitName);
                final int[] splitRevisionCodes = outPs.getSplitRevisionCodes();
                splitRevisionCodes[index] = splitRevision;
                outPs.setSplitRevisionCodes(splitRevisionCodes);
            } else {
                outPs.setSplitRevisionCodes(ArrayUtils.appendInt(
                outPs.setSplitRevisionCodes(ArrayUtils.appendInt(
                    outPs.getSplitRevisionCodes(), splitRevision));
                        outPs.getSplitRevisionCodes(), splitRevision, /* allowDuplicates= */ true));
            }
        }
        }


        XmlUtils.skipCurrentTag(parser);
        XmlUtils.skipCurrentTag(parser);
+341 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2024 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.server.pm;

import static org.testng.Assert.assertThrows;

import android.content.pm.PackageInfoLite;
import android.platform.test.annotations.Presubmit;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;

import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;

import org.junit.Test;
import org.junit.runner.RunWith;

import java.io.File;
import java.util.UUID;

@Presubmit
@RunWith(AndroidJUnit4.class)
@SmallTest
public class PackageManagerServiceUtilsTest {

    private static final String PACKAGE_NAME = "com.android.app";
    private static final File CODE_PATH =
            InstrumentationRegistry.getInstrumentation().getContext().getFilesDir();

    @Test
    public void testCheckDowngrade_packageSetting_versionCodeSmaller_throwException()
            throws Exception {
        final PackageSetting before = createPackageSetting();
        before.setLongVersionCode(2);
        final PackageInfoLite after = new PackageInfoLite();
        after.versionCode = 1;

        assertThrows(PackageManagerException.class,
                () -> PackageManagerServiceUtils.checkDowngrade(before, after));
    }

    @Test
    public void testCheckDowngrade_packageSetting_baseRevisionCodeSmaller_throwException()
            throws Exception {
        final PackageSetting before = createPackageSetting();
        before.setLongVersionCode(1);
        before.setBaseRevisionCode(2);
        final PackageInfoLite after = new PackageInfoLite();
        after.versionCode = 1;
        after.baseRevisionCode = 1;

        assertThrows(PackageManagerException.class,
                () -> PackageManagerServiceUtils.checkDowngrade(before, after));
    }

    @Test
    public void testCheckDowngrade_packageSetting_splitArraySizeIsDifferent_throwException()
            throws Exception {
        final String splitOne = "one";
        final String splitTwo = "two";
        final int revisionOne = 311;
        final int revisionTwo = 330;
        final String[] splitNames = new String[] { splitOne, splitTwo };
        final int[] beforeSplitRevisionCodes = new int[] { revisionOne };
        final int[] afterSplitRevisionCodes = new int[] { revisionOne, revisionTwo };

        final PackageSetting before = createPackageSetting();
        before.setLongVersionCode(1);
        before.setSplitNames(splitNames);
        before.setSplitRevisionCodes(beforeSplitRevisionCodes);
        final PackageInfoLite after = new PackageInfoLite();
        after.versionCode = 1;
        after.splitNames = splitNames;
        after.splitRevisionCodes = afterSplitRevisionCodes;

        assertThrows(PackageManagerException.class,
                () -> PackageManagerServiceUtils.checkDowngrade(before, after));
    }

    @Test
    public void testCheckDowngrade_packageSetting_splitRevisionCodeSmaller_throwException()
            throws Exception {
        final String splitOne = "one";
        final String splitTwo = "two";
        final int revisionOne = 311;
        final int revisionTwo = 330;
        final int revisionThree = 360;
        final String[] splitNames = new String[] { splitOne, splitTwo };
        final int[] beforeSplitRevisionCodes = new int[] { revisionTwo, revisionThree};
        final int[] afterSplitRevisionCodes = new int[] { revisionOne, revisionTwo };

        final PackageSetting before = createPackageSetting();
        before.setLongVersionCode(1);
        before.setSplitNames(splitNames);
        before.setSplitRevisionCodes(beforeSplitRevisionCodes);
        final PackageInfoLite after = new PackageInfoLite();
        after.versionCode = 1;
        after.splitNames = splitNames;
        after.splitRevisionCodes = afterSplitRevisionCodes;

        assertThrows(PackageManagerException.class,
                () -> PackageManagerServiceUtils.checkDowngrade(before, after));
    }

    @Test
    public void testCheckDowngrade_packageSetting_sameSplitNameRevisionsBigger()
            throws Exception {
        final String splitOne = "one";
        final String splitTwo = "two";
        final int revisionOne = 311;
        final int revisionTwo = 330;
        final int revisionThree = 360;
        final String[] splitNames = new String[] { splitOne, splitTwo };
        final int[] beforeSplitRevisionCodes = new int[] { revisionOne, revisionTwo};
        final int[] afterSplitRevisionCodes = new int[] { revisionOne, revisionThree };

        final PackageSetting before = createPackageSetting();
        before.setLongVersionCode(1);
        before.setSplitNames(splitNames);
        before.setSplitRevisionCodes(beforeSplitRevisionCodes);
        final PackageInfoLite after = new PackageInfoLite();
        after.versionCode = 1;
        after.splitNames = splitNames;
        after.splitRevisionCodes = afterSplitRevisionCodes;

        PackageManagerServiceUtils.checkDowngrade(before, after);
    }

    @Test
    public void testCheckDowngrade_packageSetting_hasDifferentSplitNames() throws Exception {
        final String splitOne = "one";
        final String splitTwo = "two";
        final int revisionOne = 311;
        final int revisionTwo = 330;
        final int revisionThree = 360;
        final String[] beforeSplitNames = new String[] { splitOne, splitTwo };
        final String[] afterSplitNames = new String[] { splitTwo };
        final int[] beforeSplitRevisionCodes = new int[] { revisionOne, revisionTwo};
        final int[] afterSplitRevisionCodes = new int[] { revisionThree };

        final PackageSetting before = createPackageSetting();
        before.setLongVersionCode(1);
        before.setSplitNames(beforeSplitNames);
        before.setSplitRevisionCodes(beforeSplitRevisionCodes);
        final PackageInfoLite after = new PackageInfoLite();
        after.versionCode = 1;
        after.splitNames = afterSplitNames;
        after.splitRevisionCodes = afterSplitRevisionCodes;

        PackageManagerServiceUtils.checkDowngrade(before, after);
    }

    @Test
    public void testCheckDowngrade_packageSetting_newSplitName() throws Exception {
        final String splitOne = "one";
        final String splitTwo = "two";
        final int revisionOne = 311;
        final int revisionTwo = 330;
        final String[] beforeSplitNames = new String[] { splitOne };
        final String[] afterSplitNames = new String[] { splitTwo };
        final int[] beforeSplitRevisionCodes = new int[] { revisionTwo };
        final int[] afterSplitRevisionCodes = new int[] { revisionOne };

        final PackageSetting before = createPackageSetting();
        before.setLongVersionCode(1);
        before.setSplitNames(beforeSplitNames);
        before.setSplitRevisionCodes(beforeSplitRevisionCodes);
        final PackageInfoLite after = new PackageInfoLite();
        after.versionCode = 1;
        after.splitNames = afterSplitNames;
        after.splitRevisionCodes = afterSplitRevisionCodes;

        PackageManagerServiceUtils.checkDowngrade(before, after);
    }

    @Test
    public void testCheckDowngrade_androidPackage_versionCodeSmaller_throwException()
            throws Exception {
        final AndroidPackage before = PackageImpl.forTesting(PACKAGE_NAME).hideAsParsed()
                .setVersionCode(2).hideAsFinal();
        final PackageInfoLite after = new PackageInfoLite();
        after.versionCode = 1;

        assertThrows(PackageManagerException.class,
                () -> PackageManagerServiceUtils.checkDowngrade(before, after));
    }

    @Test
    public void testCheckDowngrade_androidPackage_baseRevisionCodeSmaller_throwException()
            throws Exception {
        final AndroidPackage before = PackageImpl.forTesting(PACKAGE_NAME).setBaseRevisionCode(2)
                .hideAsParsed().setVersionCode(1).hideAsFinal();
        final PackageInfoLite after = new PackageInfoLite();
        after.versionCode = 1;
        after.baseRevisionCode = 1;

        assertThrows(PackageManagerException.class,
                () -> PackageManagerServiceUtils.checkDowngrade(before, after));
    }

    @Test
    public void testCheckDowngrade_androidPackage_splitArraySizeIsDifferent_throwException()
            throws Exception {
        final String splitOne = "one";
        final String splitTwo = "two";
        final int revisionOne = 311;
        final int revisionTwo = 330;
        final String[] splitNames = new String[] { splitOne, splitTwo };
        final int[] beforeSplitRevisionCodes = new int[] { revisionOne };
        final int[] afterSplitRevisionCodes = new int[] { revisionOne, revisionTwo };

        final AndroidPackage before = PackageImpl.forTesting(PACKAGE_NAME)
                .asSplit(splitNames, /* splitCodePaths= */ null,
                        beforeSplitRevisionCodes, /* splitDependencies= */ null)
                .hideAsParsed().setVersionCode(1).hideAsFinal();
        final PackageInfoLite after = new PackageInfoLite();
        after.versionCode = 1;
        after.splitNames = splitNames;
        after.splitRevisionCodes = afterSplitRevisionCodes;

        assertThrows(PackageManagerException.class,
                () -> PackageManagerServiceUtils.checkDowngrade(before, after));
    }

    @Test
    public void testCheckDowngrade_androidPackage_splitRevisionCodeSmaller_throwException()
            throws Exception {
        final String splitOne = "one";
        final String splitTwo = "two";
        final int revisionOne = 311;
        final int revisionTwo = 330;
        final int revisionThree = 360;
        final String[] splitNames = new String[] { splitOne, splitTwo };
        final int[] beforeSplitRevisionCodes = new int[] { revisionTwo, revisionThree};
        final int[] afterSplitRevisionCodes = new int[] { revisionOne, revisionTwo };

        final AndroidPackage before = PackageImpl.forTesting(PACKAGE_NAME)
                .asSplit(splitNames, /* splitCodePaths= */ null,
                        beforeSplitRevisionCodes, /* splitDependencies= */ null)
                .hideAsParsed().setVersionCode(1).hideAsFinal();
        final PackageInfoLite after = new PackageInfoLite();
        after.versionCode = 1;
        after.splitNames = splitNames;
        after.splitRevisionCodes = afterSplitRevisionCodes;

        assertThrows(PackageManagerException.class,
                () -> PackageManagerServiceUtils.checkDowngrade(before, after));
    }

    @Test
    public void testCheckDowngrade_androidPackage_sameSplitNameRevisionsBigger()
            throws Exception {
        final String splitOne = "one";
        final String splitTwo = "two";
        final int revisionOne = 311;
        final int revisionTwo = 330;
        final int revisionThree = 360;
        final String[] splitNames = new String[] { splitOne, splitTwo };
        final int[] beforeSplitRevisionCodes = new int[] { revisionOne, revisionTwo};
        final int[] afterSplitRevisionCodes = new int[] { revisionOne, revisionThree };

        final AndroidPackage before = PackageImpl.forTesting(PACKAGE_NAME)
                .asSplit(splitNames, /* splitCodePaths= */ null,
                        beforeSplitRevisionCodes, /* splitDependencies= */ null)
                .hideAsParsed().setVersionCode(1).hideAsFinal();
        final PackageInfoLite after = new PackageInfoLite();
        after.versionCode = 1;
        after.splitNames = splitNames;
        after.splitRevisionCodes = afterSplitRevisionCodes;

        PackageManagerServiceUtils.checkDowngrade(before, after);
    }

    @Test
    public void testCheckDowngrade_androidPackage_hasDifferentSplitNames() throws Exception {
        final String splitOne = "one";
        final String splitTwo = "two";
        final int revisionOne = 311;
        final int revisionTwo = 330;
        final int revisionThree = 360;
        final String[] beforeSplitNames = new String[] { splitOne, splitTwo };
        final String[] afterSplitNames = new String[] { splitTwo };
        final int[] beforeSplitRevisionCodes = new int[] { revisionOne, revisionTwo};
        final int[] afterSplitRevisionCodes = new int[] { revisionThree };

        final AndroidPackage before = PackageImpl.forTesting(PACKAGE_NAME)
                .asSplit(beforeSplitNames, /* splitCodePaths= */ null,
                        beforeSplitRevisionCodes, /* splitDependencies= */ null)
                .hideAsParsed().setVersionCode(1).hideAsFinal();
        final PackageInfoLite after = new PackageInfoLite();
        after.versionCode = 1;
        after.splitNames = afterSplitNames;
        after.splitRevisionCodes = afterSplitRevisionCodes;

        PackageManagerServiceUtils.checkDowngrade(before, after);
    }

    @Test
    public void testCheckDowngrade_androidPackage_newSplitName() throws Exception {
        final String splitOne = "one";
        final String splitTwo = "two";
        final int revisionOne = 311;
        final int revisionTwo = 330;
        final String[] beforeSplitNames = new String[] { splitOne };
        final String[] afterSplitNames = new String[] { splitTwo };
        final int[] beforeSplitRevisionCodes = new int[] { revisionTwo };
        final int[] afterSplitRevisionCodes = new int[] { revisionOne };

        final AndroidPackage before = PackageImpl.forTesting(PACKAGE_NAME)
                .asSplit(beforeSplitNames, /* splitCodePaths= */ null,
                        beforeSplitRevisionCodes, /* splitDependencies= */ null)
                .hideAsParsed().setVersionCode(1).hideAsFinal();
        final PackageInfoLite after = new PackageInfoLite();
        after.versionCode = 1;
        after.splitNames = afterSplitNames;
        after.splitRevisionCodes = afterSplitRevisionCodes;

        PackageManagerServiceUtils.checkDowngrade(before, after);
    }

    private PackageSetting createPackageSetting() {
        return new PackageSetting(PACKAGE_NAME, PACKAGE_NAME, CODE_PATH, /* pkgFlags= */ 0,
                /* privateFlags= */ 0 , UUID.randomUUID());
    }
}
+49 −1
Original line number Original line Diff line number Diff line
@@ -1092,7 +1092,7 @@ public class PackageManagerSettingsTests {
    }
    }


    @Test
    @Test
    public void testNoPkg_writeReadSplitVersions() {
    public void testNoPkgDifferentRevisions_writeReadSplitVersions() {
        Settings settings = makeSettings();
        Settings settings = makeSettings();
        PackageSetting packageSetting = createPackageSetting(PACKAGE_NAME_1);
        PackageSetting packageSetting = createPackageSetting(PACKAGE_NAME_1);
        packageSetting.setAppId(Process.FIRST_APPLICATION_UID);
        packageSetting.setAppId(Process.FIRST_APPLICATION_UID);
@@ -1116,6 +1116,54 @@ public class PackageManagerSettingsTests {
        assertThat(resultSetting.getSplitRevisionCodes()[1], is(revisionTwo));
        assertThat(resultSetting.getSplitRevisionCodes()[1], is(revisionTwo));
    }
    }


    @Test
    public void testNoPkgSameRevisions_writeReadSplitVersions() {
        Settings settings = makeSettings();
        PackageSetting packageSetting = createPackageSetting(PACKAGE_NAME_1);
        packageSetting.setAppId(Process.FIRST_APPLICATION_UID);

        final String splitOne = "one";
        final String splitTwo = "two";
        final int revisionOne = 311;
        packageSetting.setSplitNames(new String[] { splitOne, splitTwo});
        packageSetting.setSplitRevisionCodes(new int[] { revisionOne, revisionOne});
        settings.mPackages.put(PACKAGE_NAME_1, packageSetting);

        settings.writeLPr(computer, /* sync= */ true);
        settings.mPackages.clear();

        assertThat(settings.readLPw(computer, createFakeUsers()), is(true));
        PackageSetting resultSetting = settings.getPackageLPr(PACKAGE_NAME_1);
        assertThat(resultSetting.getSplitNames()[0], is(splitOne));
        assertThat(resultSetting.getSplitNames()[1], is(splitTwo));
        assertThat(resultSetting.getSplitRevisionCodes()[0], is(revisionOne));
        assertThat(resultSetting.getSplitRevisionCodes()[1], is(revisionOne));
    }

    @Test
    public void testNoPkgSameSplitNames_writeReadSplitVersions() {
        Settings settings = makeSettings();
        PackageSetting packageSetting = createPackageSetting(PACKAGE_NAME_1);
        packageSetting.setAppId(Process.FIRST_APPLICATION_UID);

        final String splitOne = "one";
        final int revisionOne = 311;
        final int revisionTwo = 330;
        packageSetting.setSplitNames(new String[] { splitOne, splitOne});
        packageSetting.setSplitRevisionCodes(new int[] { revisionOne, revisionTwo});
        settings.mPackages.put(PACKAGE_NAME_1, packageSetting);

        settings.writeLPr(computer, /* sync= */ true);
        settings.mPackages.clear();

        assertThat(settings.readLPw(computer, createFakeUsers()), is(true));
        PackageSetting resultSetting = settings.getPackageLPr(PACKAGE_NAME_1);
        assertThat(resultSetting.getSplitNames().length, is(1));
        assertThat(resultSetting.getSplitRevisionCodes().length, is(1));
        assertThat(resultSetting.getSplitNames()[0], is(splitOne));
        assertThat(resultSetting.getSplitRevisionCodes()[0], is(revisionTwo));
    }

    @Test
    @Test
    public void testWriteReadArchiveState() {
    public void testWriteReadArchiveState() {
        Settings settings = makeSettings();
        Settings settings = makeSettings();