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

Commit fad1ef99 authored by Winson Chiu's avatar Winson Chiu
Browse files

Add runtime unmodifiable check for PackageState

Introduces test that enforces that all members and their type
parameter children types that return collections/maps return non-null,
non-empty, unmodifiable objects when a test instance is constructed
and filled with data.

Makes the PackageImpl collections unmodifiable, but ignores the inner
objects with a constants list in the test. To be removed once the
inner object infrastructure is finished and can be marked immutable.

Bug: 235462722

Test: atest PackageManagerServiceUnitTests

Change-Id: I9759b7dd5c945e65498e22fcf408d53931dc502f
parent 94d707cc
Loading
Loading
Loading
Loading
+3 −5
Original line number Original line Diff line number Diff line
@@ -329,17 +329,15 @@ class ApexPackageInfo {
            ApexInfo ai = parsingApexInfo.get(parseResult.scanFile);
            ApexInfo ai = parsingApexInfo.get(parseResult.scanFile);


            if (throwable == null) {
            if (throwable == null) {
                // Calling hideAsFinal to assign derived fields for the app info flags.
                parseResult.parsedPackage.hideAsFinal();

                // TODO: When ENABLE_FEATURE_SCAN_APEX is finalized, remove this and the entire
                // TODO: When ENABLE_FEATURE_SCAN_APEX is finalized, remove this and the entire
                //  calling path code
                //  calling path code
                ScanPackageUtils.applyPolicy(parseResult.parsedPackage,
                ScanPackageUtils.applyPolicy(parseResult.parsedPackage,
                        PackageManagerService.SCAN_AS_SYSTEM,
                        PackageManagerService.SCAN_AS_SYSTEM,
                        mPackageManager == null ? null : mPackageManager.getPlatformPackage(),
                        mPackageManager == null ? null : mPackageManager.getPlatformPackage(),
                        false);
                        false);
                results.add(new ApexManager.ScanResult(
                // Calling hideAsFinal to assign derived fields for the app info flags.
                        ai, parseResult.parsedPackage, parseResult.parsedPackage.getPackageName()));
                AndroidPackage finalPkg = parseResult.parsedPackage.hideAsFinal();
                results.add(new ApexManager.ScanResult(ai, finalPkg, finalPkg.getPackageName()));
            } else if (throwable instanceof PackageManagerException) {
            } else if (throwable instanceof PackageManagerException) {
                throw new IllegalStateException("Unable to parse: " + ai.modulePath, throwable);
                throw new IllegalStateException("Unable to parse: " + ai.modulePath, throwable);
            } else {
            } else {
+2 −2
Original line number Original line Diff line number Diff line
@@ -3451,8 +3451,8 @@ final class InstallPackageHelper {


            if (throwable == null) {
            if (throwable == null) {
                try {
                try {
                    AndroidPackage pkg = addForInitLI(
                    addForInitLI(parseResult.parsedPackage, newParseFlags, newScanFlags, null);
                            parseResult.parsedPackage, newParseFlags, newScanFlags, null);
                    AndroidPackage pkg = parseResult.parsedPackage.hideAsFinal();
                    if (ai.isFactory && !ai.isActive) {
                    if (ai.isFactory && !ai.isActive) {
                        disableSystemPackageLPw(pkg);
                        disableSystemPackageLPw(pkg);
                    }
                    }
+12 −0
Original line number Original line Diff line number Diff line
@@ -1207,12 +1207,24 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
        return pkgState.getUsesLibraryInfos();
        return pkgState.getUsesLibraryInfos();
    }
    }


    @NonNull
    public PackageSetting addUsesLibraryInfo(@NonNull SharedLibraryInfo value) {
        pkgState.addUsesLibraryInfo(value);
        return this;
    }

    @NonNull
    @NonNull
    @Override
    @Override
    public List<String> getUsesLibraryFiles() {
    public List<String> getUsesLibraryFiles() {
        return pkgState.getUsesLibraryFiles();
        return pkgState.getUsesLibraryFiles();
    }
    }


    @NonNull
    public PackageSetting addUsesLibraryFile(String value) {
        pkgState.addUsesLibraryFile(value);
        return this;
    }

    @Override
    @Override
    public boolean isHiddenUntilInstalled() {
    public boolean isHiddenUntilInstalled() {
        return pkgState.isHiddenUntilInstalled();
        return pkgState.isHiddenUntilInstalled();
+57 −14
Original line number Original line Diff line number Diff line
@@ -385,16 +385,16 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
    @Nullable
    @Nullable
    @DataClass.ParcelWith(Parcelling.BuiltIn.ForBoolean.class)
    @DataClass.ParcelWith(Parcelling.BuiltIn.ForBoolean.class)
    private Boolean requestRawExternalStorageAccess;
    private Boolean requestRawExternalStorageAccess;
    // TODO(chiuwinson): Non-null
    @NonNull
    @Nullable
    @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringSet.class)
    private ArraySet<String> mimeGroups;
    private Set<String> mimeGroups = emptySet();
    // Usually there's code to set enabled to true during parsing, but it's possible to install
    // Usually there's code to set enabled to true during parsing, but it's possible to install
    // an APK targeting <R that doesn't contain an <application> tag. That code would be skipped
    // an APK targeting <R that doesn't contain an <application> tag. That code would be skipped
    // and never assign this, so initialize this to true for those cases.
    // and never assign this, so initialize this to true for those cases.
    private long mBooleans = Booleans.ENABLED;
    private long mBooleans = Booleans.ENABLED;
    private long mBooleans2;
    private long mBooleans2;
    @Nullable
    @NonNull
    private Set<String> mKnownActivityEmbeddingCerts;
    private Set<String> mKnownActivityEmbeddingCerts = emptySet();
    // Derived fields
    // Derived fields
    private long mLongVersionCode;
    private long mLongVersionCode;
    private int mLocaleConfigRes;
    private int mLocaleConfigRes;
@@ -549,7 +549,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
                if (mimeGroups != null && mimeGroups.size() > 500) {
                if (mimeGroups != null && mimeGroups.size() > 500) {
                    throw new IllegalStateException("Max limit on number of MIME Groups reached");
                    throw new IllegalStateException("Max limit on number of MIME Groups reached");
                }
                }
                mimeGroups = ArrayUtils.add(mimeGroups, filter.getMimeGroup(groupIndex));
                mimeGroups = CollectionUtils.add(mimeGroups, filter.getMimeGroup(groupIndex));
            }
            }
        }
        }
    }
    }
@@ -935,8 +935,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
    @NonNull
    @NonNull
    @Override
    @Override
    public Set<String> getKnownActivityEmbeddingCerts() {
    public Set<String> getKnownActivityEmbeddingCerts() {
        return mKnownActivityEmbeddingCerts == null ? Collections.emptySet()
        return mKnownActivityEmbeddingCerts;
                : mKnownActivityEmbeddingCerts;
    }
    }


    @Override
    @Override
@@ -1949,8 +1948,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
    }
    }


    @Override
    @Override
    public ParsingPackage setKnownActivityEmbeddingCerts(
    public ParsingPackage setKnownActivityEmbeddingCerts(@NonNull Set<String> knownEmbeddingCerts) {
            @Nullable Set<String> knownEmbeddingCerts) {
        mKnownActivityEmbeddingCerts = knownEmbeddingCerts;
        mKnownActivityEmbeddingCerts = knownEmbeddingCerts;
        return this;
        return this;
    }
    }
