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

Commit 5ef56ddb authored by Evan Chen's avatar Evan Chen Committed by Automerger Merge Worker
Browse files

Merge "Allow skipping CDM dialog for same-oem" into sc-dev am: ad6ef1c7 am: cbcb4a66

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/13809078

Change-Id: I310c779c8334e3286d6d8d593150ade8f636cd63
parents d0c6f767 cbcb4a66
Loading
Loading
Loading
Loading
+45 −6
Original line number Original line Diff line number Diff line
@@ -123,6 +123,15 @@ public final class AssociationRequest implements Parcelable {
     */
     */
    private long mCreationTime;
    private long mCreationTime;


    /**
     * Whether the user-prompt may be skipped once the device is found.
     *
     * Populated by the system.
     *
     * @hide
     */
    private boolean mSkipPrompt = false;

    private void onConstructed() {
    private void onConstructed() {
        mCreationTime = System.currentTimeMillis();
        mCreationTime = System.currentTimeMillis();
    }
    }
@@ -137,6 +146,11 @@ public final class AssociationRequest implements Parcelable {
        mDeviceProfilePrivilegesDescription = desc;
        mDeviceProfilePrivilegesDescription = desc;
    }
    }


    /** @hide */
    public void setSkipPrompt(boolean value) {
        mSkipPrompt = true;
    }

    /** @hide */
    /** @hide */
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public boolean isSingleDevice() {
    public boolean isSingleDevice() {
@@ -207,13 +221,14 @@ public final class AssociationRequest implements Parcelable {
            markUsed();
            markUsed();
            return new AssociationRequest(
            return new AssociationRequest(
                    mSingleDevice, emptyIfNull(mDeviceFilters),
                    mSingleDevice, emptyIfNull(mDeviceFilters),
                    mDeviceProfile, null, null, -1L);
                    mDeviceProfile, null, null, -1L, false);
        }
        }
    }
    }









    // Code below generated by codegen v1.0.22.
    // Code below generated by codegen v1.0.22.
    //
    //
    // DO NOT MODIFY!
    // DO NOT MODIFY!
