/* * Copyright (C) 2017 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; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.content.Intent; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Random; /** * Describes an externally resolvable instant application. There are three states that this class * can represent:
*
* Since intent filters may want to handle multiple hosts within a
* domain [eg “*.google.com”], the resolver is presented with multiple
* hash prefixes. For example, "a.b.c.d.e" generates digests for
* "d.e", "c.d.e", "b.c.d.e" and "a.b.c.d.e".
*
* @hide
*/
@SystemApi
public static final class InstantAppDigest implements Parcelable {
static final int DIGEST_MASK = 0xfffff000;
/**
* A special instance that represents and undefined digest used for cases that a host was
* not provided or is irrelevant to the response.
*/
public static final InstantAppDigest UNDEFINED =
new InstantAppDigest(new byte[][]{}, new int[]{});
private static Random sRandom = null;
static {
try {
sRandom = SecureRandom.getInstance("SHA1PRNG");
} catch (NoSuchAlgorithmException e) {
// oh well
sRandom = new Random();
}
}
/** Full digest of the domain hashes */
private final byte[][] mDigestBytes;
/** The first 5 bytes of the domain hashes */
private final int[] mDigestPrefix;
/** The first 5 bytes of the domain hashes interspersed with random data */
private int[] mDigestPrefixSecure;
public InstantAppDigest(@NonNull String hostName) {
this(hostName, -1 /*maxDigests*/);
}
/** @hide */
public InstantAppDigest(@NonNull String hostName, int maxDigests) {
if (hostName == null) {
throw new IllegalArgumentException();
}
mDigestBytes = generateDigest(hostName.toLowerCase(Locale.ENGLISH), maxDigests);
mDigestPrefix = new int[mDigestBytes.length];
for (int i = 0; i < mDigestBytes.length; i++) {
mDigestPrefix[i] =
((mDigestBytes[i][0] & 0xFF) << 24
| (mDigestBytes[i][1] & 0xFF) << 16
| (mDigestBytes[i][2] & 0xFF) << 8
| (mDigestBytes[i][3] & 0xFF) << 0)
& DIGEST_MASK;
}
}
private InstantAppDigest(byte[][] digestBytes, int[] prefix) {
this.mDigestPrefix = prefix;
this.mDigestBytes = digestBytes;
}
private static byte[][] generateDigest(String hostName, int maxDigests) {
ArrayList