@@ -2516,7 +2514,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
        appInfo.setVersionCode(mLongVersionCode);
        appInfo.setVersionCode(mLongVersionCode);
        appInfo.setAppClassNamesByProcess(buildAppClassNamesByProcess());
        appInfo.setAppClassNamesByProcess(buildAppClassNamesByProcess());
        appInfo.setLocaleConfigRes(mLocaleConfigRes);
        appInfo.setLocaleConfigRes(mLocaleConfigRes);
        if (mKnownActivityEmbeddingCerts != null) {
        if (!mKnownActivityEmbeddingCerts.isEmpty()) {
            appInfo.setKnownActivityEmbeddingCerts(mKnownActivityEmbeddingCerts);
            appInfo.setKnownActivityEmbeddingCerts(mKnownActivityEmbeddingCerts);
        }
        }


@@ -2593,11 +2591,11 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,


    @Override
    @Override
    public AndroidPackageInternal hideAsFinal() {
    public AndroidPackageInternal hideAsFinal() {
        // TODO(b/135203078): Lock as immutable
        if (mStorageUuid == null) {
        if (mStorageUuid == null) {
            assignDerivedFields();
            assignDerivedFields();
        }
        }
        assignDerivedFields2();
        assignDerivedFields2();
        makeImmutable();
        return this;
        return this;
    }
    }


