Merge changes from topic "MarkAPKInUpdateApexAsUpdatedSystemApp" into rvc-dev

* changes:
  Do not verify APKs out of updated APEXs
  Caches parsed package info for APEX
This commit is contained in:
Philip P. Moltmann
2020-03-26 23:08:47 +00:00
committed by Android (Google) Code Review
4 changed files with 225 additions and 128 deletions

View File

@@ -16,22 +16,22 @@
package com.android.server.pm; package com.android.server.pm;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import android.annotation.IntDef; import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.apex.ApexInfo; import android.apex.ApexInfo;
import android.apex.ApexInfoList; import android.apex.ApexInfoList;
import android.apex.ApexSessionInfo; import android.apex.ApexSessionInfo;
import android.apex.ApexSessionParams; import android.apex.ApexSessionParams;
import android.apex.IApexService; import android.apex.IApexService;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.PackageParser; import android.content.pm.PackageParser;
import android.content.pm.parsing.PackageInfoWithoutStateUtils;
import android.os.Environment; import android.os.Environment;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.ServiceManager; import android.os.ServiceManager;
@@ -44,8 +44,9 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.utils.TimingsTraceAndSlog; import com.android.server.utils.TimingsTraceAndSlog;
@@ -61,7 +62,9 @@ import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@@ -72,7 +75,7 @@ public abstract class ApexManager {
private static final String TAG = "ApexManager"; private static final String TAG = "ApexManager";
static final int MATCH_ACTIVE_PACKAGE = 1 << 0; public static final int MATCH_ACTIVE_PACKAGE = 1 << 0;
static final int MATCH_FACTORY_PACKAGE = 1 << 1; static final int MATCH_FACTORY_PACKAGE = 1 << 1;
private static final Singleton<ApexManager> sApexManagerSingleton = private static final Singleton<ApexManager> sApexManagerSingleton =
@@ -139,7 +142,14 @@ public abstract class ApexManager {
*/ */
public abstract List<ActiveApexInfo> getActiveApexInfos(); public abstract List<ActiveApexInfo> getActiveApexInfos();
abstract void systemReady(Context context); /**
* Called by package manager service to scan apex package files when device boots up.
*
* @param packageParser The package parser which supports caches.
* @param executorService An executor to support parallel package parsing.
*/
abstract void scanApexPackagesTraced(@NonNull PackageParser2 packageParser,
@NonNull ExecutorService executorService);
/** /**
* Retrieves information about an APEX package. * Retrieves information about an APEX package.
@@ -154,7 +164,7 @@ public abstract class ApexManager {
* is not found. * is not found.
*/ */
@Nullable @Nullable
abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags); public abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags);
/** /**
* Retrieves information about all active APEX packages. * Retrieves information about all active APEX packages.
@@ -188,6 +198,27 @@ public abstract class ApexManager {
*/ */
abstract boolean isApexPackage(String packageName); abstract boolean isApexPackage(String packageName);
/**
* Whether the APEX package is pre-installed or not.
*
* @param packageInfo the package to check
* @return {@code true} if this package is pre-installed, {@code false} otherwise.
*/
public static boolean isFactory(@NonNull PackageInfo packageInfo) {
return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
}
/**
* Returns the active apex package's name that contains the (apk) package.
*
* @param containedPackage The (apk) package that might be in a apex
* @return the apex package's name of {@code null} if the {@code containedPackage} is not inside
* any apex.
*/
@Nullable
public abstract String getActiveApexPackageNameContainingPackage(
@NonNull AndroidPackage containedPackage);
/** /**
* Retrieves information about an apexd staged session i.e. the internal state used by apexd to * Retrieves information about an apexd staged session i.e. the internal state used by apexd to
* track the different states of a session. * track the different states of a session.
@@ -342,7 +373,7 @@ public abstract class ApexManager {
* difference between {@code packageName} and {@code apexModuleName}. * difference between {@code packageName} and {@code apexModuleName}.
*/ */
@GuardedBy("mLock") @GuardedBy("mLock")
private Map<String, List<String>> mApksInApex = new ArrayMap<>(); private ArrayMap<String, List<String>> mApksInApex = new ArrayMap<>();
@GuardedBy("mLock") @GuardedBy("mLock")
private List<PackageInfo> mAllPackagesCache; private List<PackageInfo> mAllPackagesCache;
@@ -357,7 +388,7 @@ public abstract class ApexManager {
* the apk container to {@code apexModuleName} of the apex-payload inside. * the apk container to {@code apexModuleName} of the apex-payload inside.
*/ */
@GuardedBy("mLock") @GuardedBy("mLock")
private Map<String, String> mPackageNameToApexModuleName; private ArrayMap<String, String> mPackageNameToApexModuleName;
ApexManagerImpl(IApexService apexService) { ApexManagerImpl(IApexService apexService) {
mApexService = apexService; mApexService = apexService;
@@ -373,16 +404,6 @@ public abstract class ApexManager {
return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0; return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0;
} }
/**
* Whether the APEX package is pre-installed or not.
*
* @param packageInfo the package to check
* @return {@code true} if this package is pre-installed, {@code false} otherwise.
*/
private static boolean isFactory(PackageInfo packageInfo) {
return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
}
@Override @Override
public List<ActiveApexInfo> getActiveApexInfos() { public List<ActiveApexInfo> getActiveApexInfos() {
final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing", final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
@@ -411,104 +432,94 @@ public abstract class ApexManager {
} }
@Override @Override
void systemReady(Context context) { void scanApexPackagesTraced(@NonNull PackageParser2 packageParser,
context.registerReceiver(new BroadcastReceiver() { @NonNull ExecutorService executorService) {
@Override Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanApexPackagesTraced");
public void onReceive(Context context, Intent intent) { try {
// Post populateAllPackagesCacheIfNeeded to a background thread, since it's synchronized (mLock) {
// expensive to run it in broadcast handler thread. scanApexPackagesInternalLocked(packageParser, executorService);
BackgroundThread.getHandler().post(() -> populateAllPackagesCacheIfNeeded());
context.unregisterReceiver(this);
}
}, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
}
private void populatePackageNameToApexModuleNameIfNeeded() {
synchronized (mLock) {
if (mPackageNameToApexModuleName != null) {
return;
}
try {
mPackageNameToApexModuleName = new ArrayMap<>();
final ApexInfo[] allPkgs = mApexService.getAllPackages();
for (int i = 0; i < allPkgs.length; i++) {
ApexInfo ai = allPkgs[i];
PackageParser.PackageLite pkgLite;
try {
File apexFile = new File(ai.modulePath);
pkgLite = PackageParser.parsePackageLite(apexFile, 0);
} catch (PackageParser.PackageParserException pe) {
throw new IllegalStateException("Unable to parse: "
+ ai.modulePath, pe);
}
mPackageNameToApexModuleName.put(pkgLite.packageName, ai.moduleName);
}
} catch (RemoteException re) {
Slog.e(TAG, "Unable to retrieve packages from apexservice: ", re);
throw new RuntimeException(re);
} }
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
} }
} }
private void populateAllPackagesCacheIfNeeded() { @GuardedBy("mLock")
synchronized (mLock) { private void scanApexPackagesInternalLocked(PackageParser2 packageParser,
if (mAllPackagesCache != null) { ExecutorService executorService) {
return; final ApexInfo[] allPkgs;
} try {
try { mAllPackagesCache = new ArrayList<>();
mAllPackagesCache = new ArrayList<>(); mPackageNameToApexModuleName = new ArrayMap<>();
HashSet<String> activePackagesSet = new HashSet<>(); allPkgs = mApexService.getAllPackages();
HashSet<String> factoryPackagesSet = new HashSet<>(); } catch (RemoteException re) {
final ApexInfo[] allPkgs = mApexService.getAllPackages(); Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString());
for (ApexInfo ai : allPkgs) { throw new RuntimeException(re);
// If the device is using flattened APEX, don't report any APEX }
// packages since they won't be managed or updated by PackageManager. if (allPkgs.length == 0) {
if ((new File(ai.modulePath)).isDirectory()) { return;
break; }
} int flags = PackageManager.GET_META_DATA
int flags = PackageManager.GET_META_DATA | PackageManager.GET_SIGNING_CERTIFICATES
| PackageManager.GET_SIGNING_CERTIFICATES | PackageManager.GET_SIGNATURES;
| PackageManager.GET_SIGNATURES; ArrayMap<File, ApexInfo> parsingApexInfo = new ArrayMap<>();
PackageParser.Package pkg; ParallelPackageParser parallelPackageParser =
try { new ParallelPackageParser(packageParser, executorService);
File apexFile = new File(ai.modulePath);
PackageParser pp = new PackageParser();
pkg = pp.parsePackage(apexFile, flags, false);
PackageParser.collectCertificates(pkg, false);
} catch (PackageParser.PackageParserException pe) {
throw new IllegalStateException("Unable to parse: " + ai, pe);
}
final PackageInfo packageInfo = for (ApexInfo ai : allPkgs) {
PackageParser.generatePackageInfo(pkg, ai, flags); File apexFile = new File(ai.modulePath);
mAllPackagesCache.add(packageInfo); parallelPackageParser.submit(apexFile, flags);
if (ai.isActive) { parsingApexInfo.put(apexFile, ai);
if (activePackagesSet.contains(packageInfo.packageName)) { }
throw new IllegalStateException(
"Two active packages have the same name: " HashSet<String> activePackagesSet = new HashSet<>();
+ packageInfo.packageName); HashSet<String> factoryPackagesSet = new HashSet<>();
} // Process results one by one
activePackagesSet.add(packageInfo.packageName); for (int i = 0; i < parsingApexInfo.size(); i++) {
} ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
if (ai.isFactory) { Throwable throwable = parseResult.throwable;
if (factoryPackagesSet.contains(packageInfo.packageName)) { ApexInfo ai = parsingApexInfo.get(parseResult.scanFile);
throw new IllegalStateException(
"Two factory packages have the same name: " if (throwable == null) {
+ packageInfo.packageName); final PackageInfo packageInfo = PackageInfoWithoutStateUtils.generate(
} parseResult.parsedPackage, ai, flags);
factoryPackagesSet.add(packageInfo.packageName); if (packageInfo == null) {
} throw new IllegalStateException("Unable to generate package info: "
+ ai.modulePath);
} }
} catch (RemoteException re) { mAllPackagesCache.add(packageInfo);
Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString()); mPackageNameToApexModuleName.put(packageInfo.packageName, ai.moduleName);
throw new RuntimeException(re); if (ai.isActive) {
if (activePackagesSet.contains(packageInfo.packageName)) {
throw new IllegalStateException(
"Two active packages have the same name: "
+ packageInfo.packageName);
}
activePackagesSet.add(packageInfo.packageName);
}
if (ai.isFactory) {
if (factoryPackagesSet.contains(packageInfo.packageName)) {
throw new IllegalStateException(
"Two factory packages have the same name: "
+ packageInfo.packageName);
}
factoryPackagesSet.add(packageInfo.packageName);
}
} else if (throwable instanceof PackageParser.PackageParserException) {
throw new IllegalStateException("Unable to parse: " + ai.modulePath, throwable);
} else {
throw new IllegalStateException("Unexpected exception occurred while parsing "
+ ai.modulePath, throwable);
} }
} }
} }
@Override @Override
@Nullable PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags) { @Nullable
populateAllPackagesCacheIfNeeded(); public PackageInfo getPackageInfo(String packageName,
@PackageInfoFlags int flags) {
Preconditions.checkState(mAllPackagesCache != null,
"APEX packages have not been scanned");
boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0; boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0;
boolean matchFactory = (flags & MATCH_FACTORY_PACKAGE) != 0; boolean matchFactory = (flags & MATCH_FACTORY_PACKAGE) != 0;
for (PackageInfo packageInfo: mAllPackagesCache) { for (PackageInfo packageInfo: mAllPackagesCache) {
@@ -525,7 +536,8 @@ public abstract class ApexManager {
@Override @Override
List<PackageInfo> getActivePackages() { List<PackageInfo> getActivePackages() {
populateAllPackagesCacheIfNeeded(); Preconditions.checkState(mAllPackagesCache != null,
"APEX packages have not been scanned");
return mAllPackagesCache return mAllPackagesCache
.stream() .stream()
.filter(item -> isActive(item)) .filter(item -> isActive(item))
@@ -534,7 +546,8 @@ public abstract class ApexManager {
@Override @Override
List<PackageInfo> getFactoryPackages() { List<PackageInfo> getFactoryPackages() {
populateAllPackagesCacheIfNeeded(); Preconditions.checkState(mAllPackagesCache != null,
"APEX packages have not been scanned");
return mAllPackagesCache return mAllPackagesCache
.stream() .stream()
.filter(item -> isFactory(item)) .filter(item -> isFactory(item))
@@ -543,7 +556,8 @@ public abstract class ApexManager {
@Override @Override
List<PackageInfo> getInactivePackages() { List<PackageInfo> getInactivePackages() {
populateAllPackagesCacheIfNeeded(); Preconditions.checkState(mAllPackagesCache != null,
"APEX packages have not been scanned");
return mAllPackagesCache return mAllPackagesCache
.stream() .stream()
.filter(item -> !isActive(item)) .filter(item -> !isActive(item))
@@ -553,7 +567,8 @@ public abstract class ApexManager {
@Override @Override
boolean isApexPackage(String packageName) { boolean isApexPackage(String packageName) {
if (!isApexSupported()) return false; if (!isApexSupported()) return false;
populateAllPackagesCacheIfNeeded(); Preconditions.checkState(mAllPackagesCache != null,
"APEX packages have not been scanned");
for (PackageInfo packageInfo : mAllPackagesCache) { for (PackageInfo packageInfo : mAllPackagesCache) {
if (packageInfo.packageName.equals(packageName)) { if (packageInfo.packageName.equals(packageName)) {
return true; return true;
@@ -562,6 +577,36 @@ public abstract class ApexManager {
return false; return false;
} }
@Override
@Nullable
public String getActiveApexPackageNameContainingPackage(
@NonNull AndroidPackage containedPackage) {
Preconditions.checkState(mPackageNameToApexModuleName != null,
"APEX packages have not been scanned");
Objects.requireNonNull(containedPackage);
synchronized (mLock) {
int numApksInApex = mApksInApex.size();
for (int apkInApexNum = 0; apkInApexNum < numApksInApex; apkInApexNum++) {
if (mApksInApex.valueAt(apkInApexNum).contains(
containedPackage.getPackageName())) {
String apexModuleName = mApksInApex.keyAt(apkInApexNum);
int numApexPkgs = mPackageNameToApexModuleName.size();
for (int apexPkgNum = 0; apexPkgNum < numApexPkgs; apexPkgNum++) {
if (mPackageNameToApexModuleName.valueAt(apexPkgNum).equals(
apexModuleName)) {
return mPackageNameToApexModuleName.keyAt(apexPkgNum);
}
}
}
}
}
return null;
}
@Override @Override
@Nullable ApexSessionInfo getStagedSessionInfo(int sessionId) { @Nullable ApexSessionInfo getStagedSessionInfo(int sessionId) {
try { try {
@@ -684,8 +729,9 @@ public abstract class ApexManager {
@Override @Override
List<String> getApksInApex(String apexPackageName) { List<String> getApksInApex(String apexPackageName) {
populatePackageNameToApexModuleNameIfNeeded();
synchronized (mLock) { synchronized (mLock) {
Preconditions.checkState(mPackageNameToApexModuleName != null,
"APEX packages have not been scanned");
String moduleName = mPackageNameToApexModuleName.get(apexPackageName); String moduleName = mPackageNameToApexModuleName.get(apexPackageName);
if (moduleName == null) { if (moduleName == null) {
return Collections.emptyList(); return Collections.emptyList();
@@ -697,17 +743,19 @@ public abstract class ApexManager {
@Override @Override
@Nullable @Nullable
public String getApexModuleNameForPackageName(String apexPackageName) { public String getApexModuleNameForPackageName(String apexPackageName) {
populatePackageNameToApexModuleNameIfNeeded();
synchronized (mLock) { synchronized (mLock) {
Preconditions.checkState(mPackageNameToApexModuleName != null,
"APEX packages have not been scanned");
return mPackageNameToApexModuleName.get(apexPackageName); return mPackageNameToApexModuleName.get(apexPackageName);
} }
} }
@Override @Override
public long snapshotCeData(int userId, int rollbackId, String apexPackageName) { public long snapshotCeData(int userId, int rollbackId, String apexPackageName) {
populatePackageNameToApexModuleNameIfNeeded();
String apexModuleName; String apexModuleName;
synchronized (mLock) { synchronized (mLock) {
Preconditions.checkState(mPackageNameToApexModuleName != null,
"APEX packages have not been scanned");
apexModuleName = mPackageNameToApexModuleName.get(apexPackageName); apexModuleName = mPackageNameToApexModuleName.get(apexPackageName);
} }
if (apexModuleName == null) { if (apexModuleName == null) {
@@ -724,9 +772,10 @@ public abstract class ApexManager {
@Override @Override
public boolean restoreCeData(int userId, int rollbackId, String apexPackageName) { public boolean restoreCeData(int userId, int rollbackId, String apexPackageName) {
populatePackageNameToApexModuleNameIfNeeded();
String apexModuleName; String apexModuleName;
synchronized (mLock) { synchronized (mLock) {
Preconditions.checkState(mPackageNameToApexModuleName != null,
"APEX packages have not been scanned");
apexModuleName = mPackageNameToApexModuleName.get(apexPackageName); apexModuleName = mPackageNameToApexModuleName.get(apexPackageName);
} }
if (apexModuleName == null) { if (apexModuleName == null) {
@@ -797,15 +846,7 @@ public abstract class ApexManager {
void dump(PrintWriter pw, @Nullable String packageName) { void dump(PrintWriter pw, @Nullable String packageName) {
final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120); final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
try { try {
populateAllPackagesCacheIfNeeded();
ipw.println(); ipw.println();
ipw.println("Active APEX packages:");
dumpFromPackagesCache(getActivePackages(), packageName, ipw);
ipw.println("Inactive APEX packages:");
dumpFromPackagesCache(getInactivePackages(), packageName, ipw);
ipw.println("Factory APEX packages:");
dumpFromPackagesCache(getFactoryPackages(), packageName, ipw);
ipw.increaseIndent();
ipw.println("APEX session state:"); ipw.println("APEX session state:");
ipw.increaseIndent(); ipw.increaseIndent();
final ApexSessionInfo[] sessions = mApexService.getSessions(); final ApexSessionInfo[] sessions = mApexService.getSessions();
@@ -834,6 +875,17 @@ public abstract class ApexManager {
ipw.decreaseIndent(); ipw.decreaseIndent();
} }
ipw.decreaseIndent(); ipw.decreaseIndent();
ipw.println();
if (mAllPackagesCache == null) {
ipw.println("APEX packages have not been scanned");
return;
}
ipw.println("Active APEX packages:");
dumpFromPackagesCache(getActivePackages(), packageName, ipw);
ipw.println("Inactive APEX packages:");
dumpFromPackagesCache(getInactivePackages(), packageName, ipw);
ipw.println("Factory APEX packages:");
dumpFromPackagesCache(getFactoryPackages(), packageName, ipw);
} catch (RemoteException e) { } catch (RemoteException e) {
ipw.println("Couldn't communicate with apexd."); ipw.println("Couldn't communicate with apexd.");
} }
@@ -879,12 +931,13 @@ public abstract class ApexManager {
} }
@Override @Override
void systemReady(Context context) { void scanApexPackagesTraced(@NonNull PackageParser2 packageParser,
@NonNull ExecutorService executorService) {
// No-op // No-op
} }
@Override @Override
PackageInfo getPackageInfo(String packageName, int flags) { public PackageInfo getPackageInfo(String packageName, int flags) {
return null; return null;
} }
@@ -908,6 +961,15 @@ public abstract class ApexManager {
return false; return false;
} }
@Override
@Nullable
public String getActiveApexPackageNameContainingPackage(
@NonNull AndroidPackage containedPackage) {
Objects.requireNonNull(containedPackage);
return null;
}
@Override @Override
ApexSessionInfo getStagedSessionInfo(int sessionId) { ApexSessionInfo getStagedSessionInfo(int sessionId) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();

View File

@@ -2900,6 +2900,9 @@ public class PackageManagerService extends IPackageManager.Stub
mMetrics, mCacheDir, mPackageParserCallback); mMetrics, mCacheDir, mPackageParserCallback);
ExecutorService executorService = ParallelPackageParser.makeExecutorService(); ExecutorService executorService = ParallelPackageParser.makeExecutorService();
// Prepare apex package info before scanning APKs, these information are needed when
// scanning apk in apex.
mApexManager.scanApexPackagesTraced(packageParser, executorService);
// Collect vendor/product/system_ext overlay packages. (Do this before scanning // Collect vendor/product/system_ext overlay packages. (Do this before scanning
// any apps.) // any apps.)
// For security and version matching reason, only consider overlay packages if they // For security and version matching reason, only consider overlay packages if they
@@ -20696,7 +20699,6 @@ public class PackageManagerService extends IPackageManager.Stub
storage.registerListener(mStorageListener); storage.registerListener(mStorageListener);
mInstallerService.systemReady(); mInstallerService.systemReady();
mApexManager.systemReady(mContext);
mPackageDexOptimizer.systemReady(); mPackageDexOptimizer.systemReady();
mInjector.getStorageManagerInternal().addExternalStoragePolicy( mInjector.getStorageManagerInternal().addExternalStoragePolicy(

View File

@@ -42,6 +42,7 @@ import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.permission.PermissionManager.KILL_APP_REASON_GIDS_CHANGED; import static android.permission.PermissionManager.KILL_APP_REASON_GIDS_CHANGED;
import static android.permission.PermissionManager.KILL_APP_REASON_PERMISSIONS_REVOKED; import static android.permission.PermissionManager.KILL_APP_REASON_PERMISSIONS_REVOKED;
import static com.android.server.pm.ApexManager.MATCH_ACTIVE_PACKAGE;
import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL; import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING; import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING;
import static com.android.server.pm.PackageManagerService.DEBUG_PERMISSIONS; import static com.android.server.pm.PackageManagerService.DEBUG_PERMISSIONS;
@@ -130,6 +131,7 @@ import com.android.server.LocalServices;
import com.android.server.ServiceThread; import com.android.server.ServiceThread;
import com.android.server.SystemConfig; import com.android.server.SystemConfig;
import com.android.server.Watchdog; import com.android.server.Watchdog;
import com.android.server.pm.ApexManager;
import com.android.server.pm.PackageManagerServiceUtils; import com.android.server.pm.PackageManagerServiceUtils;
import com.android.server.pm.PackageSetting; import com.android.server.pm.PackageSetting;
import com.android.server.pm.SharedUserSetting; import com.android.server.pm.SharedUserSetting;
@@ -3317,8 +3319,16 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (!privappPermissionsDisable && privilegedPermission && pkg.isPrivileged() if (!privappPermissionsDisable && privilegedPermission && pkg.isPrivileged()
&& !platformPackage && platformPermission) { && !platformPackage && platformPermission) {
if (!hasPrivappWhitelistEntry(perm, pkg)) { if (!hasPrivappWhitelistEntry(perm, pkg)) {
// Only report violations for apps on system image ApexManager apexMgr = ApexManager.getInstance();
if (!mSystemReady && !pkgSetting.getPkgState().isUpdatedSystemApp()) { String apexContainingPkg = apexMgr.getActiveApexPackageNameContainingPackage(pkg);
// Only enforce whitelist this on boot
if (!mSystemReady
// Updated system apps do not need to be whitelisted
&& !pkgSetting.getPkgState().isUpdatedSystemApp()
// Apps that are in updated apexs' do not need to be whitelisted
&& (apexContainingPkg == null || apexMgr.isFactory(
apexMgr.getPackageInfo(apexContainingPkg, MATCH_ACTIVE_PACKAGE)))) {
// it's only a reportable violation if the permission isn't explicitly denied // it's only a reportable violation if the permission isn't explicitly denied
ArraySet<String> deniedPermissions = null; ArraySet<String> deniedPermissions = null;
if (pkg.isVendor()) { if (pkg.isVendor()) {

View File

@@ -43,6 +43,7 @@ import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4; import androidx.test.runner.AndroidJUnit4;
import com.android.frameworks.servicestests.R; import com.android.frameworks.servicestests.R;
import com.android.server.pm.parsing.PackageParser2;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -63,6 +64,7 @@ public class ApexManagerTest {
private static final int[] TEST_CHILD_SESSION_ID = {8888, 7777}; private static final int[] TEST_CHILD_SESSION_ID = {8888, 7777};
private ApexManager mApexManager; private ApexManager mApexManager;
private Context mContext; private Context mContext;
private PackageParser2 mPackageParser2;
private IApexService mApexService = mock(IApexService.class); private IApexService mApexService = mock(IApexService.class);
@@ -70,11 +72,14 @@ public class ApexManagerTest {
public void setUp() throws RemoteException { public void setUp() throws RemoteException {
mContext = InstrumentationRegistry.getInstrumentation().getContext(); mContext = InstrumentationRegistry.getInstrumentation().getContext();
mApexManager = new ApexManager.ApexManagerImpl(mApexService); mApexManager = new ApexManager.ApexManagerImpl(mApexService);
mPackageParser2 = new PackageParser2(null, false, null, null, null);
} }
@Test @Test
public void testGetPackageInfo_setFlagsMatchActivePackage() throws RemoteException { public void testGetPackageInfo_setFlagsMatchActivePackage() throws RemoteException {
when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false)); when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false));
mApexManager.scanApexPackagesTraced(mPackageParser2,
ParallelPackageParser.makeExecutorService());
final PackageInfo activePkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG, final PackageInfo activePkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG,
ApexManager.MATCH_ACTIVE_PACKAGE); ApexManager.MATCH_ACTIVE_PACKAGE);
@@ -90,6 +95,8 @@ public class ApexManagerTest {
@Test @Test
public void testGetPackageInfo_setFlagsMatchFactoryPackage() throws RemoteException { public void testGetPackageInfo_setFlagsMatchFactoryPackage() throws RemoteException {
when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true)); when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
mApexManager.scanApexPackagesTraced(mPackageParser2,
ParallelPackageParser.makeExecutorService());
PackageInfo factoryPkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG, PackageInfo factoryPkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG,
ApexManager.MATCH_FACTORY_PACKAGE); ApexManager.MATCH_FACTORY_PACKAGE);
@@ -105,6 +112,8 @@ public class ApexManagerTest {
@Test @Test
public void testGetPackageInfo_setFlagsNone() throws RemoteException { public void testGetPackageInfo_setFlagsNone() throws RemoteException {
when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true)); when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
mApexManager.scanApexPackagesTraced(mPackageParser2,
ParallelPackageParser.makeExecutorService());
assertThat(mApexManager.getPackageInfo(TEST_APEX_PKG, 0)).isNull(); assertThat(mApexManager.getPackageInfo(TEST_APEX_PKG, 0)).isNull();
} }
@@ -112,6 +121,8 @@ public class ApexManagerTest {
@Test @Test
public void testGetActivePackages() throws RemoteException { public void testGetActivePackages() throws RemoteException {
when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, true)); when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, true));
mApexManager.scanApexPackagesTraced(mPackageParser2,
ParallelPackageParser.makeExecutorService());
assertThat(mApexManager.getActivePackages()).isNotEmpty(); assertThat(mApexManager.getActivePackages()).isNotEmpty();
} }
@@ -119,6 +130,8 @@ public class ApexManagerTest {
@Test @Test
public void testGetActivePackages_noneActivePackages() throws RemoteException { public void testGetActivePackages_noneActivePackages() throws RemoteException {
when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true)); when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
mApexManager.scanApexPackagesTraced(mPackageParser2,
ParallelPackageParser.makeExecutorService());
assertThat(mApexManager.getActivePackages()).isEmpty(); assertThat(mApexManager.getActivePackages()).isEmpty();
} }
@@ -126,6 +139,8 @@ public class ApexManagerTest {
@Test @Test
public void testGetFactoryPackages() throws RemoteException { public void testGetFactoryPackages() throws RemoteException {
when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true)); when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
mApexManager.scanApexPackagesTraced(mPackageParser2,
ParallelPackageParser.makeExecutorService());
assertThat(mApexManager.getFactoryPackages()).isNotEmpty(); assertThat(mApexManager.getFactoryPackages()).isNotEmpty();
} }
@@ -133,6 +148,8 @@ public class ApexManagerTest {
@Test @Test
public void testGetFactoryPackages_noneFactoryPackages() throws RemoteException { public void testGetFactoryPackages_noneFactoryPackages() throws RemoteException {
when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false)); when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false));
mApexManager.scanApexPackagesTraced(mPackageParser2,
ParallelPackageParser.makeExecutorService());
assertThat(mApexManager.getFactoryPackages()).isEmpty(); assertThat(mApexManager.getFactoryPackages()).isEmpty();
} }
@@ -140,6 +157,8 @@ public class ApexManagerTest {
@Test @Test
public void testGetInactivePackages() throws RemoteException { public void testGetInactivePackages() throws RemoteException {
when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true)); when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
mApexManager.scanApexPackagesTraced(mPackageParser2,
ParallelPackageParser.makeExecutorService());
assertThat(mApexManager.getInactivePackages()).isNotEmpty(); assertThat(mApexManager.getInactivePackages()).isNotEmpty();
} }
@@ -147,6 +166,8 @@ public class ApexManagerTest {
@Test @Test
public void testGetInactivePackages_noneInactivePackages() throws RemoteException { public void testGetInactivePackages_noneInactivePackages() throws RemoteException {
when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false)); when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false));
mApexManager.scanApexPackagesTraced(mPackageParser2,
ParallelPackageParser.makeExecutorService());
assertThat(mApexManager.getInactivePackages()).isEmpty(); assertThat(mApexManager.getInactivePackages()).isEmpty();
} }
@@ -154,6 +175,8 @@ public class ApexManagerTest {
@Test @Test
public void testIsApexPackage() throws RemoteException { public void testIsApexPackage() throws RemoteException {
when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true)); when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
mApexManager.scanApexPackagesTraced(mPackageParser2,
ParallelPackageParser.makeExecutorService());
assertThat(mApexManager.isApexPackage(TEST_APEX_PKG)).isTrue(); assertThat(mApexManager.isApexPackage(TEST_APEX_PKG)).isTrue();
} }