11fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy/* 21fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * Copyright (C) 2017 The Android Open Source Project 31fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * 41fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * Licensed under the Apache License, Version 2.0 (the "License"); 51fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * you may not use this file except in compliance with the License. 61fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * You may obtain a copy of the License at 71fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * 81fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * http://www.apache.org/licenses/LICENSE-2.0 91fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * 101fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * Unless required by applicable law or agreed to in writing, software 111fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * distributed under the License is distributed on an "AS IS" BASIS, 121fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * See the License for the specific language governing permissions and 141fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * limitations under the License. 151fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy */ 161fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy 171fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedypackage android.content.pm; 181fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy 191fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedyimport android.annotation.NonNull; 201fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedyimport android.annotation.Nullable; 211fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedyimport android.annotation.SystemApi; 22577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumannimport android.content.Intent; 23709ee1551db935adb2026fae9dd799e60f784499Patrick Baumannimport android.os.Bundle; 241fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedyimport android.os.Parcel; 251fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedyimport android.os.Parcelable; 261fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy 271fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedyimport java.security.MessageDigest; 281fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedyimport java.security.NoSuchAlgorithmException; 294db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumannimport java.security.SecureRandom; 301fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedyimport java.util.ArrayList; 314db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumannimport java.util.Arrays; 32577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumannimport java.util.Collections; 331fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedyimport java.util.List; 341fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedyimport java.util.Locale; 354db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumannimport java.util.Random; 361fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy 371fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy/** 38577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann * Describes an externally resolvable instant application. There are three states that this class 39577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann * can represent: <p/> 40577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann * <ul> 41577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann * <li> 42577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann * The first, usable only for non http/s intents, implies that the resolver cannot 43577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann * immediately resolve this intent and would prefer that resolution be deferred to the 44577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann * instant app installer. Represent this state with {@link #InstantAppResolveInfo(Bundle)}. 45577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann * If the {@link android.content.Intent} has the scheme set to http/s and a set of digest 46577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann * prefixes were passed into one of the resolve methods in 47577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann * {@link android.app.InstantAppResolverService}, this state cannot be used. 48577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann * </li> 49577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann * <li> 50577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann * The second represents a partial match and is constructed with any of the other 51577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann * constructors. By setting one or more of the {@link Nullable}arguments to null, you 52577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann * communicate to the resolver in response to 53577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann * {@link android.app.InstantAppResolverService#onGetInstantAppResolveInfo(Intent, int[], 54577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann * String, InstantAppResolverService.InstantAppResolutionCallback)} 55577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann * that you need a 2nd round of resolution to complete the request. 56577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann * </li> 57577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann * <li> 58577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann * The third represents a complete match and is constructed with all @Nullable parameters 59577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann * populated. 60577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann * </li> 61577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann * </ul> 621fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * @hide 631fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy */ 641fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy@SystemApi 651fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedypublic final class InstantAppResolveInfo implements Parcelable { 661fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy /** Algorithm that will be used to generate the domain digest */ 67877e979b108f4fde20c73035c125a445e5b23269Todd Kennedy private static final String SHA_ALGORITHM = "SHA-256"; 681fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy 69577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann private static final byte[] EMPTY_DIGEST = new byte[0]; 70577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann 711fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy private final InstantAppDigest mDigest; 721fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy private final String mPackageName; 731fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy /** The filters used to match domain */ 741fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy private final List<InstantAppIntentFilter> mFilters; 751fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy /** The version code of the app that this class resolves to */ 763accca05ddcad9d0b1b313eae49f273e39121d3cDianne Hackborn private final long mVersionCode; 77709ee1551db935adb2026fae9dd799e60f784499Patrick Baumann /** Data about the app that should be passed along to the Instant App installer on resolve */ 78709ee1551db935adb2026fae9dd799e60f784499Patrick Baumann private final Bundle mExtras; 79577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann /** 80577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann * A flag that indicates that the resolver is aware that an app may match, but would prefer 813abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann * that the installer get the sanitized intent to decide. 82577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann */ 83577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann private final boolean mShouldLetInstallerDecide; 841fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy 85577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann /** Constructor for intent-based InstantApp resolution results. */ 861fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy public InstantAppResolveInfo(@NonNull InstantAppDigest digest, @Nullable String packageName, 87c0dd03a666467d03e140f3a43704b3f3f3f4d4b7Todd Kennedy @Nullable List<InstantAppIntentFilter> filters, int versionCode) { 88709ee1551db935adb2026fae9dd799e60f784499Patrick Baumann this(digest, packageName, filters, (long) versionCode, null /* extras */); 893accca05ddcad9d0b1b313eae49f273e39121d3cDianne Hackborn } 903accca05ddcad9d0b1b313eae49f273e39121d3cDianne Hackborn 91577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann /** Constructor for intent-based InstantApp resolution results with extras. */ 923accca05ddcad9d0b1b313eae49f273e39121d3cDianne Hackborn public InstantAppResolveInfo(@NonNull InstantAppDigest digest, @Nullable String packageName, 93709ee1551db935adb2026fae9dd799e60f784499Patrick Baumann @Nullable List<InstantAppIntentFilter> filters, long versionCode, 94709ee1551db935adb2026fae9dd799e60f784499Patrick Baumann @Nullable Bundle extras) { 95577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann this(digest, packageName, filters, versionCode, extras, false); 96577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann } 97577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann 983abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann /** Constructor for intent-based InstantApp resolution results by hostname. */ 993abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann public InstantAppResolveInfo(@NonNull String hostName, @Nullable String packageName, 1003abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann @Nullable List<InstantAppIntentFilter> filters) { 1013abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann this(new InstantAppDigest(hostName), packageName, filters, -1 /*versionCode*/, 1023abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann null /* extras */); 1033abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann } 1043abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann 1053abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann /** 1063abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann * Constructor that indicates that resolution could be delegated to the installer when the 1073abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann * sanitized intent contains enough information to resolve completely. 1083abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann */ 1093abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann public InstantAppResolveInfo(@Nullable Bundle extras) { 1103abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann this(InstantAppDigest.UNDEFINED, null, null, -1, extras, true); 1113abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann } 1123abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann 113577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann private InstantAppResolveInfo(@NonNull InstantAppDigest digest, @Nullable String packageName, 114577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann @Nullable List<InstantAppIntentFilter> filters, long versionCode, 115577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann @Nullable Bundle extras, boolean shouldLetInstallerDecide) { 1161fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy // validate arguments 1171fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy if ((packageName == null && (filters != null && filters.size() != 0)) 1181fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy || (packageName != null && (filters == null || filters.size() == 0))) { 1191fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy throw new IllegalArgumentException(); 1201fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 1211fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy mDigest = digest; 1221fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy if (filters != null) { 123577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann mFilters = new ArrayList<>(filters.size()); 1241fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy mFilters.addAll(filters); 1251fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } else { 1261fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy mFilters = null; 1271fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 1281fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy mPackageName = packageName; 129c0dd03a666467d03e140f3a43704b3f3f3f4d4b7Todd Kennedy mVersionCode = versionCode; 130709ee1551db935adb2026fae9dd799e60f784499Patrick Baumann mExtras = extras; 131577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann mShouldLetInstallerDecide = shouldLetInstallerDecide; 1321fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 1331fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy 1341fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy InstantAppResolveInfo(Parcel in) { 135577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann mShouldLetInstallerDecide = in.readBoolean(); 136709ee1551db935adb2026fae9dd799e60f784499Patrick Baumann mExtras = in.readBundle(); 137577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann if (mShouldLetInstallerDecide) { 138577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann mDigest = InstantAppDigest.UNDEFINED; 139577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann mPackageName = null; 140577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann mFilters = Collections.emptyList(); 141577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann mVersionCode = -1; 142577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann } else { 143577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann mDigest = in.readParcelable(null /*loader*/); 144577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann mPackageName = in.readString(); 145577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann mFilters = new ArrayList<>(); 146577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann in.readList(mFilters, null /*loader*/); 147577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann mVersionCode = in.readLong(); 148577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann } 149577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann } 150577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann 1513abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann /** 1523abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann * Returns true if the resolver is aware that an app may match, but would prefer 1533abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann * that the installer get the sanitized intent to decide. This should not be true for 1543abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann * resolutions that include a host and will be ignored in such cases. 1553abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann */ 156577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann public boolean shouldLetInstallerDecide() { 157577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann return mShouldLetInstallerDecide; 1581fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 1591fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy 1601fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy public byte[] getDigestBytes() { 161577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann return mDigest.mDigestBytes.length > 0 ? mDigest.getDigestBytes()[0] : EMPTY_DIGEST; 1621fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 1631fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy 1641fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy public int getDigestPrefix() { 1651fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy return mDigest.getDigestPrefix()[0]; 1661fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 1671fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy 1681fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy public String getPackageName() { 1691fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy return mPackageName; 1701fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 1711fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy 1721fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy public List<InstantAppIntentFilter> getIntentFilters() { 1731fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy return mFilters; 1741fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 1751fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy 1763accca05ddcad9d0b1b313eae49f273e39121d3cDianne Hackborn /** 1773accca05ddcad9d0b1b313eae49f273e39121d3cDianne Hackborn * @deprecated Use {@link #getLongVersionCode} instead. 1783accca05ddcad9d0b1b313eae49f273e39121d3cDianne Hackborn */ 1793accca05ddcad9d0b1b313eae49f273e39121d3cDianne Hackborn @Deprecated 1801fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy public int getVersionCode() { 1813accca05ddcad9d0b1b313eae49f273e39121d3cDianne Hackborn return (int) (mVersionCode & 0xffffffff); 1823accca05ddcad9d0b1b313eae49f273e39121d3cDianne Hackborn } 1833accca05ddcad9d0b1b313eae49f273e39121d3cDianne Hackborn 1843accca05ddcad9d0b1b313eae49f273e39121d3cDianne Hackborn public long getLongVersionCode() { 1851fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy return mVersionCode; 1861fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 1871fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy 188709ee1551db935adb2026fae9dd799e60f784499Patrick Baumann @Nullable 189709ee1551db935adb2026fae9dd799e60f784499Patrick Baumann public Bundle getExtras() { 190709ee1551db935adb2026fae9dd799e60f784499Patrick Baumann return mExtras; 191709ee1551db935adb2026fae9dd799e60f784499Patrick Baumann } 192709ee1551db935adb2026fae9dd799e60f784499Patrick Baumann 1931fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy @Override 1941fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy public int describeContents() { 1951fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy return 0; 1961fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 1971fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy 1981fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy @Override 1991fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy public void writeToParcel(Parcel out, int flags) { 200577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann out.writeBoolean(mShouldLetInstallerDecide); 201577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann out.writeBundle(mExtras); 202577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann if (mShouldLetInstallerDecide) { 203577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann return; 204577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann } 2051fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy out.writeParcelable(mDigest, flags); 2061fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy out.writeString(mPackageName); 2071fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy out.writeList(mFilters); 2083accca05ddcad9d0b1b313eae49f273e39121d3cDianne Hackborn out.writeLong(mVersionCode); 2091fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 2101fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy 2111fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy public static final Parcelable.Creator<InstantAppResolveInfo> CREATOR 2121fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy = new Parcelable.Creator<InstantAppResolveInfo>() { 2131fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy public InstantAppResolveInfo createFromParcel(Parcel in) { 2141fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy return new InstantAppResolveInfo(in); 2151fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 2161fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy 2171fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy public InstantAppResolveInfo[] newArray(int size) { 2181fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy return new InstantAppResolveInfo[size]; 2191fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 2201fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy }; 2211fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy 2221fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy /** 2231fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * Helper class to generate and store each of the digests and prefixes 2241fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * sent to the Instant App Resolver. 2251fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * <p> 2261fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * Since intent filters may want to handle multiple hosts within a 2271fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * domain [eg “*.google.com”], the resolver is presented with multiple 2281fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * hash prefixes. For example, "a.b.c.d.e" generates digests for 2291fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * "d.e", "c.d.e", "b.c.d.e" and "a.b.c.d.e". 2301fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * 2311fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy * @hide 2321fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy */ 2331fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy @SystemApi 2341fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy public static final class InstantAppDigest implements Parcelable { 2354db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann static final int DIGEST_MASK = 0xfffff000; 2363abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann 2373abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann /** 2383abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann * A special instance that represents and undefined digest used for cases that a host was 2393abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann * not provided or is irrelevant to the response. 2403abf547d1f45557aad8b8d28e5ee87d1bb039623Patrick Baumann */ 241577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann public static final InstantAppDigest UNDEFINED = 242577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann new InstantAppDigest(new byte[][]{}, new int[]{}); 2434db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann 2444db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann private static Random sRandom = null; 2454db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann static { 2464db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann try { 2474db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann sRandom = SecureRandom.getInstance("SHA1PRNG"); 2484db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann } catch (NoSuchAlgorithmException e) { 2494db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann // oh well 2504db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann sRandom = new Random(); 2514db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann } 2524db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann } 2531fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy /** Full digest of the domain hashes */ 2541fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy private final byte[][] mDigestBytes; 2554db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann /** The first 5 bytes of the domain hashes */ 2561fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy private final int[] mDigestPrefix; 2574db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann /** The first 5 bytes of the domain hashes interspersed with random data */ 2584db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann private int[] mDigestPrefixSecure; 2591fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy 2601fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy public InstantAppDigest(@NonNull String hostName) { 2611fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy this(hostName, -1 /*maxDigests*/); 2621fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 2631fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy 2641fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy /** @hide */ 2651fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy public InstantAppDigest(@NonNull String hostName, int maxDigests) { 2661fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy if (hostName == null) { 2671fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy throw new IllegalArgumentException(); 2681fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 2691fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy mDigestBytes = generateDigest(hostName.toLowerCase(Locale.ENGLISH), maxDigests); 2701fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy mDigestPrefix = new int[mDigestBytes.length]; 2711fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy for (int i = 0; i < mDigestBytes.length; i++) { 2721fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy mDigestPrefix[i] = 2731fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy ((mDigestBytes[i][0] & 0xFF) << 24 2741fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy | (mDigestBytes[i][1] & 0xFF) << 16 2751fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy | (mDigestBytes[i][2] & 0xFF) << 8 2761fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy | (mDigestBytes[i][3] & 0xFF) << 0) 2771fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy & DIGEST_MASK; 2781fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 2791fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 2801fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy 281577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann private InstantAppDigest(byte[][] digestBytes, int[] prefix) { 282577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann this.mDigestPrefix = prefix; 283577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann this.mDigestBytes = digestBytes; 284577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann } 285577d402d0d938c14d415054289a5ecbc613d0046Patrick Baumann 2861fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy private static byte[][] generateDigest(String hostName, int maxDigests) { 2871fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy ArrayList<byte[]> digests = new ArrayList<>(); 2881fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy try { 2891fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy final MessageDigest digest = MessageDigest.getInstance(SHA_ALGORITHM); 2901fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy if (maxDigests <= 0) { 2911fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy final byte[] hostBytes = hostName.getBytes(); 2921fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy digests.add(digest.digest(hostBytes)); 2931fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } else { 2941fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy int prevDot = hostName.lastIndexOf('.'); 2951fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy prevDot = hostName.lastIndexOf('.', prevDot - 1); 2961fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy // shortcut for short URLs 2971fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy if (prevDot < 0) { 2981fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy digests.add(digest.digest(hostName.getBytes())); 2991fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } else { 3001fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy byte[] hostBytes = 3011fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy hostName.substring(prevDot + 1, hostName.length()).getBytes(); 3021fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy digests.add(digest.digest(hostBytes)); 3031fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy int digestCount = 1; 3041fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy while (prevDot >= 0 && digestCount < maxDigests) { 3051fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy prevDot = hostName.lastIndexOf('.', prevDot - 1); 3061fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy hostBytes = 3071fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy hostName.substring(prevDot + 1, hostName.length()).getBytes(); 3081fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy digests.add(digest.digest(hostBytes)); 3091fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy digestCount++; 3101fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 3111fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 3121fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 3131fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } catch (NoSuchAlgorithmException e) { 3141fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy throw new IllegalStateException("could not find digest algorithm"); 3151fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 3161fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy return digests.toArray(new byte[digests.size()][]); 3171fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 3181fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy 3191fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy InstantAppDigest(Parcel in) { 3201fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy final int digestCount = in.readInt(); 3211fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy if (digestCount == -1) { 3221fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy mDigestBytes = null; 3231fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } else { 3241fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy mDigestBytes = new byte[digestCount][]; 3251fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy for (int i = 0; i < digestCount; i++) { 3261fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy mDigestBytes[i] = in.createByteArray(); 3271fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 3281fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 3291fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy mDigestPrefix = in.createIntArray(); 3304db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann mDigestPrefixSecure = in.createIntArray(); 3311fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 3321fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy 3331fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy public byte[][] getDigestBytes() { 3341fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy return mDigestBytes; 3351fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 3361fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy 3371fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy public int[] getDigestPrefix() { 3381fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy return mDigestPrefix; 3391fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 3401fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy 3414db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann /** 3424db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann * Returns a digest prefix with additional random prefixes interspersed. 3434db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann * @hide 3444db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann */ 3454db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann public int[] getDigestPrefixSecure() { 3464db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann if (this == InstantAppResolveInfo.InstantAppDigest.UNDEFINED) { 3474db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann return getDigestPrefix(); 3484db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann } else if (mDigestPrefixSecure == null) { 3494db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann // let's generate some random data to intersperse throughout the set of prefixes 3504db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann final int realSize = getDigestPrefix().length; 3514db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann final int manufacturedSize = realSize + 10 + sRandom.nextInt(10); 3524db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann mDigestPrefixSecure = Arrays.copyOf(getDigestPrefix(), manufacturedSize); 3534db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann for (int i = realSize; i < manufacturedSize; i++) { 3544db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann mDigestPrefixSecure[i] = sRandom.nextInt() & DIGEST_MASK; 3554db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann } 3564db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann Arrays.sort(mDigestPrefixSecure); 3574db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann } 3584db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann return mDigestPrefixSecure; 3594db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann } 3604db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann 3611fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy @Override 3621fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy public int describeContents() { 3631fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy return 0; 3641fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 3651fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy 3661fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy @Override 3671fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy public void writeToParcel(Parcel out, int flags) { 3684db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann final boolean isUndefined = this == UNDEFINED; 3694db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann out.writeBoolean(isUndefined); 3704db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann if (isUndefined) { 3714db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann return; 3724db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann } 3731fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy if (mDigestBytes == null) { 3741fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy out.writeInt(-1); 3751fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } else { 3761fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy out.writeInt(mDigestBytes.length); 3771fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy for (int i = 0; i < mDigestBytes.length; i++) { 3781fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy out.writeByteArray(mDigestBytes[i]); 3791fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 3801fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 3811fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy out.writeIntArray(mDigestPrefix); 3824db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann out.writeIntArray(mDigestPrefixSecure); 3831fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 3841fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy 3851fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy @SuppressWarnings("hiding") 3861fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy public static final Parcelable.Creator<InstantAppDigest> CREATOR = 3871fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy new Parcelable.Creator<InstantAppDigest>() { 3881fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy @Override 3891fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy public InstantAppDigest createFromParcel(Parcel in) { 3904db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann if (in.readBoolean() /* is undefined */) { 3914db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann return UNDEFINED; 3924db6bc16d0cc3c3b60a6b5305118f266ab2028a8Patrick Baumann } 3931fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy return new InstantAppDigest(in); 3941fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 3951fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy @Override 3961fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy public InstantAppDigest[] newArray(int size) { 3971fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy return new InstantAppDigest[size]; 3981fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 3991fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy }; 4001fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy } 4011fb3404b2ba69a823e961bec2d9ed61622107052Todd Kennedy} 402