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

Commit 105c6f5c authored by Adnan Begovic's avatar Adnan Begovic
Browse files

pm: Avoid installing prebundle to other users that were uninstalled by owner.

  Otherwise the copied app data (since these are treated similarily to system
  packages on user creation) would be purged of the granted permissions in
  packages.xml.

  Also, it just doesn't make sense from a users perspective.

Change-Id: I9a72eb9a9f0bea9401e90daa86c8fa32e866c380
TICKET: OPO-695
parent a54a4794
Loading
Loading
Loading
Loading
+9 −8
Original line number Diff line number Diff line
@@ -5994,16 +5994,17 @@ public class PackageManagerService extends IPackageManager.Stub {
        if ((parseFlags & PackageParser.PARSE_IS_PREBUNDLED_DIR) != 0) {
            synchronized (mPackages) {
                PackageSetting existingSettings = mSettings.peekPackageLPr(pkg.packageName);
                boolean isInstalledForUser = (existingSettings != null
                        && existingSettings.getInstalled(user.getIdentifier()));
                if (mSettings.wasPrebundledPackageInstalledLPr(user.getIdentifier(),
                        pkg.packageName) && !isInstalledForUser) {
                    // The prebundled app was installed at some point for the user and isn't
                    // currently installed for the user, skip reinstalling it
                if (!mSettings.shouldPrebundledPackageBeInstalledForUserLPr(existingSettings,
                        user.getIdentifier(), pkg.packageName)) {
                    // The prebundled app was installed at some point for the owner and isn't
                    // currently installed for the owner, dont install it for a new user
                    // OR the prebundled app was installed for the user at some point and isn't
                    // current installed for the user, so skip reinstalling it
                    throw new PackageManagerException(INSTALL_FAILED_UNINSTALLED_PREBUNDLE,
                            "skip reinstall for " + pkg.packageName);
                } else if (!mSettings.shouldPrebundledPackageBeInstalled(mContext.getResources(),
                                pkg.packageName, mCustomResources)) {
                } else if (!mSettings.shouldPrebundledPackageBeInstalledForRegion(
                        mContext.getResources(), pkg.packageName, mCustomResources)) {
                    // The prebundled app is not needed for the default mobile country code,
                    // skip installing it
                    throw new PackageManagerException(INSTALL_FAILED_REGION_LOCKED_PREBUNDLE,
+32 −1
Original line number Diff line number Diff line
@@ -2524,7 +2524,7 @@ final class Settings {
        return mPrebundledPackages.get(userId).contains(packageName);
    }

    boolean shouldPrebundledPackageBeInstalled(Resources res, String packageName,
    boolean shouldPrebundledPackageBeInstalledForRegion(Resources res, String packageName,
                                            Resources configuredResources) {
        // Default fallback on lack of bad package
        if (TextUtils.isEmpty(packageName)) {
@@ -2557,6 +2557,37 @@ final class Settings {
        return !ArrayUtils.contains(prebundledArray, packageName);
    }

    boolean shouldPrebundledPackageBeInstalledForUserLPr(PackageSetting existingSettings,
            int userIdentifier, String packageName) {

        // Check if package installed for the user
        final boolean isInstalledForUser = (existingSettings != null
                && existingSettings.getInstalled(userIdentifier));

        // Check if package installed for the owner
        final boolean isInstalledForOwner = (existingSettings != null
                && existingSettings.getInstalled(UserHandle.USER_OWNER));

        // Check if the user is the owner
        final boolean isOwner = userIdentifier == UserHandle.USER_OWNER;

        // If the given user is not the owner, and the prebundle was installed for the owner
        // but is no longer installed, and isn't currently installed for the user,
        // skip installing it.
        if (!isOwner && wasPrebundledPackageInstalledLPr(UserHandle.USER_OWNER, packageName)
                && !isInstalledForOwner && !isInstalledForUser) {
            return false;
        }

        // If the given package was installed for the user and isn't currently, skip reinstalling it
        if (wasPrebundledPackageInstalledLPr(userIdentifier, packageName) &&
                !isInstalledForUser) {
            return false;
        }

        return true;
    }

    void writeDisabledSysPackageLPr(XmlSerializer serializer, final PackageSetting pkg)
            throws java.io.IOException {
        serializer.startTag(null, "updated-package");
+66 −2
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.test.AndroidTestCase;
import android.test.mock.MockContext;
import android.text.TextUtils;
@@ -365,7 +366,7 @@ public class PackageManagerSettingsTests extends AndroidTestCase {
        };
        Mockito.when(resources.getStringArray(R.array.config_restrict_to_region_locked_devices))
                .thenReturn(regionRestrictedPackages);
        assertFalse(settings.shouldPrebundledPackageBeInstalled(resources,
        assertFalse(settings.shouldPrebundledPackageBeInstalledForRegion(resources,
                expectedPackageNeededForRegion, resources));
    }

@@ -384,7 +385,70 @@ public class PackageManagerSettingsTests extends AndroidTestCase {

        Mockito.when(resources.getStringArray(R.array.config_restrict_to_region_locked_devices))
                .thenReturn(regionLockedPackages);
        assertTrue(settings.shouldPrebundledPackageBeInstalled(resources,
        assertTrue(settings.shouldPrebundledPackageBeInstalledForRegion(resources,
                expectedPackageNeededForRegion, resources));
    }

    // Shamelessly kanged from KeySetManagerServiceTest
    public PackageSetting generateFakePackageSetting(String name) {
        return new PackageSetting(name, name, new File(mContext.getCacheDir(), "fakeCodePath"),
                new File(mContext.getCacheDir(), "fakeResPath"), "", "", "",
                "", 1, 0, 0);
    }

    // Checks if a package that was installed and currently isn't installed for the owner
    // is accepted for a secondary user
    public void testPrebundledSecondaryUserAccept() {
        Settings settings = new Settings(getContext().getFilesDir());
        String expectedPackageToBeInstalled = "org.cyanogenmod.secondaryuser.package";

        PackageSetting packageSetting =
                generateFakePackageSetting(expectedPackageToBeInstalled);

        int userOwner = UserHandle.USER_OWNER;
        int userSecondary = 1000;

        // Return true that the package was installed for the owner at some point
        settings.markPrebundledPackageInstalledLPr(userOwner, expectedPackageToBeInstalled);
        assertTrue(settings.wasPrebundledPackageInstalledLPr(userOwner,
                expectedPackageToBeInstalled));

        // Return false that the package was installed for the secondary user at some point
        // DON'T MARK PREBUNDLED PACKAGE INSTALLED

        // Return false that the package is currently not installed for the owner
        packageSetting.setInstalled(false, userOwner);
        assertFalse(packageSetting.getInstalled(userOwner));

        // Return false that the package is currently not installed for the secondary user
        packageSetting.setInstalled(false, userSecondary);
        assertFalse(packageSetting.getInstalled(userSecondary));

        assertFalse(settings.shouldPrebundledPackageBeInstalledForUserLPr(packageSetting,
                userSecondary, expectedPackageToBeInstalled));
    }

    // Checks if a package that was installed for a secondary user and currently isn't installed
    // for the user is accepted to be reinstalled
    public void testPrebundledSecondaryUserReinstallAccept() {
        Settings settings = new Settings(getContext().getFilesDir());
        String expectedPackageToBeInstalled = "org.cyanogenmod.secondaryuser.package";

        PackageSetting packageSetting =
                generateFakePackageSetting(expectedPackageToBeInstalled);

        int userSecondary = 1000;

        // Return true that the package was installed for the secondary user at some point
        settings.markPrebundledPackageInstalledLPr(userSecondary, expectedPackageToBeInstalled);
        assertTrue(settings.wasPrebundledPackageInstalledLPr(userSecondary,
                expectedPackageToBeInstalled));

        // Return false that the package is currently not installed for the secondary user
        packageSetting.setInstalled(false, userSecondary);
        assertFalse(packageSetting.getInstalled(userSecondary));

        assertFalse(settings.shouldPrebundledPackageBeInstalledForUserLPr(packageSetting,
                userSecondary, expectedPackageToBeInstalled));
    }
}