133 lines
5.3 KiB
Java
133 lines
5.3 KiB
Java
// Copyright 2015 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
package org.chromium.base;
|
|
|
|
import android.annotation.SuppressLint;
|
|
import android.content.Context;
|
|
import android.content.pm.PackageInfo;
|
|
import android.content.pm.PackageManager;
|
|
import android.content.pm.Signature;
|
|
|
|
import androidx.annotation.Nullable;
|
|
import androidx.annotation.VisibleForTesting;
|
|
|
|
import java.io.ByteArrayInputStream;
|
|
import java.io.InputStream;
|
|
import java.security.MessageDigest;
|
|
import java.security.NoSuchAlgorithmException;
|
|
import java.security.cert.CertificateException;
|
|
import java.security.cert.CertificateFactory;
|
|
import java.security.cert.X509Certificate;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
/** This class provides package checking related methods. */
|
|
public class PackageUtils {
|
|
private static final String TAG = "PackageUtils";
|
|
private static final char[] HEX_CHAR_LOOKUP = "0123456789ABCDEF".toCharArray();
|
|
|
|
/** Retrieves the PackageInfo for the given package, or null if it is not installed. */
|
|
public static @Nullable PackageInfo getPackageInfo(String packageName, int flags) {
|
|
PackageManager pm = ContextUtils.getApplicationContext().getPackageManager();
|
|
try {
|
|
return pm.getPackageInfo(packageName, flags);
|
|
} catch (PackageManager.NameNotFoundException e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retrieves the version of the given package installed on the device.
|
|
*
|
|
* @param packageName Name of the package to find.
|
|
* @return The package's version code if found, -1 otherwise.
|
|
*/
|
|
public static int getPackageVersion(String packageName) {
|
|
// TODO(agrieve): Return a long and move BuildInfo.packageVersionCode() to this class.
|
|
PackageInfo packageInfo = getPackageInfo(packageName, 0);
|
|
if (packageInfo != null) return packageInfo.versionCode;
|
|
return -1;
|
|
}
|
|
|
|
// TODO(agrieve): Delete downstream references.
|
|
public static int getPackageVersion(Context unused, String packageName) {
|
|
return getPackageVersion(packageName);
|
|
}
|
|
|
|
/**
|
|
* Checks if the app has been installed on the system.
|
|
* @return true if the PackageManager reports that the app is installed, false otherwise.
|
|
* @param packageName Name of the package to check.
|
|
*/
|
|
public static boolean isPackageInstalled(String packageName) {
|
|
return getPackageInfo(packageName, 0) != null;
|
|
}
|
|
|
|
/** Returns the PackageInfo for the current app, as retrieve by PackageManager. */
|
|
public static PackageInfo getApplicationPackageInfo(int flags) {
|
|
PackageInfo ret = getPackageInfo(BuildInfo.getInstance().packageName, flags);
|
|
assert ret != null;
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Computes the SHA256 certificates for the given package name. The app with the given package
|
|
* name has to be installed on device. The output will be a list of 30 long HEX strings with :
|
|
* between each value. There will be one string for each signature the app is signed with.
|
|
* @param packageName The package name to query the signature for.
|
|
* @return The SHA256 certificate for the package name.
|
|
*/
|
|
@SuppressLint("PackageManagerGetSignatures")
|
|
// https://stackoverflow.com/questions/39192844/android-studio-warning-when-using-packagemanager-get-signatures
|
|
public static List<String> getCertificateSHA256FingerprintForPackage(String packageName) {
|
|
PackageInfo packageInfo = getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
|
|
|
|
if (packageInfo == null) return null;
|
|
|
|
ArrayList<String> fingerprints = new ArrayList<>(packageInfo.signatures.length);
|
|
|
|
for (Signature signature : packageInfo.signatures) {
|
|
InputStream input = new ByteArrayInputStream(signature.toByteArray());
|
|
String hexString = null;
|
|
try {
|
|
X509Certificate certificate =
|
|
(X509Certificate)
|
|
CertificateFactory.getInstance("X509").generateCertificate(input);
|
|
hexString =
|
|
byteArrayToHexString(
|
|
MessageDigest.getInstance("SHA256")
|
|
.digest(certificate.getEncoded()));
|
|
} catch (CertificateException | NoSuchAlgorithmException e) {
|
|
Log.w(TAG, "Exception", e);
|
|
return null;
|
|
}
|
|
|
|
fingerprints.add(hexString);
|
|
}
|
|
|
|
return fingerprints;
|
|
}
|
|
|
|
/**
|
|
* Converts a byte array to hex string with : inserted between each element.
|
|
* @param byteArray The array to be converted.
|
|
* @return A string with two letters representing each byte and : in between.
|
|
*/
|
|
@VisibleForTesting
|
|
static String byteArrayToHexString(byte[] byteArray) {
|
|
StringBuilder hexString = new StringBuilder(byteArray.length * 3 - 1);
|
|
for (int i = 0; i < byteArray.length; ++i) {
|
|
hexString.append(HEX_CHAR_LOOKUP[(byteArray[i] & 0xf0) >>> 4]);
|
|
hexString.append(HEX_CHAR_LOOKUP[byteArray[i] & 0xf]);
|
|
if (i < (byteArray.length - 1)) hexString.append(':');
|
|
}
|
|
return hexString.toString();
|
|
}
|
|
|
|
private PackageUtils() {
|
|
// Hide constructor
|
|
}
|
|
}
|