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 Diff line number Diff line
@@ -329,17 +329,15 @@ class ApexPackageInfo {
            ApexInfo ai = parsingApexInfo.get(parseResult.scanFile);

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

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

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

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

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

    @Override
    public boolean isHiddenUntilInstalled() {
        return pkgState.isHiddenUntilInstalled();
+57 −14
Original line number Diff line number Diff line
@@ -385,16 +385,16 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
    @Nullable
    @DataClass.ParcelWith(Parcelling.BuiltIn.ForBoolean.class)
    private Boolean requestRawExternalStorageAccess;
    // TODO(chiuwinson): Non-null
    @Nullable
    private ArraySet<String> mimeGroups;
    @NonNull
    @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringSet.class)
    private Set<String> mimeGroups = emptySet();
    // 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
    // and never assign this, so initialize this to true for those cases.
    private long mBooleans = Booleans.ENABLED;
    private long mBooleans2;
    @Nullable
    private Set<String> mKnownActivityEmbeddingCerts;
    @NonNull
    private Set<String> mKnownActivityEmbeddingCerts = emptySet();
    // Derived fields
    private long mLongVersionCode;
    private int mLocaleConfigRes;
@@ -549,7 +549,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
                if (mimeGroups != null && mimeGroups.size() > 500) {
                    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
    @Override
    public Set<String> getKnownActivityEmbeddingCerts() {
        return mKnownActivityEmbeddingCerts == null ? Collections.emptySet()
                : mKnownActivityEmbeddingCerts;
        return mKnownActivityEmbeddingCerts;
    }

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

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

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

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

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

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

        assignDerivedFields();
        assignDerivedFields2();

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

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

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

Loading