@@ -250,6 +265,10 @@ public final class AssociationRequest implements Parcelable {
     *   Populated by the system.
     *   Populated by the system.
     * @param creationTime
     * @param creationTime
     *   The time at which his request was created
     *   The time at which his request was created
     * @param skipPrompt
     *   Whether the user-prompt may be skipped once the device is found.
     *
     *   Populated by the system.
     * @hide
     * @hide
     */
     */
    @DataClass.Generated.Member
    @DataClass.Generated.Member
@@ -259,7 +278,8 @@ public final class AssociationRequest implements Parcelable {
            @Nullable @DeviceProfile String deviceProfile,
            @Nullable @DeviceProfile String deviceProfile,
            @Nullable String callingPackage,
            @Nullable String callingPackage,
            @Nullable String deviceProfilePrivilegesDescription,
            @Nullable String deviceProfilePrivilegesDescription,
            long creationTime) {
            long creationTime,
            boolean skipPrompt) {
        this.mSingleDevice = singleDevice;
        this.mSingleDevice = singleDevice;
        this.mDeviceFilters = deviceFilters;
        this.mDeviceFilters = deviceFilters;
        com.android.internal.util.AnnotationValidations.validate(
        com.android.internal.util.AnnotationValidations.validate(
@@ -270,6 +290,7 @@ public final class AssociationRequest implements Parcelable {
        this.mCallingPackage = callingPackage;
        this.mCallingPackage = callingPackage;
        this.mDeviceProfilePrivilegesDescription = deviceProfilePrivilegesDescription;
        this.mDeviceProfilePrivilegesDescription = deviceProfilePrivilegesDescription;
        this.mCreationTime = creationTime;
        this.mCreationTime = creationTime;
        this.mSkipPrompt = skipPrompt;


        onConstructed();
        onConstructed();
    }
    }
@@ -318,6 +339,18 @@ public final class AssociationRequest implements Parcelable {
        return mCreationTime;
        return mCreationTime;
    }
    }


    /**
     * Whether the user-prompt may be skipped once the device is found.
     *
     * Populated by the system.
     *
     * @hide
     */
    @DataClass.Generated.Member
    public boolean isSkipPrompt() {
        return mSkipPrompt;
    }

    @Override
    @Override
    @DataClass.Generated.Member
    @DataClass.Generated.Member
    public String toString() {
    public String toString() {
@@ -330,7 +363,8 @@ public final class AssociationRequest implements Parcelable {
                "deviceProfile = " + mDeviceProfile + ", " +
                "deviceProfile = " + mDeviceProfile + ", " +
                "callingPackage = " + mCallingPackage + ", " +
                "callingPackage = " + mCallingPackage + ", " +
                "deviceProfilePrivilegesDescription = " + mDeviceProfilePrivilegesDescription + ", " +
                "deviceProfilePrivilegesDescription = " + mDeviceProfilePrivilegesDescription + ", " +
                "creationTime = " + mCreationTime +
                "creationTime = " + mCreationTime + ", " +
                "skipPrompt = " + mSkipPrompt +
        " }";
        " }";
    }
    }


@@ -352,7 +386,8 @@ public final class AssociationRequest implements Parcelable {
                && Objects.equals(mDeviceProfile, that.mDeviceProfile)
                && Objects.equals(mDeviceProfile, that.mDeviceProfile)
                && Objects.equals(mCallingPackage, that.mCallingPackage)
                && Objects.equals(mCallingPackage, that.mCallingPackage)
                && Objects.equals(mDeviceProfilePrivilegesDescription, that.mDeviceProfilePrivilegesDescription)
                && Objects.equals(mDeviceProfilePrivilegesDescription, that.mDeviceProfilePrivilegesDescription)
                && mCreationTime == that.mCreationTime;
                && mCreationTime == that.mCreationTime
                && mSkipPrompt == that.mSkipPrompt;
    }
    }


    @Override
    @Override
@@ -368,6 +403,7 @@ public final class AssociationRequest implements Parcelable {
        _hash = 31 * _hash + Objects.hashCode(mCallingPackage);
        _hash = 31 * _hash + Objects.hashCode(mCallingPackage);
        _hash = 31 * _hash + Objects.hashCode(mDeviceProfilePrivilegesDescription);
        _hash = 31 * _hash + Objects.hashCode(mDeviceProfilePrivilegesDescription);
        _hash = 31 * _hash + Long.hashCode(mCreationTime);
        _hash = 31 * _hash + Long.hashCode(mCreationTime);
        _hash = 31 * _hash + Boolean.hashCode(mSkipPrompt);
        return _hash;
        return _hash;
    }
    }


@@ -379,6 +415,7 @@ public final class AssociationRequest implements Parcelable {


        byte flg = 0;
        byte flg = 0;
        if (mSingleDevice) flg |= 0x1;
        if (mSingleDevice) flg |= 0x1;
        if (mSkipPrompt) flg |= 0x40;
        if (mDeviceProfile != null) flg |= 0x4;
        if (mDeviceProfile != null) flg |= 0x4;
        if (mCallingPackage != null) flg |= 0x8;
        if (mCallingPackage != null) flg |= 0x8;
        if (mDeviceProfilePrivilegesDescription != null) flg |= 0x10;
        if (mDeviceProfilePrivilegesDescription != null) flg |= 0x10;
@@ -403,6 +440,7 @@ public final class AssociationRequest implements Parcelable {


        byte flg = in.readByte();
        byte flg = in.readByte();
        boolean singleDevice = (flg & 0x1) != 0;
        boolean singleDevice = (flg & 0x1) != 0;
        boolean skipPrompt = (flg & 0x40) != 0;
        List<DeviceFilter<?>> deviceFilters = new ArrayList<>();
        List<DeviceFilter<?>> deviceFilters = new ArrayList<>();
        in.readParcelableList(deviceFilters, DeviceFilter.class.getClassLoader());
        in.readParcelableList(deviceFilters, DeviceFilter.class.getClassLoader());
        String deviceProfile = (flg & 0x4) == 0 ? null : in.readString();
        String deviceProfile = (flg & 0x4) == 0 ? null : in.readString();
@@ -420,6 +458,7 @@ public final class AssociationRequest implements Parcelable {
        this.mCallingPackage = callingPackage;
        this.mCallingPackage = callingPackage;
        this.mDeviceProfilePrivilegesDescription = deviceProfilePrivilegesDescription;
        this.mDeviceProfilePrivilegesDescription = deviceProfilePrivilegesDescription;
        this.mCreationTime = creationTime;
        this.mCreationTime = creationTime;
        this.mSkipPrompt = skipPrompt;


        onConstructed();
        onConstructed();
    }
    }
@@ -439,10 +478,10 @@ public final class AssociationRequest implements Parcelable {
    };
    };


    @DataClass.Generated(
    @DataClass.Generated(
            time = 1614976943652L,
            time = 1615252862756L,
            codegenVersion = "1.0.22",
            codegenVersion = "1.0.22",
            sourceFile = "frameworks/base/core/java/android/companion/AssociationRequest.java",
            sourceFile = "frameworks/base/core/java/android/companion/AssociationRequest.java",
            inputSignatures = "private static final  java.lang.String LOG_TAG\npublic static final  java.lang.String DEVICE_PROFILE_WATCH\nprivate  boolean mSingleDevice\nprivate @com.android.internal.util.DataClass.PluralOf(\"deviceFilter\") @android.annotation.NonNull java.util.List<android.companion.DeviceFilter<?>> mDeviceFilters\nprivate @android.annotation.Nullable @android.companion.AssociationRequest.DeviceProfile java.lang.String mDeviceProfile\nprivate @android.annotation.Nullable java.lang.String mCallingPackage\nprivate @android.annotation.Nullable java.lang.String mDeviceProfilePrivilegesDescription\nprivate  long mCreationTime\nprivate  void onConstructed()\npublic  void setCallingPackage(java.lang.String)\npublic  void setDeviceProfilePrivilegesDescription(java.lang.String)\npublic @android.compat.annotation.UnsupportedAppUsage boolean isSingleDevice()\npublic @android.annotation.NonNull @android.compat.annotation.UnsupportedAppUsage java.util.List<android.companion.DeviceFilter<?>> getDeviceFilters()\nclass AssociationRequest extends java.lang.Object implements [android.os.Parcelable]\nprivate  boolean mSingleDevice\nprivate @android.annotation.Nullable java.util.ArrayList<android.companion.DeviceFilter<?>> mDeviceFilters\nprivate @android.annotation.Nullable java.lang.String mDeviceProfile\npublic @android.annotation.NonNull android.companion.AssociationRequest.Builder setSingleDevice(boolean)\npublic @android.annotation.NonNull android.companion.AssociationRequest.Builder addDeviceFilter(android.companion.DeviceFilter<?>)\npublic @android.annotation.NonNull android.companion.AssociationRequest.Builder setDeviceProfile(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override android.companion.AssociationRequest build()\nclass Builder extends android.provider.OneTimeUseBuilder<android.companion.AssociationRequest> implements []\n@com.android.internal.util.DataClass(genToString=true, genEqualsHashCode=true, genHiddenGetters=true, genParcelable=true, genHiddenConstructor=true, genBuilder=false)")
            inputSignatures = "private static final  java.lang.String LOG_TAG\npublic static final  java.lang.String DEVICE_PROFILE_WATCH\nprivate  boolean mSingleDevice\nprivate @com.android.internal.util.DataClass.PluralOf(\"deviceFilter\") @android.annotation.NonNull java.util.List<android.companion.DeviceFilter<?>> mDeviceFilters\nprivate @android.annotation.Nullable @android.companion.AssociationRequest.DeviceProfile java.lang.String mDeviceProfile\nprivate @android.annotation.Nullable java.lang.String mCallingPackage\nprivate @android.annotation.Nullable java.lang.String mDeviceProfilePrivilegesDescription\nprivate  long mCreationTime\nprivate  boolean mSkipPrompt\nprivate  void onConstructed()\npublic  void setCallingPackage(java.lang.String)\npublic  void setDeviceProfilePrivilegesDescription(java.lang.String)\npublic  void setSkipPrompt(boolean)\npublic @android.compat.annotation.UnsupportedAppUsage boolean isSingleDevice()\npublic @android.annotation.NonNull @android.compat.annotation.UnsupportedAppUsage java.util.List<android.companion.DeviceFilter<?>> getDeviceFilters()\nclass AssociationRequest extends java.lang.Object implements [android.os.Parcelable]\nprivate  boolean mSingleDevice\nprivate @android.annotation.Nullable java.util.ArrayList<android.companion.DeviceFilter<?>> mDeviceFilters\nprivate @android.annotation.Nullable java.lang.String mDeviceProfile\npublic @android.annotation.NonNull android.companion.AssociationRequest.Builder setSingleDevice(boolean)\npublic @android.annotation.NonNull android.companion.AssociationRequest.Builder addDeviceFilter(android.companion.DeviceFilter<?>)\npublic @android.annotation.NonNull android.companion.AssociationRequest.Builder setDeviceProfile(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override android.companion.AssociationRequest build()\nclass Builder extends android.provider.OneTimeUseBuilder<android.companion.AssociationRequest> implements []\n@com.android.internal.util.DataClass(genToString=true, genEqualsHashCode=true, genHiddenGetters=true, genParcelable=true, genHiddenConstructor=true, genBuilder=false)")
    @Deprecated
    @Deprecated
    private void __metadata() {}
    private void __metadata() {}


+17 −0
Original line number Original line Diff line number Diff line
@@ -3774,6 +3774,23 @@
    -->
    -->
    <string name="config_companionDeviceManagerPackage" translatable="false"></string>
    <string name="config_companionDeviceManagerPackage" translatable="false"></string>


    <!-- A list of packages managing companion device(s) by the same manufacturers as the main
         device. It will fall back to showing a prompt if the association has been called multiple
         times in a short period.
         Note that config_companionDeviceManagerPackage and config_companionDeviceCerts are
         parallel arrays.
     -->
    <string-array name="config_companionDevicePackages" translatable="false"></string-array>

    <!-- A list of SHA256 Certificates managing companion device(s) by the same manufacturers as
         the main device. It will fall back to showing a prompt if the association has been called
         multiple times in a short period.
         Note that config_companionDeviceCerts and config_companionDeviceManagerPackage are parallel
         arrays.
         Example: "1A:2B:3C:4D"
     -->
    <string-array name="config_companionDeviceCerts" translatable="false"></string-array>

    <!-- The package name for the default wellbeing app.
    <!-- The package name for the default wellbeing app.
         This package must be trusted, as it has the permissions to control other applications
         This package must be trusted, as it has the permissions to control other applications
         on the device.
         on the device.
+2 −0
Original line number Original line Diff line number Diff line
@@ -692,6 +692,8 @@
  <java-symbol type="string" name="cfTemplateRegisteredTime" />
  <java-symbol type="string" name="cfTemplateRegisteredTime" />
  <java-symbol type="string" name="chooseActivity" />
  <java-symbol type="string" name="chooseActivity" />
  <java-symbol type="string" name="checked" />
  <java-symbol type="string" name="checked" />
  <java-symbol type="array" name="config_companionDevicePackages" />
  <java-symbol type="array" name="config_companionDeviceCerts" />
  <java-symbol type="string" name="config_default_dns_server" />
  <java-symbol type="string" name="config_default_dns_server" />
  <java-symbol type="string" name="config_ethernet_iface_regex" />
  <java-symbol type="string" name="config_ethernet_iface_regex" />
  <java-symbol type="string" name="not_checked" />
  <java-symbol type="string" name="not_checked" />
+3 −0
Original line number Original line Diff line number Diff line
@@ -100,6 +100,9 @@ public class CompanionDeviceActivity extends Activity {
            mPairButton.setOnClickListener(v -> onDeviceConfirmed(getService().mSelectedDevice));
            mPairButton.setOnClickListener(v -> onDeviceConfirmed(getService().mSelectedDevice));
            getService().mSelectedDevice = selectedDevice;
            getService().mSelectedDevice = selectedDevice;
            onSelectionUpdate();
            onSelectionUpdate();
            if (getRequest().isSkipPrompt()) {
                onDeviceConfirmed(selectedDevice);
            }
        } else {
        } else {
            setContentView(R.layout.device_chooser);
            setContentView(R.layout.device_chooser);
            mPairButton = findViewById(R.id.button_pair);
            mPairButton = findViewById(R.id.button_pair);
+81 −2
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.bluetooth.le.ScanSettings.CALLBACK_TYPE_ALL_MATCHES;
import static android.bluetooth.le.ScanSettings.SCAN_MODE_BALANCED;
import static android.bluetooth.le.ScanSettings.SCAN_MODE_BALANCED;
import static android.content.Context.BIND_IMPORTANT;
import static android.content.Context.BIND_IMPORTANT;
import static android.content.pm.PackageManager.MATCH_ALL;
import static android.content.pm.PackageManager.MATCH_ALL;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;


import static com.android.internal.util.CollectionUtils.any;
import static com.android.internal.util.CollectionUtils.any;
import static com.android.internal.util.CollectionUtils.emptyIfNull;
import static com.android.internal.util.CollectionUtils.emptyIfNull;
@@ -75,6 +76,7 @@ import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
import android.content.pm.UserInfo;
import android.content.pm.UserInfo;
import android.net.NetworkPolicyManager;
import android.net.NetworkPolicyManager;
import android.os.Binder;
import android.os.Binder;
@@ -101,6 +103,7 @@ import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.AtomicFile;
import android.util.ExceptionUtils;
import android.util.ExceptionUtils;
import android.util.Log;
import android.util.Log;
import android.util.PackageUtils;
import android.util.Slog;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseArray;
import android.util.Xml;
import android.util.Xml;
@@ -134,8 +137,10 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Collections;
import java.util.Date;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.List;
import java.util.Objects;
import java.util.Objects;
import java.util.Set;
import java.util.Set;
@@ -164,6 +169,9 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
    private static final String PREF_FILE_NAME = "companion_device_preferences.xml";
    private static final String PREF_FILE_NAME = "companion_device_preferences.xml";
    private static final String PREF_KEY_AUTO_REVOKE_GRANTS_DONE = "auto_revoke_grants_done";
    private static final String PREF_KEY_AUTO_REVOKE_GRANTS_DONE = "auto_revoke_grants_done";


    private static final int ASSOCIATE_WITHOUT_PROMPT_MAX_PER_TIME_WINDOW = 5;
    private static final long ASSOCIATE_WITHOUT_PROMPT_WINDOW_MS = 60 * 60 * 1000; // 60 min;

    private static final String XML_TAG_ASSOCIATIONS = "associations";
    private static final String XML_TAG_ASSOCIATIONS = "associations";
    private static final String XML_TAG_ASSOCIATION = "association";
    private static final String XML_TAG_ASSOCIATION = "association";
    private static final String XML_ATTR_PACKAGE = "package";
    private static final String XML_ATTR_PACKAGE = "package";
@@ -418,6 +426,11 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
            mRequest = request;
            mRequest = request;
            mCallingPackage = callingPackage;
            mCallingPackage = callingPackage;
            request.setCallingPackage(callingPackage);
            request.setCallingPackage(callingPackage);

            if (mayAssociateWithoutPrompt(callingPackage, userId)) {
                Slog.i(LOG_TAG, "setSkipPrompt(true)");
                request.setSkipPrompt(true);
            }
            callback.asBinder().linkToDeath(CompanionDeviceManagerService.this /* recipient */, 0);
            callback.asBinder().linkToDeath(CompanionDeviceManagerService.this /* recipient */, 0);


            AndroidFuture<String> fetchProfileDescription =
            AndroidFuture<String> fetchProfileDescription =
@@ -503,7 +516,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
        private boolean callerCanManageCompanionDevices() {
        private boolean callerCanManageCompanionDevices() {
            return getContext().checkCallingOrSelfPermission(
            return getContext().checkCallingOrSelfPermission(
                    android.Manifest.permission.MANAGE_COMPANION_DEVICES)
                    android.Manifest.permission.MANAGE_COMPANION_DEVICES)
                    == PackageManager.PERMISSION_GRANTED;
                    == PERMISSION_GRANTED;
        }
        }


        private void checkCallerIsSystemOr(String pkg) throws RemoteException {
        private void checkCallerIsSystemOr(String pkg) throws RemoteException {
@@ -583,7 +596,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind


            boolean bypassMacPermission = getContext().getPackageManager().checkPermission(
            boolean bypassMacPermission = getContext().getPackageManager().checkPermission(
                    android.Manifest.permission.COMPANION_APPROVE_WIFI_CONNECTIONS, packageName)
                    android.Manifest.permission.COMPANION_APPROVE_WIFI_CONNECTIONS, packageName)
                    == PackageManager.PERMISSION_GRANTED;
                    == PERMISSION_GRANTED;
            if (bypassMacPermission) {
            if (bypassMacPermission) {
                return true;
                return true;
            }
            }
@@ -844,6 +857,72 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
        }
        }
    }
    }


    private Set<String> getSameOemPackageCerts(
            String packageName, String[] oemPackages, String[] sameOemCerts) {
        Set<String> sameOemPackageCerts = new HashSet<>();

        // Assume OEM may enter same package name in the parallel string array with
        // multiple ADK certs corresponding to it
        for (int i = 0; i < oemPackages.length; i++) {
            if (oemPackages[i].equals(packageName)) {
                sameOemPackageCerts.add(sameOemCerts[i].replaceAll(":", ""));
            }
        }

        return sameOemPackageCerts;
    }

    boolean mayAssociateWithoutPrompt(String packageName, int userId) {
        String[] sameOemPackages = getContext()
                .getResources()
                .getStringArray(com.android.internal.R.array.config_companionDevicePackages);
        if (!ArrayUtils.contains(sameOemPackages, packageName)) {
            Slog.w(LOG_TAG, packageName
                    + " can not silently create associations due to no package found."
                    + " Packages from OEM: " + Arrays.toString(sameOemPackages)
            );
            return false;
        }

        // Throttle frequent associations
        long now = System.currentTimeMillis();
        Set<Association> recentAssociations = filter(
                getAllAssociations(userId, packageName),
                a -> now - a.getTimeApprovedMs() < ASSOCIATE_WITHOUT_PROMPT_WINDOW_MS);

        if (recentAssociations.size() >= ASSOCIATE_WITHOUT_PROMPT_MAX_PER_TIME_WINDOW) {
            Slog.w(LOG_TAG, "Too many associations. " + packageName
                    + " already associated " + recentAssociations.size()
                    + " devices within the last " + ASSOCIATE_WITHOUT_PROMPT_WINDOW_MS
                    + "ms: " + recentAssociations);
            return false;
        }
        String[] sameOemCerts = getContext()
                .getResources()
                .getStringArray(com.android.internal.R.array.config_companionDeviceCerts);

        Signature[] signatures = mPackageManagerInternal
                .getPackage(packageName).getSigningDetails().signatures;
        String[] apkCerts = PackageUtils.computeSignaturesSha256Digests(signatures);

        Set<String> sameOemPackageCerts =
                getSameOemPackageCerts(packageName, sameOemPackages, sameOemCerts);

        for (String cert : apkCerts) {
            if (sameOemPackageCerts.contains(cert)) {
                return true;
            }
        }

        Slog.w(LOG_TAG, packageName
                + " can not silently create associations. " + packageName
                + " has SHA256 certs from APK: " + Arrays.toString(apkCerts)
                + " and from OEM: " + Arrays.toString(sameOemCerts)
        );

        return false;
    }

    private static <T> boolean containsEither(T[] array, T a, T b) {
    private static <T> boolean containsEither(T[] array, T a, T b) {
        return ArrayUtils.contains(array, a) || ArrayUtils.contains(array, b);
        return ArrayUtils.contains(array, a) || ArrayUtils.contains(array, b);
    }
    }