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

Commit cb5517f3 authored by Winson's avatar Winson Committed by Winson Chiu
Browse files

Update domain verification Settings API

Adjusts the logic for selecting a domain, removing the selection for
other applications once a domain is verified or overridden by another
application being selected.

To this end, exposes a new Domain class with verified/selected booleans
to encapsulate the state, returned in the initial response for the
Settings screen API. This avoids the usage of the
getDomainVerificationSet API, so that can be restricted to only the
domain verification agent in a future change.

Also introduces the concept of a DomainOwner, which represents a single
package who has been granted any positive level of approval to open
a domain.

Bug: 177923646

CTS-Coverage-Bug: 179382047

Test: atest com.android.server.pm.verify.domain
Test: TODO with Settings changes

Change-Id: Ib14049e397154616f84a2264167ac30659cd81c9
parent ad07b851
Loading
Loading
Loading
Loading
+14 −1
Original line number Diff line number Diff line
@@ -2757,6 +2757,15 @@ package android.content.pm.permission {
package android.content.pm.verify.domain {
  public final class DomainOwner implements android.os.Parcelable {
    ctor public DomainOwner(@NonNull String, boolean);
    method public int describeContents();
    method @NonNull public String getPackageName();
    method public boolean isOverrideable();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.verify.domain.DomainOwner> CREATOR;
  }
  public final class DomainVerificationInfo implements android.os.Parcelable {
    method public int describeContents();
    method @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getHostToStateMap();
@@ -2769,6 +2778,7 @@ package android.content.pm.verify.domain {
  public interface DomainVerificationManager {
    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.DOMAIN_VERIFICATION_AGENT, android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION}) public android.content.pm.verify.domain.DomainVerificationInfo getDomainVerificationInfo(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
    method @Nullable @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION) public android.content.pm.verify.domain.DomainVerificationUserSelection getDomainVerificationUserSelection(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
    method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION) public java.util.List<android.content.pm.verify.domain.DomainOwner> getOwnersForDomain(@NonNull String);
    method @NonNull @RequiresPermission(android.Manifest.permission.DOMAIN_VERIFICATION_AGENT) public java.util.List<java.lang.String> getValidVerificationPackageNames();
    method public static boolean isStateModifiable(int);
    method public static boolean isStateVerified(int);
@@ -2790,13 +2800,16 @@ package android.content.pm.verify.domain {
  public final class DomainVerificationUserSelection implements android.os.Parcelable {
    method public int describeContents();
    method @NonNull public java.util.Map<java.lang.String,java.lang.Boolean> getHostToUserSelectionMap();
    method @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getHostToStateMap();
    method @NonNull public java.util.UUID getIdentifier();
    method @NonNull public String getPackageName();
    method @NonNull public android.os.UserHandle getUser();
    method @NonNull public boolean isLinkHandlingAllowed();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.verify.domain.DomainVerificationUserSelection> CREATOR;
    field public static final int DOMAIN_STATE_NONE = 0; // 0x0
    field public static final int DOMAIN_STATE_SELECTED = 1; // 0x1
    field public static final int DOMAIN_STATE_VERIFIED = 2; // 0x2
  }
}
+19 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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 android.content.pm.verify.domain;

parcelable DomainOwner;
+219 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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 android.content.pm.verify.domain;

import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Parcelable;

import com.android.internal.util.DataClass;

import java.util.Set;
import java.util.UUID;

/**
 * @hide
 */
@SystemApi
@DataClass(genParcelable = true, genEqualsHashCode = true, genAidl = true, genToString = true)
public final class DomainOwner implements Parcelable {

    /**
     * Package name of that owns the domain.
     */
    @NonNull
    private final String mPackageName;

    /**
     * Whether or not this owner can be automatically overridden.
     *
     * @see DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set, boolean)
     */
    private final boolean mOverrideable;



    // Code below generated by codegen v1.0.22.
    //
    // DO NOT MODIFY!
    // CHECKSTYLE:OFF Generated code
    //
    // To regenerate run:
    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain/DomainOwner.java
    //
    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
    //   Settings > Editor > Code Style > Formatter Control
    //@formatter:off


    /**
     * Creates a new DomainOwner.
     *
     * @param packageName
     *   Package name of that owns the domain.
     * @param overrideable
     *   Whether or not this owner can be automatically overridden. If all owners for a domain are
     *   overrideable, then calling
     *   {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID,
     *   Set, boolean)} to enable the domain will disable all other owners. On the other hand, if any
     *   of the owners are non-overrideable, then
     *   {@link DomainVerificationManager#setDomainVerificationLinkHandlingAllowed(String,
     *   boolean)} must be called with false to disable all of the other owners before this domain can
     *   be taken by a new owner through
     *   {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID,
     *   Set, boolean)}.
     */
    @DataClass.Generated.Member
    public DomainOwner(
            @NonNull String packageName,
            boolean overrideable) {
        this.mPackageName = packageName;
        com.android.internal.util.AnnotationValidations.validate(
                NonNull.class, null, mPackageName);
        this.mOverrideable = overrideable;

        // onConstructed(); // You can define this method to get a callback
    }

    /**
     * Package name of that owns the domain.
     */
    @DataClass.Generated.Member
    public @NonNull String getPackageName() {
        return mPackageName;
    }

    /**
     * Whether or not this owner can be automatically overridden. If all owners for a domain are
     * overrideable, then calling
     * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID,
     * Set, boolean)} to enable the domain will disable all other owners. On the other hand, if any
     * of the owners are non-overrideable, then
     * {@link DomainVerificationManager#setDomainVerificationLinkHandlingAllowed(String,
     * boolean)} must be called with false to disable all of the other owners before this domain can
     * be taken by a new owner through
     * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID,
     * Set, boolean)}.
     */
    @DataClass.Generated.Member
    public boolean isOverrideable() {
        return mOverrideable;
    }

    @Override
    @DataClass.Generated.Member
    public String toString() {
        // You can override field toString logic by defining methods like:
        // String fieldNameToString() { ... }

        return "DomainOwner { " +
                "packageName = " + mPackageName + ", " +
                "overrideable = " + mOverrideable +
        " }";
    }

    @Override
    @DataClass.Generated.Member
    public boolean equals(@android.annotation.Nullable Object o) {
        // You can override field equality logic by defining either of the methods like:
        // boolean fieldNameEquals(DomainOwner other) { ... }
        // boolean fieldNameEquals(FieldType otherValue) { ... }

        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        @SuppressWarnings("unchecked")
        DomainOwner that = (DomainOwner) o;
        //noinspection PointlessBooleanExpression
        return true
                && java.util.Objects.equals(mPackageName, that.mPackageName)
                && mOverrideable == that.mOverrideable;
    }

    @Override
    @DataClass.Generated.Member
    public int hashCode() {
        // You can override field hashCode logic by defining methods like:
        // int fieldNameHashCode() { ... }

        int _hash = 1;
        _hash = 31 * _hash + java.util.Objects.hashCode(mPackageName);
        _hash = 31 * _hash + Boolean.hashCode(mOverrideable);
        return _hash;
    }

    @Override
    @DataClass.Generated.Member
    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
        // You can override field parcelling by defining methods like:
        // void parcelFieldName(Parcel dest, int flags) { ... }

        byte flg = 0;
        if (mOverrideable) flg |= 0x2;
        dest.writeByte(flg);
        dest.writeString(mPackageName);
    }

    @Override
    @DataClass.Generated.Member
    public int describeContents() { return 0; }

    /** @hide */
    @SuppressWarnings({"unchecked", "RedundantCast"})
    @DataClass.Generated.Member
    /* package-private */ DomainOwner(@NonNull android.os.Parcel in) {
        // You can override field unparcelling by defining methods like:
        // static FieldType unparcelFieldName(Parcel in) { ... }

        byte flg = in.readByte();
        boolean overrideable = (flg & 0x2) != 0;
        String packageName = in.readString();

        this.mPackageName = packageName;
        com.android.internal.util.AnnotationValidations.validate(
                NonNull.class, null, mPackageName);
        this.mOverrideable = overrideable;

        // onConstructed(); // You can define this method to get a callback
    }

    @DataClass.Generated.Member
    public static final @NonNull Parcelable.Creator<DomainOwner> CREATOR
            = new Parcelable.Creator<DomainOwner>() {
        @Override
        public DomainOwner[] newArray(int size) {
            return new DomainOwner[size];
        }

        @Override
        public DomainOwner createFromParcel(@NonNull android.os.Parcel in) {
            return new DomainOwner(in);
        }
    };

    @DataClass.Generated(
            time = 1614119379978L,
            codegenVersion = "1.0.22",
            sourceFile = "frameworks/base/core/java/android/content/pm/verify/domain/DomainOwner.java",
            inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final  boolean mOverrideable\nclass DomainOwner extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genEqualsHashCode=true, genAidl=true, genToString=true)")
    @Deprecated
    private void __metadata() {}


    //@formatter:on
    // End of generated code

}
+22 −1
Original line number Diff line number Diff line
@@ -239,7 +239,15 @@ public interface DomainVerificationManager {
     * {@link Context#createPackageContextAsUser(String, int, UserHandle)} should be used.
     *
     * Enabling an unverified domain will allow an application to open it, but this can only occur
     * if no other app on the device is approved for the domain.
     * if no other app on the device is approved for a higher approval level. This can queried
     * using {@link #getOwnersForDomain(String)}.
     *
     * If all owners for a domain are {@link DomainOwner#isOverrideable()}, then calling this to
     * enable that domain will disable all other owners.
     *
     * On the other hand, if any of the owners are non-overrideable, then this must be called with
     * false for all of the other owners to disable them before the domain can be taken by a new
     * owner.
     *
     * @param domainSetId See {@link DomainVerificationInfo#getIdentifier()}.
     * @param domains     The domains to toggle the state of.
@@ -275,6 +283,19 @@ public interface DomainVerificationManager {
    DomainVerificationUserSelection getDomainVerificationUserSelection(@NonNull String packageName)
            throws NameNotFoundException;

    /**
     * For the given domain, return all apps which are approved to open it in a
     * greater than 0 priority. This does not mean that all apps can actually open
     * an Intent with that domain. That will be decided by the set of apps which
     * are the highest priority level, ignoring all lower priority levels.
     *
     * By default the list will be returned ordered from lowest to highest
     * priority.
     */
    @NonNull
    @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION)
    List<DomainOwner> getOwnersForDomain(@NonNull String domain);

    /**
     * Thrown if a {@link DomainVerificationInfo#getIdentifier()}} or an associated set of domains
     * provided by the caller is no longer valid. This may be recoverable, and the caller should
+10 −2
Original line number Diff line number Diff line
@@ -21,11 +21,9 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.verify.domain.IDomainVerificationManager;
import android.os.RemoteException;
import android.os.ServiceSpecificException;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
@@ -158,6 +156,16 @@ public class DomainVerificationManagerImpl implements DomainVerificationManager
        }
    }

    @NonNull
    @Override
    public List<DomainOwner> getOwnersForDomain(@NonNull String domain) {
        try {
            return mDomainVerificationManager.getOwnersForDomain(domain, mContext.getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    private Exception rethrow(Exception exception, @Nullable UUID domainSetId) {
        return rethrow(exception, domainSetId, null);
    }
Loading