@@ -2613,6 +2611,48 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
                baseAppDataDir + Environment.DIR_USER_DE + systemUserSuffix);
                baseAppDataDir + Environment.DIR_USER_DE + systemUserSuffix);
    }
    }


    private void makeImmutable() {
        usesLibraries = Collections.unmodifiableList(usesLibraries);
        usesOptionalLibraries = Collections.unmodifiableList(usesOptionalLibraries);
        usesNativeLibraries = Collections.unmodifiableList(usesNativeLibraries);
        usesOptionalNativeLibraries = Collections.unmodifiableList(usesOptionalNativeLibraries);
        originalPackages = Collections.unmodifiableList(originalPackages);
        adoptPermissions = Collections.unmodifiableList(adoptPermissions);
        requestedPermissions = Collections.unmodifiableList(requestedPermissions);
        protectedBroadcasts = Collections.unmodifiableList(protectedBroadcasts);
        apexSystemServices = Collections.unmodifiableList(apexSystemServices);

        activities = Collections.unmodifiableList(activities);
        receivers = Collections.unmodifiableList(receivers);
        services = Collections.unmodifiableList(services);
        providers = Collections.unmodifiableList(providers);
        permissions = Collections.unmodifiableList(permissions);
        permissionGroups = Collections.unmodifiableList(permissionGroups);
        instrumentations = Collections.unmodifiableList(instrumentations);

        overlayables = Collections.unmodifiableMap(overlayables);
        libraryNames = Collections.unmodifiableList(libraryNames);
        usesStaticLibraries = Collections.unmodifiableList(usesStaticLibraries);
        usesSdkLibraries = Collections.unmodifiableList(usesSdkLibraries);
        configPreferences = Collections.unmodifiableList(configPreferences);
        reqFeatures = Collections.unmodifiableList(reqFeatures);
        featureGroups = Collections.unmodifiableList(featureGroups);
        usesPermissions = Collections.unmodifiableList(usesPermissions);
        usesSdkLibraries = Collections.unmodifiableList(usesSdkLibraries);
        implicitPermissions = Collections.unmodifiableList(implicitPermissions);
        upgradeKeySets = Collections.unmodifiableSet(upgradeKeySets);
        keySetMapping = Collections.unmodifiableMap(keySetMapping);
        attributions = Collections.unmodifiableList(attributions);
        preferredActivityFilters = Collections.unmodifiableList(preferredActivityFilters);
        processes = Collections.unmodifiableMap(processes);
        mProperties = Collections.unmodifiableMap(mProperties);
        queriesIntents = Collections.unmodifiableList(queriesIntents);
        queriesPackages = Collections.unmodifiableList(queriesPackages);
        queriesProviders = Collections.unmodifiableSet(queriesProviders);
        mimeGroups = Collections.unmodifiableSet(mimeGroups);
        mKnownActivityEmbeddingCerts = Collections.unmodifiableSet(mKnownActivityEmbeddingCerts);
    }

    @Override
    @Override
    public long getLongVersionCode() {
    public long getLongVersionCode() {
        return PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode);
        return PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode);
@@ -3041,7 +3081,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
        dest.writeIntArray(this.splitRevisionCodes);
        dest.writeIntArray(this.splitRevisionCodes);
        sForBoolean.parcel(this.resizeableActivity, dest, flags);
        sForBoolean.parcel(this.resizeableActivity, dest, flags);
        dest.writeInt(this.autoRevokePermissions);
        dest.writeInt(this.autoRevokePermissions);
        dest.writeArraySet(this.mimeGroups);
        sForInternedStringSet.parcel(this.mimeGroups, dest, flags);
        dest.writeInt(this.gwpAsanMode);
        dest.writeInt(this.gwpAsanMode);
        dest.writeSparseIntArray(this.minExtensionVersions);
        dest.writeSparseIntArray(this.minExtensionVersions);
        dest.writeMap(this.mProperties);
        dest.writeMap(this.mProperties);
@@ -3201,7 +3241,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
        this.resizeableActivity = sForBoolean.unparcel(in);
        this.resizeableActivity = sForBoolean.unparcel(in);


        this.autoRevokePermissions = in.readInt();
        this.autoRevokePermissions = in.readInt();
        this.mimeGroups = (ArraySet<String>) in.readArraySet(boot);
        this.mimeGroups = sForInternedStringSet.unparcel(in);
        this.gwpAsanMode = in.readInt();
        this.gwpAsanMode = in.readInt();
        this.minExtensionVersions = in.readSparseIntArray();
        this.minExtensionVersions = in.readSparseIntArray();
        this.mProperties = in.readHashMap(boot);
        this.mProperties = in.readHashMap(boot);
