Merge "Move code"

This commit is contained in:
Todd Kennedy
2017-11-06 21:26:57 +00:00
committed by Android (Google) Code Review
7 changed files with 447 additions and 402 deletions

View File

@@ -16,6 +16,8 @@
package com.android.server;
import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
import android.content.ContentResolver;
import android.content.Context;
import android.os.Build;
@@ -146,7 +148,7 @@ public class RescueParty {
SystemProperties.set(PROP_RESCUE_LEVEL, Integer.toString(level));
EventLogTags.writeRescueLevel(level, triggerUid);
PackageManagerService.logCriticalInfo(Log.WARN, "Incremented rescue level to "
logCriticalInfo(Log.WARN, "Incremented rescue level to "
+ levelToString(level) + " triggered by UID " + triggerUid);
}
@@ -166,12 +168,12 @@ public class RescueParty {
try {
executeRescueLevelInternal(context, level);
EventLogTags.writeRescueSuccess(level);
PackageManagerService.logCriticalInfo(Log.DEBUG,
logCriticalInfo(Log.DEBUG,
"Finished rescue level " + levelToString(level));
} catch (Throwable t) {
final String msg = ExceptionUtils.getCompleteMessage(t);
EventLogTags.writeRescueFailure(level, msg);
PackageManagerService.logCriticalInfo(Log.ERROR,
logCriticalInfo(Log.ERROR,
"Failed rescue level " + levelToString(level) + ": " + msg);
}
}

View File

@@ -18,6 +18,8 @@ package com.android.server.pm;
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
import static com.android.server.pm.PackageManagerService.SCAN_INITIAL;
import com.android.internal.util.Preconditions;
import android.content.pm.PackageParser;
import android.util.ArrayMap;
@@ -341,6 +343,41 @@ public class KeySetManagerService {
return mKeySets.get(id) != null;
}
public boolean shouldCheckUpgradeKeySetLocked(PackageSettingBase oldPs, int scanFlags) {
// Can't rotate keys during boot or if sharedUser.
if (oldPs == null || (scanFlags&SCAN_INITIAL) != 0 || oldPs.isSharedUser()
|| !oldPs.keySetData.isUsingUpgradeKeySets()) {
return false;
}
// app is using upgradeKeySets; make sure all are valid
long[] upgradeKeySets = oldPs.keySetData.getUpgradeKeySets();
for (int i = 0; i < upgradeKeySets.length; i++) {
if (!isIdValidKeySetId(upgradeKeySets[i])) {
Slog.wtf(TAG, "Package "
+ (oldPs.name != null ? oldPs.name : "<null>")
+ " contains upgrade-key-set reference to unknown key-set: "
+ upgradeKeySets[i]
+ " reverting to signatures check.");
return false;
}
}
return true;
}
public boolean checkUpgradeKeySetLocked(PackageSettingBase oldPS,
PackageParser.Package newPkg) {
// Upgrade keysets are being used. Determine if new package has a superset of the
// required keys.
long[] upgradeKeySets = oldPS.keySetData.getUpgradeKeySets();
for (int i = 0; i < upgradeKeySets.length; i++) {
Set<PublicKey> upgradeSet = getPublicKeysFromKeySetLPr(upgradeKeySets[i]);
if (upgradeSet != null && newPkg.mSigningKeys.containsAll(upgradeSet)) {
return true;
}
}
return false;
}
/**
* Fetches the {@link PublicKey public keys} which belong to the specified
* KeySet id.

View File

@@ -102,6 +102,15 @@ import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getCompilerFilterForReason;
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter;
import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
import static com.android.server.pm.PackageManagerServiceUtils.compressedFileExists;
import static com.android.server.pm.PackageManagerServiceUtils.decompressFile;
import static com.android.server.pm.PackageManagerServiceUtils.deriveAbiOverride;
import static com.android.server.pm.PackageManagerServiceUtils.dumpCriticalInfo;
import static com.android.server.pm.PackageManagerServiceUtils.getCompressedFiles;
import static com.android.server.pm.PackageManagerServiceUtils.getLastModifiedTime;
import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
import static com.android.server.pm.PackageManagerServiceUtils.verifySignatures;
import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_FAILURE;
import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_SUCCESS;
import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
@@ -408,7 +417,7 @@ public class PackageManagerService extends IPackageManager.Stub
private static final boolean DEBUG_FILTERS = false;
public static final boolean DEBUG_PERMISSIONS = false;
private static final boolean DEBUG_SHARED_LIBRARIES = false;
private static final boolean DEBUG_COMPRESSION = Build.IS_DEBUGGABLE;
public static final boolean DEBUG_COMPRESSION = Build.IS_DEBUGGABLE;
// Debug output for dexopting. This is shared between PackageManagerService, OtaDexoptService
// and PackageDexOptimizer. All these classes have their own flag to allow switching a single
@@ -462,9 +471,9 @@ public class PackageManagerService extends IPackageManager.Stub
private static final String STATIC_SHARED_LIB_DELIMITER = "_";
/** Extension of the compressed packages */
private final static String COMPRESSED_EXTENSION = ".gz";
public final static String COMPRESSED_EXTENSION = ".gz";
/** Suffix of stub packages on the system partition */
private final static String STUB_SUFFIX = "-Stub";
public final static String STUB_SUFFIX = "-Stub";
private static final int[] EMPTY_INT_ARRAY = new int[0];
@@ -3076,75 +3085,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
private int decompressFile(File srcFile, File dstFile) throws ErrnoException {
if (DEBUG_COMPRESSION) {
Slog.i(TAG, "Decompress file"
+ "; src: " + srcFile.getAbsolutePath()
+ ", dst: " + dstFile.getAbsolutePath());
}
try (
InputStream fileIn = new GZIPInputStream(new FileInputStream(srcFile));
OutputStream fileOut = new FileOutputStream(dstFile, false /*append*/);
) {
Streams.copy(fileIn, fileOut);
Os.chmod(dstFile.getAbsolutePath(), 0644);
return PackageManager.INSTALL_SUCCEEDED;
} catch (IOException e) {
logCriticalInfo(Log.ERROR, "Failed to decompress file"
+ "; src: " + srcFile.getAbsolutePath()
+ ", dst: " + dstFile.getAbsolutePath());
}
return PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
}
private File[] getCompressedFiles(String codePath) {
final File stubCodePath = new File(codePath);
final String stubName = stubCodePath.getName();
// The layout of a compressed package on a given partition is as follows :
//
// Compressed artifacts:
//
// /partition/ModuleName/foo.gz
// /partation/ModuleName/bar.gz
//
// Stub artifact:
//
// /partition/ModuleName-Stub/ModuleName-Stub.apk
//
// In other words, stub is on the same partition as the compressed artifacts
// and in a directory that's suffixed with "-Stub".
int idx = stubName.lastIndexOf(STUB_SUFFIX);
if (idx < 0 || (stubName.length() != (idx + STUB_SUFFIX.length()))) {
return null;
}
final File stubParentDir = stubCodePath.getParentFile();
if (stubParentDir == null) {
Slog.e(TAG, "Unable to determine stub parent dir for codePath: " + codePath);
return null;
}
final File compressedPath = new File(stubParentDir, stubName.substring(0, idx));
final File[] files = compressedPath.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(COMPRESSED_EXTENSION);
}
});
if (DEBUG_COMPRESSION && files != null && files.length > 0) {
Slog.i(TAG, "getCompressedFiles[" + codePath + "]: " + Arrays.toString(files));
}
return files;
}
private boolean compressedFileExists(String codePath) {
final File[] compressedFiles = getCompressedFiles(codePath);
return compressedFiles != null && compressedFiles.length > 0;
}
/**
* Decompresses the given package on the system image onto
* the /data partition.
@@ -5384,56 +5324,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
/**
* Compares two sets of signatures. Returns:
* <br />
* {@link PackageManager#SIGNATURE_NEITHER_SIGNED}: if both signature sets are null,
* <br />
* {@link PackageManager#SIGNATURE_FIRST_NOT_SIGNED}: if the first signature set is null,
* <br />
* {@link PackageManager#SIGNATURE_SECOND_NOT_SIGNED}: if the second signature set is null,
* <br />
* {@link PackageManager#SIGNATURE_MATCH}: if the two signature sets are identical,
* <br />
* {@link PackageManager#SIGNATURE_NO_MATCH}: if the two signature sets differ.
*/
public static int compareSignatures(Signature[] s1, Signature[] s2) {
if (s1 == null) {
return s2 == null
? PackageManager.SIGNATURE_NEITHER_SIGNED
: PackageManager.SIGNATURE_FIRST_NOT_SIGNED;
}
if (s2 == null) {
return PackageManager.SIGNATURE_SECOND_NOT_SIGNED;
}
if (s1.length != s2.length) {
return PackageManager.SIGNATURE_NO_MATCH;
}
// Since both signature sets are of size 1, we can compare without HashSets.
if (s1.length == 1) {
return s1[0].equals(s2[0]) ?
PackageManager.SIGNATURE_MATCH :
PackageManager.SIGNATURE_NO_MATCH;
}
ArraySet<Signature> set1 = new ArraySet<Signature>();
for (Signature sig : s1) {
set1.add(sig);
}
ArraySet<Signature> set2 = new ArraySet<Signature>();
for (Signature sig : s2) {
set2.add(sig);
}
// Make sure s2 contains all signatures in s1.
if (set1.equals(set2)) {
return PackageManager.SIGNATURE_MATCH;
}
return PackageManager.SIGNATURE_NO_MATCH;
}
/**
* If the database version for this type of package (internal storage or
* external storage) is less than the version where package signatures
@@ -5444,76 +5334,11 @@ public class PackageManagerService extends IPackageManager.Stub
return ver.databaseVersion < DatabaseVersion.SIGNATURE_END_ENTITY;
}
/**
* Used for backward compatibility to make sure any packages with
* certificate chains get upgraded to the new style. {@code existingSigs}
* will be in the old format (since they were stored on disk from before the
* system upgrade) and {@code scannedSigs} will be in the newer format.
*/
private int compareSignaturesCompat(PackageSignatures existingSigs,
PackageParser.Package scannedPkg) {
if (!isCompatSignatureUpdateNeeded(scannedPkg)) {
return PackageManager.SIGNATURE_NO_MATCH;
}
ArraySet<Signature> existingSet = new ArraySet<Signature>();
for (Signature sig : existingSigs.mSignatures) {
existingSet.add(sig);
}
ArraySet<Signature> scannedCompatSet = new ArraySet<Signature>();
for (Signature sig : scannedPkg.mSignatures) {
try {
Signature[] chainSignatures = sig.getChainSignatures();
for (Signature chainSig : chainSignatures) {
scannedCompatSet.add(chainSig);
}
} catch (CertificateEncodingException e) {
scannedCompatSet.add(sig);
}
}
/*
* Make sure the expanded scanned set contains all signatures in the
* existing one.
*/
if (scannedCompatSet.equals(existingSet)) {
// Migrate the old signatures to the new scheme.
existingSigs.assignSignatures(scannedPkg.mSignatures);
// The new KeySets will be re-added later in the scanning process.
synchronized (mPackages) {
mSettings.mKeySetManagerService.removeAppKeySetDataLPw(scannedPkg.packageName);
}
return PackageManager.SIGNATURE_MATCH;
}
return PackageManager.SIGNATURE_NO_MATCH;
}
private boolean isRecoverSignatureUpdateNeeded(PackageParser.Package scannedPkg) {
final VersionInfo ver = getSettingsVersionForPackage(scannedPkg);
return ver.databaseVersion < DatabaseVersion.SIGNATURE_MALFORMED_RECOVER;
}
private int compareSignaturesRecover(PackageSignatures existingSigs,
PackageParser.Package scannedPkg) {
if (!isRecoverSignatureUpdateNeeded(scannedPkg)) {
return PackageManager.SIGNATURE_NO_MATCH;
}
String msg = null;
try {
if (Signature.areEffectiveMatch(existingSigs.mSignatures, scannedPkg.mSignatures)) {
logCriticalInfo(Log.INFO, "Recovered effectively matching certificates for "
+ scannedPkg.packageName);
return PackageManager.SIGNATURE_MATCH;
}
} catch (CertificateException e) {
msg = e.getMessage();
}
logCriticalInfo(Log.INFO,
"Failed to recover certificates for " + scannedPkg.packageName + ": " + msg);
return PackageManager.SIGNATURE_NO_MATCH;
}
@Override
public List<String> getAllPackages() {
final int callingUid = Binder.getCallingUid();
@@ -8237,51 +8062,10 @@ public class PackageManagerService extends IPackageManager.Stub
parallelPackageParser.close();
}
private static File getSettingsProblemFile() {
File dataDir = Environment.getDataDirectory();
File systemDir = new File(dataDir, "system");
File fname = new File(systemDir, "uiderrors.txt");
return fname;
}
public static void reportSettingsProblem(int priority, String msg) {
logCriticalInfo(priority, msg);
}
public static void logCriticalInfo(int priority, String msg) {
Slog.println(priority, TAG, msg);
EventLogTags.writePmCriticalInfo(msg);
try {
File fname = getSettingsProblemFile();
FileOutputStream out = new FileOutputStream(fname, true);
PrintWriter pw = new FastPrintWriter(out);
SimpleDateFormat formatter = new SimpleDateFormat();
String dateString = formatter.format(new Date(System.currentTimeMillis()));
pw.println(dateString + ": " + msg);
pw.close();
FileUtils.setPermissions(
fname.toString(),
FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IROTH,
-1, -1);
} catch (java.io.IOException e) {
}
}
private long getLastModifiedTime(PackageParser.Package pkg, File srcFile) {
if (srcFile.isDirectory()) {
final File baseFile = new File(pkg.baseCodePath);
long maxModifiedTime = baseFile.lastModified();
if (pkg.splitCodePaths != null) {
for (int i = pkg.splitCodePaths.length - 1; i >=0; --i) {
final File splitFile = new File(pkg.splitCodePaths[i]);
maxModifiedTime = Math.max(maxModifiedTime, splitFile.lastModified());
}
}
return maxModifiedTime;
}
return srcFile.lastModified();
}
private void collectCertificatesLI(PackageSetting ps, PackageParser.Package pkg, File srcFile,
final int policyFlags) throws PackageManagerException {
// When upgrading from pre-N MR1, verify the package time stamp using the package
@@ -8294,7 +8078,7 @@ public class PackageManagerService extends IPackageManager.Stub
&& !isCompatSignatureUpdateNeeded(pkg)
&& !isRecoverSignatureUpdateNeeded(pkg)) {
long mSigningKeySetId = ps.keySetData.getProperSigningKeySet();
KeySetManagerService ksms = mSettings.mKeySetManagerService;
final KeySetManagerService ksms = mSettings.mKeySetManagerService;
ArraySet<PublicKey> signingKs;
synchronized (mPackages) {
signingKs = ksms.getPublicKeysFromKeySetLPr(mSigningKeySetId);
@@ -8710,7 +8494,7 @@ public class PackageManagerService extends IPackageManager.Stub
return scannedPkg;
}
private void renameStaticSharedLibraryPackage(PackageParser.Package pkg) {
private static void renameStaticSharedLibraryPackage(PackageParser.Package pkg) {
// Derive the new package synthetic package name
pkg.setPackageName(pkg.packageName + STATIC_SHARED_LIB_DELIMITER
+ pkg.staticSharedLibVersion);
@@ -8724,49 +8508,6 @@ public class PackageManagerService extends IPackageManager.Stub
return processName;
}
private void verifySignaturesLP(PackageSetting pkgSetting, PackageParser.Package pkg)
throws PackageManagerException {
if (pkgSetting.signatures.mSignatures != null) {
// Already existing package. Make sure signatures match
boolean match = compareSignatures(pkgSetting.signatures.mSignatures, pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH;
if (!match) {
match = compareSignaturesCompat(pkgSetting.signatures, pkg)
== PackageManager.SIGNATURE_MATCH;
}
if (!match) {
match = compareSignaturesRecover(pkgSetting.signatures, pkg)
== PackageManager.SIGNATURE_MATCH;
}
if (!match) {
throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
+ pkg.packageName + " signatures do not match the "
+ "previously installed version; ignoring!");
}
}
// Check for shared user signatures
if (pkgSetting.sharedUser != null && pkgSetting.sharedUser.signatures.mSignatures != null) {
// Already existing package. Make sure signatures match
boolean match = compareSignatures(pkgSetting.sharedUser.signatures.mSignatures,
pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;
if (!match) {
match = compareSignaturesCompat(pkgSetting.sharedUser.signatures, pkg)
== PackageManager.SIGNATURE_MATCH;
}
if (!match) {
match = compareSignaturesRecover(pkgSetting.sharedUser.signatures, pkg)
== PackageManager.SIGNATURE_MATCH;
}
if (!match) {
throw new PackageManagerException(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
"Package " + pkg.packageName
+ " has no signatures that match those in shared user "
+ pkgSetting.sharedUser.name + "; ignoring!");
}
}
}
/**
* Enforces that only the system UID or root's UID can call a method exposed
* via Binder.
@@ -9737,24 +9478,6 @@ public class PackageManagerService extends IPackageManager.Stub
return res;
}
/**
* Derive the value of the {@code cpuAbiOverride} based on the provided
* value and an optional stored value from the package settings.
*/
private static String deriveAbiOverride(String abiOverride, PackageSetting settings) {
String cpuAbiOverride = null;
if (NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(abiOverride)) {
cpuAbiOverride = null;
} else if (abiOverride != null) {
cpuAbiOverride = abiOverride;
} else if (settings != null) {
cpuAbiOverride = settings.cpuAbiOverrideString;
}
return cpuAbiOverride;
}
private PackageParser.Package scanPackageTracedLI(PackageParser.Package pkg,
final int policyFlags, int scanFlags, long currentTime, @Nullable UserHandle user)
throws PackageManagerException {
@@ -10102,8 +9825,9 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
if (shouldCheckUpgradeKeySetLP(signatureCheckPs, scanFlags)) {
if (checkUpgradeKeySetLP(signatureCheckPs, pkg)) {
final KeySetManagerService ksms = mSettings.mKeySetManagerService;
if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
if (ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) {
// We just determined the app is signed correctly, so bring
// over the latest parsed certs.
pkgSetting.signatures.mSignatures = pkg.mSignatures;
@@ -10121,8 +9845,16 @@ public class PackageManagerService extends IPackageManager.Stub
}
} else {
try {
// SIDE EFFECTS; compareSignaturesCompat() changes KeysetManagerService
verifySignaturesLP(signatureCheckPs, pkg);
final boolean compareCompat = isCompatSignatureUpdateNeeded(pkg);
final boolean compareRecover = isRecoverSignatureUpdateNeeded(pkg);
final boolean compatMatch = verifySignatures(signatureCheckPs, pkg.mSignatures,
compareCompat, compareRecover);
// The new KeySets will be re-added later in the scanning process.
if (compatMatch) {
synchronized (mPackages) {
ksms.removeAppKeySetDataLPw(pkg.packageName);
}
}
// We just determined the app is signed correctly, so bring
// over the latest parsed certs.
pkgSetting.signatures.mSignatures = pkg.mSignatures;
@@ -10410,7 +10142,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
// Make sure we're not adding any bogus keyset info
KeySetManagerService ksms = mSettings.mKeySetManagerService;
final KeySetManagerService ksms = mSettings.mKeySetManagerService;
ksms.assertScannedPackageValid(pkg);
synchronized (mPackages) {
@@ -15566,42 +15298,6 @@ public class PackageManagerService extends IPackageManager.Stub
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
private boolean shouldCheckUpgradeKeySetLP(PackageSettingBase oldPs, int scanFlags) {
// Can't rotate keys during boot or if sharedUser.
if (oldPs == null || (scanFlags&SCAN_INITIAL) != 0 || oldPs.isSharedUser()
|| !oldPs.keySetData.isUsingUpgradeKeySets()) {
return false;
}
// app is using upgradeKeySets; make sure all are valid
KeySetManagerService ksms = mSettings.mKeySetManagerService;
long[] upgradeKeySets = oldPs.keySetData.getUpgradeKeySets();
for (int i = 0; i < upgradeKeySets.length; i++) {
if (!ksms.isIdValidKeySetId(upgradeKeySets[i])) {
Slog.wtf(TAG, "Package "
+ (oldPs.name != null ? oldPs.name : "<null>")
+ " contains upgrade-key-set reference to unknown key-set: "
+ upgradeKeySets[i]
+ " reverting to signatures check.");
return false;
}
}
return true;
}
private boolean checkUpgradeKeySetLP(PackageSettingBase oldPS, PackageParser.Package newPkg) {
// Upgrade keysets are being used. Determine if new package has a superset of the
// required keys.
long[] upgradeKeySets = oldPS.keySetData.getUpgradeKeySets();
KeySetManagerService ksms = mSettings.mKeySetManagerService;
for (int i = 0; i < upgradeKeySets.length; i++) {
Set<PublicKey> upgradeSet = ksms.getPublicKeysFromKeySetLPr(upgradeKeySets[i]);
if (upgradeSet != null && newPkg.mSigningKeys.containsAll(upgradeSet)) {
return true;
}
}
return false;
}
private static void updateDigest(MessageDigest digest, File file) throws IOException {
try (DigestInputStream digestStream =
new DigestInputStream(new FileInputStream(file), digest)) {
@@ -15640,8 +15336,9 @@ public class PackageManagerService extends IPackageManager.Stub
ps = mSettings.mPackages.get(pkgName);
// verify signatures are valid
if (shouldCheckUpgradeKeySetLP(ps, scanFlags)) {
if (!checkUpgradeKeySetLP(ps, pkg)) {
final KeySetManagerService ksms = mSettings.mKeySetManagerService;
if (ksms.shouldCheckUpgradeKeySetLocked(ps, scanFlags)) {
if (!ksms.checkUpgradeKeySetLocked(ps, pkg)) {
res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
"New package not signed by keys specified by upgrade-keysets: "
+ pkgName);
@@ -16542,8 +16239,9 @@ public class PackageManagerService extends IPackageManager.Stub
// Quick sanity check that we're signed correctly if updating;
// we'll check this again later when scanning, but we want to
// bail early here before tripping over redefined permissions.
if (shouldCheckUpgradeKeySetLP(signatureCheckPs, scanFlags)) {
if (!checkUpgradeKeySetLP(signatureCheckPs, pkg)) {
final KeySetManagerService ksms = mSettings.mKeySetManagerService;
if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) {
res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
+ pkg.packageName + " upgrade keys do not match the "
+ "previously installed version");
@@ -16551,7 +16249,16 @@ public class PackageManagerService extends IPackageManager.Stub
}
} else {
try {
verifySignaturesLP(signatureCheckPs, pkg);
final boolean compareCompat = isCompatSignatureUpdateNeeded(pkg);
final boolean compareRecover = isRecoverSignatureUpdateNeeded(pkg);
final boolean compatMatch = verifySignatures(
signatureCheckPs, pkg.mSignatures, compareCompat, compareRecover);
// The new KeySets will be re-added later in the scanning process.
if (compatMatch) {
synchronized (mPackages) {
ksms.removeAppKeySetDataLPw(pkg.packageName);
}
}
} catch (PackageManagerException e) {
res.setError(e.error, e.getMessage());
return;
@@ -16589,10 +16296,11 @@ public class PackageManagerService extends IPackageManager.Stub
final boolean sigsOk;
final String sourcePackageName = bp.getSourcePackageName();
final PackageSettingBase sourcePackageSetting = bp.getSourcePackageSetting();
final KeySetManagerService ksms = mSettings.mKeySetManagerService;
if (sourcePackageName.equals(pkg.packageName)
&& (shouldCheckUpgradeKeySetLP(sourcePackageSetting,
scanFlags))) {
sigsOk = checkUpgradeKeySetLP(sourcePackageSetting, pkg);
&& (ksms.shouldCheckUpgradeKeySetLocked(
sourcePackageSetting, scanFlags))) {
sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, pkg);
} else {
sigsOk = compareSignatures(sourcePackageSetting.signatures.mSignatures,
pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;
@@ -20938,34 +20646,11 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
pw.println();
pw.println("Package warning messages:");
BufferedReader in = null;
String line = null;
try {
in = new BufferedReader(new FileReader(getSettingsProblemFile()));
while ((line = in.readLine()) != null) {
if (line.contains("ignored: updated version")) continue;
pw.println(line);
}
} catch (IOException ignored) {
} finally {
IoUtils.closeQuietly(in);
}
dumpCriticalInfo(pw, null);
}
if (checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES)) {
BufferedReader in = null;
String line = null;
try {
in = new BufferedReader(new FileReader(getSettingsProblemFile()));
while ((line = in.readLine()) != null) {
if (line.contains("ignored: updated version")) continue;
pw.print("msg,");
pw.println(line);
}
} catch (IOException ignored) {
} finally {
IoUtils.closeQuietly(in);
}
dumpCriticalInfo(pw, "msg,");
}
}
@@ -21011,26 +20696,11 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
dumpFeaturesProto(proto);
mSettings.dumpPackagesProto(proto);
mSettings.dumpSharedUsersProto(proto);
dumpMessagesProto(proto);
dumpCriticalInfo(proto);
}
proto.flush();
}
private void dumpMessagesProto(ProtoOutputStream proto) {
BufferedReader in = null;
String line = null;
try {
in = new BufferedReader(new FileReader(getSettingsProblemFile()));
while ((line = in.readLine()) != null) {
if (line.contains("ignored: updated version")) continue;
proto.write(PackageServiceDumpProto.MESSAGES, line);
}
} catch (IOException ignored) {
} finally {
IoUtils.closeQuietly(in);
}
}
private void dumpFeaturesProto(ProtoOutputStream proto) {
synchronized (mAvailableFeatures) {
final int count = mAvailableFeatures.size();
@@ -22439,7 +22109,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
Slog.w(TAG, "KeySet requested for filtered package: " + packageName);
throw new IllegalArgumentException("Unknown package: " + packageName);
}
KeySetManagerService ksms = mSettings.mKeySetManagerService;
final KeySetManagerService ksms = mSettings.mKeySetManagerService;
return new KeySet(ksms.getKeySetByAliasAndPackageNameLPr(packageName, alias));
}
}
@@ -22468,7 +22138,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
&& Process.SYSTEM_UID != callingUid) {
throw new SecurityException("May not access signing KeySet of other apps.");
}
KeySetManagerService ksms = mSettings.mKeySetManagerService;
final KeySetManagerService ksms = mSettings.mKeySetManagerService;
return new KeySet(ksms.getSigningKeySetByPackageNameLPr(packageName));
}
}
@@ -22492,7 +22162,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
}
IBinder ksh = ks.getToken();
if (ksh instanceof KeySetHandle) {
KeySetManagerService ksms = mSettings.mKeySetManagerService;
final KeySetManagerService ksms = mSettings.mKeySetManagerService;
return ksms.packageIsSignedByLPr(packageName, (KeySetHandle) ksh);
}
return false;
@@ -22518,7 +22188,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
}
IBinder ksh = ks.getToken();
if (ksh instanceof KeySetHandle) {
KeySetManagerService ksms = mSettings.mKeySetManagerService;
final KeySetManagerService ksms = mSettings.mKeySetManagerService;
return ksms.packageIsSignedByExactlyLPr(packageName, (KeySetHandle) ksh);
}
return false;

View File

@@ -16,42 +16,74 @@
package com.android.server.pm;
import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
import static com.android.server.pm.PackageManagerService.COMPRESSED_EXTENSION;
import static com.android.server.pm.PackageManagerService.DEBUG_COMPRESSION;
import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
import static com.android.server.pm.PackageManagerService.STUB_SUFFIX;
import static com.android.server.pm.PackageManagerService.TAG;
import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.server.EventLogTags;
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.PackageDexUsage;
import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
import static com.android.server.pm.PackageManagerService.TAG;
import com.android.internal.util.ArrayUtils;
import android.annotation.NonNull;
import android.app.AppGlobals;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
import android.os.Build;
import android.os.Debug;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.service.pm.PackageServiceDumpProto;
import android.system.ErrnoException;
import android.system.Os;
import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
import android.util.jar.StrictJarFile;
import dalvik.system.VMRuntime;
import libcore.io.Libcore;
import android.util.proto.ProtoOutputStream;
import dalvik.system.VMRuntime;
import libcore.io.IoUtils;
import libcore.io.Libcore;
import libcore.io.Streams;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Predicate;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipEntry;
/**
@@ -200,7 +232,7 @@ public class PackageManagerServiceUtils {
*
* If it doesn't have sufficient information about the package, it return <code>false</code>.
*/
static boolean isUnusedSinceTimeInMillis(long firstInstallTime, long currentTimeInMillis,
public static boolean isUnusedSinceTimeInMillis(long firstInstallTime, long currentTimeInMillis,
long thresholdTimeinMillis, PackageDexUsage.PackageUseInfo packageUseInfo,
long latestPackageUseTimeInMillis, long latestForegroundPackageUseTimeInMillis) {
@@ -263,6 +295,21 @@ public class PackageManagerServiceUtils {
return false;
}
public static long getLastModifiedTime(PackageParser.Package pkg, File srcFile) {
if (srcFile.isDirectory()) {
final File baseFile = new File(pkg.baseCodePath);
long maxModifiedTime = baseFile.lastModified();
if (pkg.splitCodePaths != null) {
for (int i = pkg.splitCodePaths.length - 1; i >=0; --i) {
final File splitFile = new File(pkg.splitCodePaths[i]);
maxModifiedTime = Math.max(maxModifiedTime, splitFile.lastModified());
}
}
return maxModifiedTime;
}
return srcFile.lastModified();
}
/**
* Checks that the archive located at {@code fileName} has uncompressed dex file and so
* files that can be direclty mapped.
@@ -318,6 +365,57 @@ public class PackageManagerServiceUtils {
}
}
private static File getSettingsProblemFile() {
File dataDir = Environment.getDataDirectory();
File systemDir = new File(dataDir, "system");
File fname = new File(systemDir, "uiderrors.txt");
return fname;
}
public static void dumpCriticalInfo(ProtoOutputStream proto) {
try (BufferedReader in = new BufferedReader(new FileReader(getSettingsProblemFile()))) {
String line = null;
while ((line = in.readLine()) != null) {
if (line.contains("ignored: updated version")) continue;
proto.write(PackageServiceDumpProto.MESSAGES, line);
}
} catch (IOException ignored) {
}
}
public static void dumpCriticalInfo(PrintWriter pw, String msg) {
try (BufferedReader in = new BufferedReader(new FileReader(getSettingsProblemFile()))) {
String line = null;
while ((line = in.readLine()) != null) {
if (line.contains("ignored: updated version")) continue;
if (msg != null) {
pw.print(msg);
}
pw.println(line);
}
} catch (IOException ignored) {
}
}
public static void logCriticalInfo(int priority, String msg) {
Slog.println(priority, TAG, msg);
EventLogTags.writePmCriticalInfo(msg);
try {
File fname = getSettingsProblemFile();
FileOutputStream out = new FileOutputStream(fname, true);
PrintWriter pw = new FastPrintWriter(out);
SimpleDateFormat formatter = new SimpleDateFormat();
String dateString = formatter.format(new Date(System.currentTimeMillis()));
pw.println(dateString + ": " + msg);
pw.close();
FileUtils.setPermissions(
fname.toString(),
FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IROTH,
-1, -1);
} catch (java.io.IOException e) {
}
}
public static void enforceShellRestriction(String restriction, int callingUid, int userHandle) {
if (callingUid == Process.SHELL_UID) {
if (userHandle >= 0
@@ -331,4 +429,240 @@ public class PackageManagerServiceUtils {
}
}
}
/**
* Derive the value of the {@code cpuAbiOverride} based on the provided
* value and an optional stored value from the package settings.
*/
public static String deriveAbiOverride(String abiOverride, PackageSetting settings) {
String cpuAbiOverride = null;
if (NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(abiOverride)) {
cpuAbiOverride = null;
} else if (abiOverride != null) {
cpuAbiOverride = abiOverride;
} else if (settings != null) {
cpuAbiOverride = settings.cpuAbiOverrideString;
}
return cpuAbiOverride;
}
/**
* Compares two sets of signatures. Returns:
* <br />
* {@link PackageManager#SIGNATURE_NEITHER_SIGNED}: if both signature sets are null,
* <br />
* {@link PackageManager#SIGNATURE_FIRST_NOT_SIGNED}: if the first signature set is null,
* <br />
* {@link PackageManager#SIGNATURE_SECOND_NOT_SIGNED}: if the second signature set is null,
* <br />
* {@link PackageManager#SIGNATURE_MATCH}: if the two signature sets are identical,
* <br />
* {@link PackageManager#SIGNATURE_NO_MATCH}: if the two signature sets differ.
*/
public static int compareSignatures(Signature[] s1, Signature[] s2) {
if (s1 == null) {
return s2 == null
? PackageManager.SIGNATURE_NEITHER_SIGNED
: PackageManager.SIGNATURE_FIRST_NOT_SIGNED;
}
if (s2 == null) {
return PackageManager.SIGNATURE_SECOND_NOT_SIGNED;
}
if (s1.length != s2.length) {
return PackageManager.SIGNATURE_NO_MATCH;
}
// Since both signature sets are of size 1, we can compare without HashSets.
if (s1.length == 1) {
return s1[0].equals(s2[0]) ?
PackageManager.SIGNATURE_MATCH :
PackageManager.SIGNATURE_NO_MATCH;
}
ArraySet<Signature> set1 = new ArraySet<Signature>();
for (Signature sig : s1) {
set1.add(sig);
}
ArraySet<Signature> set2 = new ArraySet<Signature>();
for (Signature sig : s2) {
set2.add(sig);
}
// Make sure s2 contains all signatures in s1.
if (set1.equals(set2)) {
return PackageManager.SIGNATURE_MATCH;
}
return PackageManager.SIGNATURE_NO_MATCH;
}
/**
* Used for backward compatibility to make sure any packages with
* certificate chains get upgraded to the new style. {@code existingSigs}
* will be in the old format (since they were stored on disk from before the
* system upgrade) and {@code scannedSigs} will be in the newer format.
*/
private static boolean matchSignaturesCompat(String packageName,
PackageSignatures packageSignatures, Signature[] parsedSignatures) {
ArraySet<Signature> existingSet = new ArraySet<Signature>();
for (Signature sig : packageSignatures.mSignatures) {
existingSet.add(sig);
}
ArraySet<Signature> scannedCompatSet = new ArraySet<Signature>();
for (Signature sig : parsedSignatures) {
try {
Signature[] chainSignatures = sig.getChainSignatures();
for (Signature chainSig : chainSignatures) {
scannedCompatSet.add(chainSig);
}
} catch (CertificateEncodingException e) {
scannedCompatSet.add(sig);
}
}
// make sure the expanded scanned set contains all signatures in the existing one
if (scannedCompatSet.equals(existingSet)) {
// migrate the old signatures to the new scheme
packageSignatures.assignSignatures(parsedSignatures);
return true;
}
return false;
}
private static boolean matchSignaturesRecover(String packageName,
Signature[] existingSignatures, Signature[] parsedSignatures) {
String msg = null;
try {
if (Signature.areEffectiveMatch(existingSignatures, parsedSignatures)) {
logCriticalInfo(Log.INFO,
"Recovered effectively matching certificates for " + packageName);
return true;
}
} catch (CertificateException e) {
msg = e.getMessage();
}
logCriticalInfo(Log.INFO,
"Failed to recover certificates for " + packageName + ": " + msg);
return false;
}
/**
* Verifies that signatures match.
* @returns {@code true} if the compat signatures were matched; otherwise, {@code false}.
* @throws PackageManagerException if the signatures did not match.
*/
public static boolean verifySignatures(PackageSetting pkgSetting,
Signature[] parsedSignatures, boolean compareCompat, boolean compareRecover)
throws PackageManagerException {
final String packageName = pkgSetting.name;
boolean compatMatch = false;
if (pkgSetting.signatures.mSignatures != null) {
// Already existing package. Make sure signatures match
boolean match = compareSignatures(pkgSetting.signatures.mSignatures, parsedSignatures)
== PackageManager.SIGNATURE_MATCH;
if (!match && compareCompat) {
match = matchSignaturesCompat(packageName, pkgSetting.signatures, parsedSignatures);
compatMatch = match;
}
if (!match && compareRecover) {
match = matchSignaturesRecover(
packageName, pkgSetting.signatures.mSignatures, parsedSignatures);
}
if (!match) {
throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
"Package " + packageName +
" signatures don't match previously installed version; ignoring!");
}
}
// Check for shared user signatures
if (pkgSetting.sharedUser != null && pkgSetting.sharedUser.signatures.mSignatures != null) {
// Already existing package. Make sure signatures match
boolean match = compareSignatures(pkgSetting.sharedUser.signatures.mSignatures,
parsedSignatures) == PackageManager.SIGNATURE_MATCH;
if (!match) {
match = matchSignaturesCompat(
packageName, pkgSetting.sharedUser.signatures, parsedSignatures);
}
if (!match && compareCompat) {
match = matchSignaturesRecover(
packageName, pkgSetting.sharedUser.signatures.mSignatures, parsedSignatures);
compatMatch |= match;
}
if (!match && compareRecover) {
throw new PackageManagerException(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
"Package " + packageName
+ " has no signatures that match those in shared user "
+ pkgSetting.sharedUser.name + "; ignoring!");
}
}
return compatMatch;
}
public static int decompressFile(File srcFile, File dstFile) throws ErrnoException {
if (DEBUG_COMPRESSION) {
Slog.i(TAG, "Decompress file"
+ "; src: " + srcFile.getAbsolutePath()
+ ", dst: " + dstFile.getAbsolutePath());
}
try (
InputStream fileIn = new GZIPInputStream(new FileInputStream(srcFile));
OutputStream fileOut = new FileOutputStream(dstFile, false /*append*/);
) {
Streams.copy(fileIn, fileOut);
Os.chmod(dstFile.getAbsolutePath(), 0644);
return PackageManager.INSTALL_SUCCEEDED;
} catch (IOException e) {
logCriticalInfo(Log.ERROR, "Failed to decompress file"
+ "; src: " + srcFile.getAbsolutePath()
+ ", dst: " + dstFile.getAbsolutePath());
}
return PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
}
public static File[] getCompressedFiles(String codePath) {
final File stubCodePath = new File(codePath);
final String stubName = stubCodePath.getName();
// The layout of a compressed package on a given partition is as follows :
//
// Compressed artifacts:
//
// /partition/ModuleName/foo.gz
// /partation/ModuleName/bar.gz
//
// Stub artifact:
//
// /partition/ModuleName-Stub/ModuleName-Stub.apk
//
// In other words, stub is on the same partition as the compressed artifacts
// and in a directory that's suffixed with "-Stub".
int idx = stubName.lastIndexOf(STUB_SUFFIX);
if (idx < 0 || (stubName.length() != (idx + STUB_SUFFIX.length()))) {
return null;
}
final File stubParentDir = stubCodePath.getParentFile();
if (stubParentDir == null) {
Slog.e(TAG, "Unable to determine stub parent dir for codePath: " + codePath);
return null;
}
final File compressedPath = new File(stubParentDir, stubName.substring(0, idx));
final File[] files = compressedPath.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(COMPRESSED_EXTENSION);
}
});
if (DEBUG_COMPRESSION && files != null && files.length > 0) {
Slog.i(TAG, "getCompressedFiles[" + codePath + "]: " + Arrays.toString(files));
}
return files;
}
public static boolean compressedFileExists(String codePath) {
final File[] compressedFiles = getCompressedFiles(codePath);
return compressedFiles != null && compressedFiles.length > 0;
}
}

View File

@@ -16,6 +16,8 @@
package com.android.server.pm;
import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
import android.content.Context;
import android.content.pm.UserInfo;
import android.os.Environment;
@@ -40,8 +42,6 @@ import java.util.List;
import java.util.Objects;
import java.util.Set;
import static com.android.server.pm.PackageManagerService.logCriticalInfo;
/**
* Helper class for preparing and destroying user storage
*/

View File

@@ -16,6 +16,8 @@
package com.android.server.pm.permission;
import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -1110,8 +1112,8 @@ public final class DefaultPermissionGrantPolicy {
final String systemPackageName = mServiceInternal.getKnownPackageName(
PackageManagerInternal.PACKAGE_SYSTEM, UserHandle.USER_SYSTEM);
final PackageParser.Package systemPackage = getPackage(systemPackageName);
return PackageManagerService.compareSignatures(systemPackage.mSignatures,
pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;
return compareSignatures(systemPackage.mSignatures, pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH;
}
private void grantDefaultPermissionExceptions(int userId) {

View File

@@ -1009,10 +1009,10 @@ Slog.e(TAG, "TODD: Packages: " + Arrays.toString(packages));
PackageManagerInternal.PACKAGE_SYSTEM, UserHandle.USER_SYSTEM);
final PackageParser.Package systemPackage =
mPackageManagerInt.getPackage(systemPackageName);
boolean allowed = (PackageManagerService.compareSignatures(
boolean allowed = (PackageManagerServiceUtils.compareSignatures(
bp.getSourceSignatures(), pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH)
|| (PackageManagerService.compareSignatures(
|| (PackageManagerServiceUtils.compareSignatures(
systemPackage.mSignatures, pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH);
if (!allowed && (privilegedPermission || oemPermission)) {