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:
committed by
Android (Google) Code Review
commit
8df5b601a2
@@ -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();
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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()) {
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user