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

Commit d08ba27a authored by Winson Chiu's avatar Winson Chiu Committed by Android (Google) Code Review
Browse files

Merge changes I2cf2e739,I9e4bd242,Ic8b93a8c,Ibccde458,I04942e14, ... into sc-dev

* changes:
  Fix domain verify restore and add signature check
  Support serializing package signatures for domain verification state
  Add domain verification CTS to TEST_MAPPING
  Fix DomainVerificationService deadlock
  Check installed and enabled state for package domain approval
  Revoke domain user selection when approved through shell
parents 748a568a 3482338b
Loading
Loading
Loading
Loading
+15 −1
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.pm.overlay.OverlayPaths;
import android.content.pm.parsing.ParsingPackageRead;
import android.content.pm.parsing.component.ParsedMainComponent;
import android.os.BaseBundle;
import android.os.Debug;
@@ -53,7 +54,6 @@ import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;

import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;

@@ -310,6 +310,20 @@ public class PackageUserState {
        return result;
    }

    public boolean isPackageEnabled(@NonNull ParsingPackageRead pkg) {
        switch (this.enabled) {
            case COMPONENT_ENABLED_STATE_ENABLED:
                return true;
            case COMPONENT_ENABLED_STATE_DISABLED:
            case COMPONENT_ENABLED_STATE_DISABLED_USER:
            case COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED:
                return false;
            default:
            case COMPONENT_ENABLED_STATE_DEFAULT:
                return pkg.isEnabled();
        }
    }

    public boolean isEnabled(ComponentInfo componentInfo, int flags) {
        return isEnabled(componentInfo.applicationInfo.enabled, componentInfo.enabled,
                componentInfo.name, flags);
+6 −0
Original line number Diff line number Diff line
@@ -7,6 +7,12 @@
          "include-filter": "com.android.server.pm.test.verify.domain"
        }
      ]
    },
    {
      "name": "CtsDomainVerificationDeviceTestCases"
    },
    {
      "name": "CtsDomainVerificationHostTestCases"
    }
  ]
}
+80 −13
Original line number Diff line number Diff line
@@ -356,6 +356,7 @@ import com.android.internal.util.CollectionUtils;
import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.FunctionalUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.permission.persistence.RuntimePermissionsPersistence;
@@ -1686,9 +1687,8 @@ public class PackageManagerService extends IPackageManager.Stub
    private final DomainVerificationConnection mDomainVerificationConnection =
            new DomainVerificationConnection();
    private class DomainVerificationConnection implements
            DomainVerificationService.Connection, DomainVerificationProxyV1.Connection,
            DomainVerificationProxyV2.Connection {
    private class DomainVerificationConnection implements DomainVerificationService.Connection,
            DomainVerificationProxyV1.Connection, DomainVerificationProxyV2.Connection {
        @Override
        public void scheduleWriteSettings() {
@@ -1734,20 +1734,75 @@ public class PackageManagerService extends IPackageManager.Stub
        @Nullable
        @Override
        public PackageSetting getPackageSettingLocked(@NonNull String pkgName) {
            return PackageManagerService.this.getPackageSetting(pkgName);
        public AndroidPackage getPackage(@NonNull String packageName) {
            return PackageManagerService.this.getPackage(packageName);
        }
        @Nullable
        @NonNull
        @Override
        public AndroidPackage getPackageLocked(@NonNull String pkgName) {
            return PackageManagerService.this.getPackage(pkgName);
        public void withPackageSettings(@NonNull Consumer<Function<String, PackageSetting>> block) {
            final Computer snapshot = snapshotComputer();
            // This method needs to either lock or not lock consistently throughout the method,
            // so if the live computer is returned, force a wrapping sync block.
            if (snapshot == mLiveComputer) {
                synchronized (mLock) {
                    block.accept(snapshot::getPackageSetting);
                }
            } else {
                block.accept(snapshot::getPackageSetting);
            }
        }
        @Nullable
        @Override
        public AndroidPackage getPackage(@NonNull String packageName) {
            return getPackageLocked(packageName);
        public <Output> Output withPackageSettingsReturning(
                @NonNull FunctionalUtils.ThrowingFunction<Function<String, PackageSetting>, Output>
                        block) {
            final Computer snapshot = snapshotComputer();
            // This method needs to either lock or not lock consistently throughout the method,
            // so if the live computer is returned, force a wrapping sync block.
            if (snapshot == mLiveComputer) {
                synchronized (mLock) {
                    return block.apply(snapshot::getPackageSetting);
                }
            } else {
                return block.apply(snapshot::getPackageSetting);
            }
        }
        @Override
        public <ExceptionType extends Exception> void withPackageSettingsThrowing(
                @NonNull ThrowingConsumer<Function<String, PackageSetting>, ExceptionType> block)
                throws ExceptionType {
            final Computer snapshot = snapshotComputer();
            // This method needs to either lock or not lock consistently throughout the method,
            // so if the live computer is returned, force a wrapping sync block.
            if (snapshot == mLiveComputer) {
                synchronized (mLock) {
                    block.accept(snapshot::getPackageSetting);
                }
            } else {
                block.accept(snapshot::getPackageSetting);
            }
        }
        @Override
        public <Output, ExceptionType extends Exception> Output
                withPackageSettingsReturningThrowing(@NonNull ThrowingFunction<Function<String,
                PackageSetting>, Output, ExceptionType> block) throws ExceptionType {
            final Computer snapshot = snapshotComputer();
            // This method needs to either lock or not lock consistently throughout the method,
            // so if the live computer is returned, force a wrapping sync block.
            if (snapshot == mLiveComputer) {
                synchronized (mLock) {
                    return block.apply(snapshot::getPackageSetting);
                }
            } else {
                return block.apply(snapshot::getPackageSetting);
            }
        }
        @Override
@@ -2012,7 +2067,7 @@ public class PackageManagerService extends IPackageManager.Stub
        // Cached attributes.  The names in this class are the same as the
        // names in PackageManagerService; see that class for documentation.
        private final Settings mSettings;
        protected final Settings mSettings;
        private final WatchedSparseIntArray mIsolatedOwners;
        private final WatchedArrayMap<String, AndroidPackage> mPackages;
        private final WatchedArrayMap<ComponentName, ParsedInstrumentation>
@@ -4669,6 +4724,17 @@ public class PackageManagerService extends IPackageManager.Stub
            mLock = mService.mLock;
        }
        /**
         * Explicilty snapshot {@link Settings#mPackages} for cases where the caller must not lock
         * in order to get package data. It is expected that the caller locks itself to be able
         * to block on changes to the package data and bring itself up to date once the change
         * propagates to it. Use with heavy caution.
         * @return
         */
        private Map<String, PackageSetting> snapshotPackageSettings() {
            return mSettings.snapshot().mPackages;
        }
        public @NonNull List<ResolveInfo> queryIntentServicesInternalBody(Intent intent,
                String resolvedType, int flags, int userId, int callingUid,
                String instantAppPkgName) {
@@ -4800,7 +4866,7 @@ public class PackageManagerService extends IPackageManager.Stub
    // Compute read-only functions, based on live data.  This attribute may be modified multiple
    // times during the PackageManagerService constructor but it should not be modified thereafter.
    private Computer mLiveComputer;
    private ComputerLocked mLiveComputer;
    // A lock-free cache for frequently called functions.
    private volatile Computer mSnapshotComputer;
    // If true, the snapshot is invalid (stale).  The attribute is static since it may be
@@ -21760,6 +21826,7 @@ public class PackageManagerService extends IPackageManager.Stub
            clearPackagePreferredActivities(ps.name, nextUserId);
            mPermissionManager.onPackageUninstalled(ps.name, ps.appId, pkg, sharedUserPkgs,
                    nextUserId);
            mDomainVerificationManager.clearPackageForUser(ps.name, nextUserId);
        }
        if (outInfo != null) {
+56 −20
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.verify.domain.DomainVerificationInfo;
import android.content.pm.verify.domain.DomainVerificationManager;
import android.content.pm.verify.domain.DomainVerificationState;
import android.os.Binder;
import android.os.UserHandle;
import android.util.IndentingPrintWriter;
@@ -35,8 +36,10 @@ import android.util.Pair;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;

import com.android.internal.util.FunctionalUtils;
import com.android.server.pm.PackageManagerService;
import com.android.server.pm.PackageSetting;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.Settings;
import com.android.server.pm.verify.domain.models.DomainVerificationPkgState;
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy;

@@ -46,6 +49,7 @@ import java.io.IOException;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Function;

public interface DomainVerificationManagerInternal {
@@ -108,9 +112,10 @@ public interface DomainVerificationManagerInternal {
    int APPROVAL_LEVEL_INSTANT_APP = 5;

    /**
     * Defines the possible values for {@link #approvalLevelForDomain(PackageSetting, Intent, int)}
     * which sorts packages by approval priority. A higher numerical value means the package should
     * override all lower values. This means that comparison using less/greater than IS valid.
     * Defines the possible values for
     * {@link #approvalLevelForDomain(PackageSetting, Intent, List, int, int)} which sorts packages
     * by approval priority. A higher numerical value means the package should override all lower
     * values. This means that comparison using less/greater than IS valid.
     *
     * Negative values are possible, although not implemented, reserved if explicit disable of a
     * package for a domain needs to be tracked.
@@ -184,7 +189,7 @@ public interface DomainVerificationManagerInternal {
    /**
     * Migrates verification state from a previous install to a new one. It is expected that the
     * {@link PackageSetting#getDomainSetId()} already be set to the correct value, usually from
     * {@link #generateNewId()}. This will preserve {@link DomainVerificationManager#STATE_SUCCESS}
     * {@link #generateNewId()}. This will preserve {@link DomainVerificationState#STATE_SUCCESS}
     * domains under the assumption that the new package will pass the same server side config as
     * the previous package, as they have matching signatures.
     * <p>
@@ -227,6 +232,11 @@ public interface DomainVerificationManagerInternal {
     */
    void clearPackage(@NonNull String packageName);

    /**
     * Remove all state for the given package for the given user.
     */
    void clearPackageForUser(@NonNull String packageName, @UserIdInt int userId);

    /**
     * Delete all the state for a user. This can be because the user has been removed from the
     * device, or simply that the state for a user should be deleted.
@@ -271,7 +281,7 @@ public interface DomainVerificationManagerInternal {

    /**
     * Until the legacy APIs are entirely removed, returns the legacy state from the previously
     * written info stored in {@link com.android.server.pm.Settings}.
     * written info stored in {@link Settings}.
     */
    int getLegacyState(@NonNull String packageName, @UserIdInt int userId);

@@ -283,15 +293,12 @@ public interface DomainVerificationManagerInternal {
     * @param userId             the specific user to print, or null to skip printing user selection
     *                           states, supports {@link android.os.UserHandle#USER_ALL}
     * @param pkgSettingFunction the method by which to retrieve package data; if this is called
     *                           from {@link com.android.server.pm.PackageManagerService}, it is
     *                           expected to pass in the snapshot of {@link PackageSetting} objects,
     *                           or if null is passed, the manager may decide to lock {@link
     *                           com.android.server.pm.PackageManagerService} through {@link
     *                           Connection#getPackageSettingLocked(String)}
     *                           from {@link PackageManagerService}, it is
     *                           expected to pass in the snapshot of {@link PackageSetting} objects
     */
    void printState(@NonNull IndentingPrintWriter writer, @Nullable String packageName,
            @Nullable @UserIdInt Integer userId,
            @Nullable Function<String, PackageSetting> pkgSettingFunction)
            @NonNull Function<String, PackageSetting> pkgSettingFunction)
            throws NameNotFoundException;

    @NonNull
@@ -363,17 +370,46 @@ public interface DomainVerificationManagerInternal {
         */
        void schedule(int code, @Nullable Object object);

        // TODO(b/178733426): Make DomainVerificationService PMS snapshot aware so it can avoid
        //  locking package state at all. This can be as simple as removing this method in favor of
        //  accepting a PackageSetting function in at every method call, although should probably
        //  be abstracted to a wrapper class.
        @Nullable
        PackageSetting getPackageSettingLocked(@NonNull String pkgName);
        /**
         * Run a function block that requires access to {@link PackageSetting} data. This will
         * ensure the {@link PackageManagerService} is taken before
         * {@link DomainVerificationManagerInternal}'s lock is taken to avoid deadlock.
         */
        void withPackageSettings(@NonNull Consumer<Function<String, PackageSetting>> block);

        @Nullable
        AndroidPackage getPackageLocked(@NonNull String pkgName);
        /**
         * Variant which returns a value to the caller.
         * @see #withPackageSettings(Consumer)
         */
        <Output> Output withPackageSettingsReturning(
                @NonNull FunctionalUtils.ThrowingFunction<Function<String, PackageSetting>, Output>
                        block);

        /**
         * Variant which throws.
         * @see #withPackageSettings(Consumer)
         */
        <ExceptionType extends Exception> void withPackageSettingsThrowing(
                @NonNull ThrowingConsumer<Function<String, PackageSetting>, ExceptionType> block)
                throws ExceptionType;

        /**
         * Variant which returns a value to the caller and throws.
         * @see #withPackageSettings(Consumer)
         */
        <Output, ExceptionType extends Exception> Output withPackageSettingsReturningThrowing(
                @NonNull ThrowingFunction<Function<String, PackageSetting>, Output, ExceptionType>
                        block) throws ExceptionType;

        @UserIdInt
        int[] getAllUserIds();

        interface ThrowingConsumer<Input, ExceptionType extends Exception> {
            void accept(Input input) throws ExceptionType;
        }

        interface ThrowingFunction<Input, Output, ExceptionType extends Exception> {
            Output apply(Input input) throws ExceptionType;
        }
    }
}
+39 −13
Original line number Diff line number Diff line
@@ -18,10 +18,12 @@ package com.android.server.pm.verify.domain;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.Signature;
import android.content.pm.verify.domain.DomainVerificationState;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.PackageUtils;
import android.util.SparseArray;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
@@ -36,6 +38,7 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.Collection;
import java.util.UUID;
import java.util.function.Function;

public class DomainVerificationPersistence {

@@ -49,6 +52,7 @@ public class DomainVerificationPersistence {
    private static final String ATTR_PACKAGE_NAME = "packageName";
    private static final String ATTR_ID = "id";
    private static final String ATTR_HAS_AUTO_VERIFY_DOMAINS = "hasAutoVerifyDomains";
    private static final String ATTR_SIGNATURE = "signature";
    private static final String TAG_USER_STATES = "user-states";

    public static final String TAG_USER_STATE = "user-state";
@@ -62,10 +66,18 @@ public class DomainVerificationPersistence {
    public static final String ATTR_NAME = "name";
    public static final String ATTR_STATE = "state";

    /**
     * @param pkgNameToSignature Converts package name to a string representation of its signature.
     *                           Usually this is the SHA-256 hash from
     *                           {@link PackageUtils#computeSignaturesSha256Digest(Signature[])},
     *                           but can be an arbitrary string for testing purposes. Pass non-null
     *                           to write out signatures, or null to ignore.
     */
    public static void writeToXml(@NonNull TypedXmlSerializer xmlSerializer,
            @NonNull DomainVerificationStateMap<DomainVerificationPkgState> attached,
            @NonNull ArrayMap<String, DomainVerificationPkgState> pending,
            @NonNull ArrayMap<String, DomainVerificationPkgState> restored) throws IOException {
            @NonNull ArrayMap<String, DomainVerificationPkgState> restored,
            @Nullable Function<String, String> pkgNameToSignature) throws IOException {
        try (SettingsXml.Serializer serializer = SettingsXml.serializer(xmlSerializer)) {
            try (SettingsXml.WriteSection ignored = serializer.startSection(
                    TAG_DOMAIN_VERIFICATIONS)) {
@@ -86,25 +98,26 @@ public class DomainVerificationPersistence {
                }

                try (SettingsXml.WriteSection activeSection = serializer.startSection(TAG_ACTIVE)) {
                    writePackageStates(activeSection, active);
                    writePackageStates(activeSection, active, pkgNameToSignature);
                }

                try (SettingsXml.WriteSection restoredSection = serializer.startSection(
                        TAG_RESTORED)) {
                    writePackageStates(restoredSection, restored.values());
                    writePackageStates(restoredSection, restored.values(), pkgNameToSignature);
                }
            }
        }
    }

    private static void writePackageStates(@NonNull SettingsXml.WriteSection section,
            @NonNull Collection<DomainVerificationPkgState> states) throws IOException {
            @NonNull Collection<DomainVerificationPkgState> states,
            @Nullable Function<String, String> pkgNameToSignature) throws IOException {
        if (states.isEmpty()) {
            return;
        }

        for (DomainVerificationPkgState state : states) {
            writePkgStateToXml(section, state);
            writePkgStateToXml(section, state, pkgNameToSignature);
        }
    }

@@ -146,11 +159,12 @@ public class DomainVerificationPersistence {
     * been entered.
     */
    @Nullable
    public static DomainVerificationPkgState createPkgStateFromXml(
    private static DomainVerificationPkgState createPkgStateFromXml(
            @NonNull SettingsXml.ReadSection section) {
        String packageName = section.getString(ATTR_PACKAGE_NAME);
        String idString = section.getString(ATTR_ID);
        boolean hasAutoVerifyDomains = section.getBoolean(ATTR_HAS_AUTO_VERIFY_DOMAINS);
        String signature = section.getString(ATTR_SIGNATURE);
        if (TextUtils.isEmpty(packageName) || TextUtils.isEmpty(idString)) {
            return null;
        }
@@ -172,7 +186,7 @@ public class DomainVerificationPersistence {
        }

        return new DomainVerificationPkgState(packageName, id, hasAutoVerifyDomains, stateMap,
                userStates);
                userStates, signature);
    }

    private static void readUserStates(@NonNull SettingsXml.ReadSection section,
@@ -196,14 +210,26 @@ public class DomainVerificationPersistence {
        }
    }

    public static void writePkgStateToXml(@NonNull SettingsXml.WriteSection parentSection,
            @NonNull DomainVerificationPkgState pkgState) throws IOException {
    private static void writePkgStateToXml(@NonNull SettingsXml.WriteSection parentSection,
            @NonNull DomainVerificationPkgState pkgState,
            @Nullable Function<String, String> pkgNameToSignature) throws IOException {
        String packageName = pkgState.getPackageName();
        String signature = pkgNameToSignature == null
                ? null : pkgNameToSignature.apply(packageName);
        if (signature == null) {
            // If a package isn't available to get its signature, fallback to the previously stored
            // result, which can occur if the package has been marked for restore but hasn't
            // been installed on the new device yet.
            signature = pkgState.getBackupSignatureHash();
        }

        try (SettingsXml.WriteSection ignored =
                     parentSection.startSection(TAG_PACKAGE_STATE)
                             .attribute(ATTR_PACKAGE_NAME, pkgState.getPackageName())
                             .attribute(ATTR_PACKAGE_NAME, packageName)
                             .attribute(ATTR_ID, pkgState.getId().toString())
                             .attribute(ATTR_HAS_AUTO_VERIFY_DOMAINS,
                                     pkgState.isHasAutoVerifyDomains())) {
                                     pkgState.isHasAutoVerifyDomains())
                             .attribute(ATTR_SIGNATURE, signature)) {
            writeStateMap(parentSection, pkgState.getStateMap());
            writeUserStates(parentSection, pkgState.getUserStates());
        }
@@ -245,7 +271,7 @@ public class DomainVerificationPersistence {
     * entered.
     */
    @Nullable
    public static DomainVerificationInternalUserState createUserStateFromXml(
    private static DomainVerificationInternalUserState createUserStateFromXml(
            @NonNull SettingsXml.ReadSection section) {
        int userId = section.getInt(ATTR_USER_ID);
        if (userId == -1) {
@@ -274,7 +300,7 @@ public class DomainVerificationPersistence {
        }
    }

    public static void writeUserStateToXml(@NonNull SettingsXml.WriteSection parentSection,
    private static void writeUserStateToXml(@NonNull SettingsXml.WriteSection parentSection,
            @NonNull DomainVerificationInternalUserState userState) throws IOException {
        try (SettingsXml.WriteSection section =
                     parentSection.startSection(TAG_USER_STATE)
Loading