@@ -3224,6 +3264,9 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,


        assignDerivedFields();
        assignDerivedFields();
        assignDerivedFields2();
        assignDerivedFields2();

        // Do not call makeImmutable here as cached parsing will need
        // to mutate this instance before it's finalized.
    }
    }


    @NonNull
    @NonNull
+6 −5
Original line number Original line Diff line number Diff line
@@ -33,6 +33,7 @@ import com.android.server.pm.PackageSetting;
import com.android.server.pm.Settings;
import com.android.server.pm.Settings;


import java.io.File;
import java.io.File;
import java.util.Collections;
import java.util.List;
import java.util.List;
import java.util.Map;
import java.util.Map;
import java.util.Set;
import java.util.Set;
@@ -170,7 +171,7 @@ public class PackageStateImpl implements PackageState {
        mLastModifiedTime = pkgState.getLastModifiedTime();
        mLastModifiedTime = pkgState.getLastModifiedTime();
        mLastUpdateTime = pkgState.getLastUpdateTime();
        mLastUpdateTime = pkgState.getLastUpdateTime();
        mLongVersionCode = pkgState.getVersionCode();
        mLongVersionCode = pkgState.getVersionCode();
        mMimeGroups = pkgState.getMimeGroups();
        mMimeGroups = Collections.unmodifiableMap(pkgState.getMimeGroups());
        mPath = pkgState.getPath();
        mPath = pkgState.getPath();
        mPrimaryCpuAbi = pkgState.getPrimaryCpuAbi();
        mPrimaryCpuAbi = pkgState.getPrimaryCpuAbi();
        mSecondaryCpuAbi = pkgState.getSecondaryCpuAbi();
        mSecondaryCpuAbi = pkgState.getSecondaryCpuAbi();
@@ -180,8 +181,8 @@ public class PackageStateImpl implements PackageState {
        mUsesSdkLibrariesVersionsMajor = pkgState.getUsesSdkLibrariesVersionsMajor();
        mUsesSdkLibrariesVersionsMajor = pkgState.getUsesSdkLibrariesVersionsMajor();
        mUsesStaticLibraries = pkgState.getUsesStaticLibraries();
        mUsesStaticLibraries = pkgState.getUsesStaticLibraries();
        mUsesStaticLibrariesVersions = pkgState.getUsesStaticLibrariesVersions();
        mUsesStaticLibrariesVersions = pkgState.getUsesStaticLibrariesVersions();
        mUsesLibraryInfos = pkgState.getUsesLibraryInfos();
        mUsesLibraryInfos = Collections.unmodifiableList(pkgState.getUsesLibraryInfos());
        mUsesLibraryFiles = pkgState.getUsesLibraryFiles();
        mUsesLibraryFiles = Collections.unmodifiableList(pkgState.getUsesLibraryFiles());
        setBoolean(Booleans.FORCE_QUERYABLE_OVERRIDE, pkgState.isForceQueryableOverride());
        setBoolean(Booleans.FORCE_QUERYABLE_OVERRIDE, pkgState.isForceQueryableOverride());
        setBoolean(Booleans.HIDDEN_UNTIL_INSTALLED, pkgState.isHiddenUntilInstalled());
        setBoolean(Booleans.HIDDEN_UNTIL_INSTALLED, pkgState.isHiddenUntilInstalled());
        setBoolean(Booleans.INSTALL_PERMISSIONS_FIXED, pkgState.isInstallPermissionsFixed());
        setBoolean(Booleans.INSTALL_PERMISSIONS_FIXED, pkgState.isInstallPermissionsFixed());
@@ -195,8 +196,8 @@ public class PackageStateImpl implements PackageState {
        int userStatesSize = userStates.size();
        int userStatesSize = userStates.size();
        mUserStates = new SparseArray<>(userStatesSize);
        mUserStates = new SparseArray<>(userStatesSize);
        for (int index = 0; index < userStatesSize; index++) {
        for (int index = 0; index < userStatesSize; index++) {
            mUserStates.put(mUserStates.keyAt(index),
            mUserStates.put(userStates.keyAt(index),
                    UserStateImpl.copy(mUserStates.valueAt(index)));
                    UserStateImpl.copy(userStates.valueAt(index)));
        }
        }
    }
    }


Loading