Important migration for new ParsingPackage/ParsedPackage split

Part of the Parsing/ParsedPackage split into core/server.

This splits all the "important" changes, or those which change
significant code/logic and that requires a closer look during
review.

Bug: 135203078

Test: enumerated in first commit of change ID
		Ib4fe51d729a56bfb0ea1316e577358ba0dfceccf

Change-Id: Ie0e4394de2b3063121d850060fcd58622511c59d
This commit is contained in:
Winson
2020-01-24 11:56:44 -08:00
parent 01e38f40c2
commit e23ae20e30
25 changed files with 1878 additions and 1104 deletions

View File

@@ -79,14 +79,10 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.os.PatternMatcher;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.system.ErrnoException;
import android.system.OsConstants;
import android.system.StructStat;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -118,7 +114,6 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -316,8 +311,8 @@ public class PackageParser {
public int mParseError = PackageManager.INSTALL_SUCCEEDED;
public ThreadLocal<ApkParseUtils.ParseResult> mSharedResult
= ThreadLocal.withInitial(ApkParseUtils.ParseResult::new);
public ThreadLocal<ParsingPackageUtils.ParseResult> mSharedResult
= ThreadLocal.withInitial(ParsingPackageUtils.ParseResult::new);
public static boolean sCompatibilityModeEnabled = true;
public static boolean sUseRoundIcon = false;
@@ -1054,7 +1049,7 @@ public class PackageParser {
* and unique split names.
* <p>
* Note that this <em>does not</em> perform signature verification; that
* must be done separately in {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}.
* must be done separately in {@link #collectCertificates(Package, boolean)}.
*
* If {@code useCaches} is true, the package parser might return a cached
* result from a previous parse of the same {@code packageFile} with the same
@@ -1081,201 +1076,6 @@ public class PackageParser {
return parsePackage(packageFile, flags, false /* useCaches */);
}
/**
* Updated method which returns {@link ParsedPackage}, the current representation of a
* package parsed from disk.
*
* @see #parsePackage(File, int, boolean)
*/
@AnyThread
public ParsedPackage parseParsedPackage(File packageFile, int flags, boolean useCaches)
throws PackageParserException {
ParsedPackage parsed = useCaches ? getCachedResult(packageFile, flags) : null;
if (parsed != null) {
return parsed;
}
long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
ApkParseUtils.ParseInput parseInput = mSharedResult.get().reset();
parsed = ApkParseUtils.parsePackage(
parseInput,
mSeparateProcesses,
mCallback,
mMetrics,
mOnlyCoreApps,
packageFile,
flags
)
.hideAsParsed();
long cacheTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
cacheResult(packageFile, flags, parsed);
if (LOG_PARSE_TIMINGS) {
parseTime = cacheTime - parseTime;
cacheTime = SystemClock.uptimeMillis() - cacheTime;
if (parseTime + cacheTime > LOG_PARSE_TIMINGS_THRESHOLD_MS) {
Slog.i(TAG, "Parse times for '" + packageFile + "': parse=" + parseTime
+ "ms, update_cache=" + cacheTime + " ms");
}
}
return parsed;
}
/**
* Returns the cache key for a specified {@code packageFile} and {@code flags}.
*/
private String getCacheKey(File packageFile, int flags) {
StringBuilder sb = new StringBuilder(packageFile.getName());
sb.append('-');
sb.append(flags);
return sb.toString();
}
@VisibleForTesting
protected ParsedPackage fromCacheEntry(byte[] bytes) {
return fromCacheEntryStatic(bytes);
}
/** static version of {@link #fromCacheEntry} for unit tests. */
@VisibleForTesting
public static ParsedPackage fromCacheEntryStatic(byte[] bytes) {
final Parcel p = Parcel.obtain();
p.unmarshall(bytes, 0, bytes.length);
p.setDataPosition(0);
final ReadHelper helper = new ReadHelper(p);
helper.startAndInstall();
// TODO(b/135203078): Hide PackageImpl constructor?
ParsedPackage pkg = new PackageImpl(p);
p.recycle();
sCachedPackageReadCount.incrementAndGet();
return pkg;
}
@VisibleForTesting
protected byte[] toCacheEntry(ParsedPackage pkg) {
return toCacheEntryStatic(pkg);
}
/** static version of {@link #toCacheEntry} for unit tests. */
@VisibleForTesting
public static byte[] toCacheEntryStatic(ParsedPackage pkg) {
final Parcel p = Parcel.obtain();
final WriteHelper helper = new WriteHelper(p);
pkg.writeToParcel(p, 0 /* flags */);
helper.finishAndUninstall();
byte[] serialized = p.marshall();
p.recycle();
return serialized;
}
/**
* Given a {@code packageFile} and a {@code cacheFile} returns whether the
* cache file is up to date based on the mod-time of both files.
*/
private static boolean isCacheUpToDate(File packageFile, File cacheFile) {
try {
// NOTE: We don't use the File.lastModified API because it has the very
// non-ideal failure mode of returning 0 with no excepions thrown.
// The nio2 Files API is a little better but is considerably more expensive.
final StructStat pkg = android.system.Os.stat(packageFile.getAbsolutePath());
final StructStat cache = android.system.Os.stat(cacheFile.getAbsolutePath());
return pkg.st_mtime < cache.st_mtime;
} catch (ErrnoException ee) {
// The most common reason why stat fails is that a given cache file doesn't
// exist. We ignore that here. It's easy to reason that it's safe to say the
// cache isn't up to date if we see any sort of exception here.
//
// (1) Exception while stating the package file : This should never happen,
// and if it does, we do a full package parse (which is likely to throw the
// same exception).
// (2) Exception while stating the cache file : If the file doesn't exist, the
// cache is obviously out of date. If the file *does* exist, we can't read it.
// We will attempt to delete and recreate it after parsing the package.
if (ee.errno != OsConstants.ENOENT) {
Slog.w("Error while stating package cache : ", ee);
}
return false;
}
}
/**
* Returns the cached parse result for {@code packageFile} for parse flags {@code flags},
* or {@code null} if no cached result exists.
*/
public ParsedPackage getCachedResult(File packageFile, int flags) {
if (mCacheDir == null) {
return null;
}
final String cacheKey = getCacheKey(packageFile, flags);
final File cacheFile = new File(mCacheDir, cacheKey);
try {
// If the cache is not up to date, return null.
if (!isCacheUpToDate(packageFile, cacheFile)) {
return null;
}
final byte[] bytes = IoUtils.readFileAsByteArray(cacheFile.getAbsolutePath());
return fromCacheEntry(bytes);
} catch (Throwable e) {
Slog.w(TAG, "Error reading package cache: ", e);
// If something went wrong while reading the cache entry, delete the cache file
// so that we regenerate it the next time.
cacheFile.delete();
return null;
}
}
/**
* Caches the parse result for {@code packageFile} with flags {@code flags}.
*/
public void cacheResult(File packageFile, int flags, ParsedPackage parsed) {
if (mCacheDir == null) {
return;
}
try {
final String cacheKey = getCacheKey(packageFile, flags);
final File cacheFile = new File(mCacheDir, cacheKey);
if (cacheFile.exists()) {
if (!cacheFile.delete()) {
Slog.e(TAG, "Unable to delete cache file: " + cacheFile);
}
}
final byte[] cacheEntry = toCacheEntry(parsed);
if (cacheEntry == null) {
return;
}
try (FileOutputStream fos = new FileOutputStream(cacheFile)) {
fos.write(cacheEntry);
} catch (IOException ioe) {
Slog.w(TAG, "Error writing cache entry.", ioe);
cacheFile.delete();
}
} catch (Throwable e) {
Slog.w(TAG, "Error saving package cache.", e);
}
}
/**
* Parse all APKs contained in the given directory, treating them as a
* single package. This also performs sanity checking, such as requiring
@@ -1284,7 +1084,7 @@ public class PackageParser {
* <p>
* Note that this <em>does not</em> perform signature verification; that
* must be done separately in
* {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}.
* {@link #collectCertificates(Package, boolean)} .
*/
private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
final PackageLite lite = parseClusterPackageLite(packageDir, 0);
@@ -1346,7 +1146,7 @@ public class PackageParser {
* <p>
* Note that this <em>does not</em> perform signature verification; that
* must be done separately in
* {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}.
* {@link #collectCertificates(Package, boolean)}.
*/
@UnsupportedAppUsage
public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {

View File

@@ -50,7 +50,7 @@ import java.util.List;
/** @hide */
public class ApkLiteParseUtils {
private static final String TAG = ApkParseUtils.TAG;
private static final String TAG = ParsingPackageUtils.TAG;
// TODO(b/135203078): Consolidate constants
private static final int DEFAULT_MIN_SDK_VERSION = 1;
@@ -235,7 +235,7 @@ public class ApkLiteParseUtils {
final boolean skipVerify = (flags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0;
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
try {
signingDetails = ApkParseUtils.collectCertificates(apkFile.getAbsolutePath(),
signingDetails = ParsingPackageUtils.collectCertificates(apkFile.getAbsolutePath(),
skipVerify, false, PackageParser.SigningDetails.UNKNOWN,
DEFAULT_TARGET_SDK_VERSION);
} finally {

View File

@@ -82,7 +82,7 @@ import java.util.Objects;
*/
public class ComponentParseUtils {
private static final String TAG = ApkParseUtils.TAG;
private static final String TAG = ParsingUtils.TAG;
// TODO(b/135203078): None of this class's subclasses do anything. Remove in favor of base?
public static class ParsedIntentInfo extends IntentFilter {
@@ -315,7 +315,7 @@ public class ComponentParseUtils {
// TODO(b/135203078): Make subclass that contains these fields only for the necessary
// subtypes
protected boolean enabled = true;
protected boolean directBootAware;
public boolean directBootAware;
public int flags;
private String packageName;
@@ -1460,7 +1460,7 @@ public class ComponentParseUtils {
outError[0] = tag + " does not specify android:name";
return null;
} else {
String className = ApkParseUtils.buildClassName(packageName, name);
String className = ParsingUtils.buildClassName(packageName, name);
if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
outError[0] = tag + " invalid android:name";
return null;
@@ -1537,7 +1537,7 @@ public class ComponentParseUtils {
R.styleable.AndroidManifestActivity_parentActivityName,
Configuration.NATIVE_CONFIG_VERSION);
if (parentName != null) {
String parentClassName = ApkParseUtils.buildClassName(packageName, parentName);
String parentClassName = ParsingUtils.buildClassName(packageName, parentName);
if (parentClassName == null) {
Log.e(TAG,
"Activity " + result.className
@@ -1856,9 +1856,8 @@ public class ComponentParseUtils {
parsingPackage.addPreferredActivityFilter(intentInfo);
}
} else if (parser.getName().equals("meta-data")) {
if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
result.metaData,
outError)) == null) {
if ((result.metaData = ParsingPackageUtils.parseMetaData(parsingPackage, res,
parser, result.metaData, outError)) == null) {
return null;
}
} else if (!receiver && parser.getName().equals("layout")) {
@@ -1969,7 +1968,7 @@ public class ComponentParseUtils {
outError[0] = "<service> does not specify android:name";
return null;
} else {
String className = ApkParseUtils.buildClassName(packageName, name);
String className = ParsingUtils.buildClassName(packageName, name);
if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
outError[0] = "<service> invalid android:name";
return null;
@@ -2099,7 +2098,7 @@ public class ComponentParseUtils {
}
}
if (parsingPackage.cantSaveState()) {
if (parsingPackage.isCantSaveState()) {
// A heavy-weight application can not have services in its main process
// We can do direct compare because we intern all strings.
if (Objects.equals(result.getProcessName(), parsingPackage.getPackageName())) {
@@ -2132,9 +2131,8 @@ public class ComponentParseUtils {
result.order = Math.max(intent.getOrder(), result.order);
result.intents.add(intent);
} else if (parser.getName().equals("meta-data")) {
if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
result.metaData,
outError)) == null) {
if ((result.metaData = ParsingPackageUtils.parseMetaData(parsingPackage, res,
parser, result.metaData, outError)) == null) {
return null;
}
} else {
@@ -2182,7 +2180,7 @@ public class ComponentParseUtils {
outError[0] = "<provider> does not specify android:name";
return null;
} else {
String className = ApkParseUtils.buildClassName(packageName, name);
String className = ParsingUtils.buildClassName(packageName, name);
if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
outError[0] = "<provider> invalid android:name";
return null;
@@ -2413,7 +2411,7 @@ public class ComponentParseUtils {
outInfo.intents.add(intent);
} else if (parser.getName().equals("meta-data")) {
Bundle metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
Bundle metaData = ParsingPackageUtils.parseMetaData(parsingPackage, res, parser,
outInfo.metaData, outError);
if (metaData == null) {
return false;
@@ -2607,7 +2605,7 @@ public class ComponentParseUtils {
}
String packageName = parsingPackage.getPackageName();
targetActivity = ApkParseUtils.buildClassName(packageName, targetActivity);
targetActivity = ParsingUtils.buildClassName(packageName, targetActivity);
if (targetActivity == null) {
outError[0] = "Empty class name in package " + packageName;
sa.recycle();
@@ -2664,7 +2662,7 @@ public class ComponentParseUtils {
result.requestedVrComponent = target.requestedVrComponent;
result.directBootAware = target.directBootAware;
result.setProcessName(parsingPackage.getAppInfoProcessName(), target.getProcessName());
result.setProcessName(parsingPackage.getProcessName(), target.getProcessName());
// Not all attributes from the target ParsedActivity are copied to the alias.
// Careful when adding an attribute and determine whether or not it should be copied.
@@ -2686,7 +2684,7 @@ public class ComponentParseUtils {
outError[0] = "<activity-alias> does not specify android:name";
return null;
} else {
String className = ApkParseUtils.buildClassName(packageName, name);
String className = ParsingUtils.buildClassName(packageName, name);
if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
outError[0] = "<activity-alias> invalid android:name";
return null;
@@ -2751,7 +2749,7 @@ public class ComponentParseUtils {
R.styleable.AndroidManifestActivityAlias_parentActivityName,
Configuration.NATIVE_CONFIG_VERSION);
if (parentName != null) {
String parentClassName = ApkParseUtils.buildClassName(result.getPackageName(),
String parentClassName = ParsingUtils.buildClassName(result.getPackageName(),
parentName);
if (parentClassName == null) {
Log.e(TAG, "Activity alias " + result.className +
@@ -2811,9 +2809,8 @@ public class ComponentParseUtils {
result.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
}
} else if (tagName.equals("meta-data")) {
if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
result.metaData,
outError)) == null) {
if ((result.metaData = ParsingPackageUtils.parseMetaData(parsingPackage, res,
parser, result.metaData, outError)) == null) {
return null;
}
} else {
@@ -2935,7 +2932,7 @@ public class ComponentParseUtils {
outError[0] = "<permission> does not specify android:name";
return null;
} else {
String className = ApkParseUtils.buildClassName(packageName, name);
String className = ParsingUtils.buildClassName(packageName, name);
if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
outError[0] = "<permission> invalid android:name";
return null;
@@ -3073,7 +3070,7 @@ public class ComponentParseUtils {
outError[0] = "<permission-tree> does not specify android:name";
return null;
} else {
String className = ApkParseUtils.buildClassName(packageName, name);
String className = ParsingUtils.buildClassName(packageName, name);
if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
outError[0] = "<permission-tree> invalid android:name";
return null;
@@ -3163,7 +3160,7 @@ public class ComponentParseUtils {
outError[0] = "<permission> does not specify android:name";
return null;
} else {
String className = ApkParseUtils.buildClassName(packageName, name);
String className = ParsingUtils.buildClassName(packageName, name);
if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
outError[0] = "<permission> invalid android:name";
return null;
@@ -3262,7 +3259,7 @@ public class ComponentParseUtils {
outError[0] = "<instrumentation> does not specify android:name";
return null;
} else {
String className = ApkParseUtils.buildClassName(packageName, name);
String className = ParsingUtils.buildClassName(packageName, name);
if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
outError[0] = "<instrumentation> invalid android:name";
return null;
@@ -3764,8 +3761,8 @@ public class ComponentParseUtils {
}
if (parser.getName().equals("meta-data")) {
if ((outInfo.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
outInfo.metaData, outError)) == null) {
if ((outInfo.metaData = ParsingPackageUtils.parseMetaData(parsingPackage, res,
parser, outInfo.metaData, outError)) == null) {
return false;
}
} else {

View File

@@ -1,595 +0,0 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.content.pm.parsing;
import android.annotation.Nullable;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ComponentInfo;
import android.content.pm.ConfigurationInfo;
import android.content.pm.FallbackCategoryProvider;
import android.content.pm.FeatureGroupInfo;
import android.content.pm.FeatureInfo;
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.PackageUserState;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.ProcessInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.SELinuxUtil;
import android.content.pm.ServiceInfo;
import android.content.pm.Signature;
import android.content.pm.SigningInfo;
import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
import android.util.ArrayMap;
import android.util.ArraySet;
import com.android.internal.util.ArrayUtils;
import java.util.Set;
/** @hide */
public class PackageInfoUtils {
private static final String TAG = ApkParseUtils.TAG;
/**
* Returns true if the package is installed and not hidden, or if the caller
* explicitly wanted all uninstalled and hidden packages as well.
*/
private static boolean checkUseInstalledOrHidden(AndroidPackage pkg, PackageUserState state,
@PackageManager.PackageInfoFlags int flags) {
// Returns false if the package is hidden system app until installed.
if ((flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) == 0
&& !state.installed
&& pkg.isHiddenUntilInstalled()) {
return false;
}
// If available for the target user, or trying to match uninstalled packages and it's
// a system app.
return state.isAvailable(flags)
|| (pkg.isSystemApp()
&& ((flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0
|| (flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) != 0));
}
public static PackageInfo generate(AndroidPackage pkg, int[] gids,
@PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
Set<String> grantedPermissions, PackageUserState state, int userId) {
if (!checkUseInstalledOrHidden(pkg, state, flags) || !pkg.isMatch(flags)) {
return null;
}
ApplicationInfo applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
PackageInfo pi = new PackageInfo();
pi.packageName = pkg.getPackageName();
pi.splitNames = pkg.getSplitNames();
pi.versionCode = pkg.getVersionCode();
pi.versionCodeMajor = pkg.getVersionCodeMajor();
pi.baseRevisionCode = pkg.getBaseRevisionCode();
pi.splitRevisionCodes = pkg.getSplitRevisionCodes();
pi.versionName = pkg.getVersionName();
pi.sharedUserId = pkg.getSharedUserId();
pi.sharedUserLabel = pkg.getSharedUserLabel();
pi.applicationInfo = applicationInfo;
pi.installLocation = pkg.getInstallLocation();
pi.isStub = pkg.isStub();
pi.coreApp = pkg.isCoreApp();
if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
|| (pi.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
pi.requiredForAllUsers = pkg.isRequiredForAllUsers();
}
pi.restrictedAccountType = pkg.getRestrictedAccountType();
pi.requiredAccountType = pkg.getRequiredAccountType();
pi.overlayTarget = pkg.getOverlayTarget();
pi.targetOverlayableName = pkg.getOverlayTargetName();
pi.overlayCategory = pkg.getOverlayCategory();
pi.overlayPriority = pkg.getOverlayPriority();
pi.mOverlayIsStatic = pkg.isOverlayIsStatic();
pi.compileSdkVersion = pkg.getCompileSdkVersion();
pi.compileSdkVersionCodename = pkg.getCompileSdkVersionCodeName();
pi.firstInstallTime = firstInstallTime;
pi.lastUpdateTime = lastUpdateTime;
if ((flags & PackageManager.GET_GIDS) != 0) {
pi.gids = gids;
}
if ((flags & PackageManager.GET_CONFIGURATIONS) != 0) {
int size = pkg.getConfigPreferences() != null ? pkg.getConfigPreferences().size() : 0;
if (size > 0) {
pi.configPreferences = new ConfigurationInfo[size];
pkg.getConfigPreferences().toArray(pi.configPreferences);
}
size = pkg.getReqFeatures() != null ? pkg.getReqFeatures().size() : 0;
if (size > 0) {
pi.reqFeatures = new FeatureInfo[size];
pkg.getReqFeatures().toArray(pi.reqFeatures);
}
size = pkg.getFeatureGroups() != null ? pkg.getFeatureGroups().size() : 0;
if (size > 0) {
pi.featureGroups = new FeatureGroupInfo[size];
pkg.getFeatureGroups().toArray(pi.featureGroups);
}
}
if ((flags & PackageManager.GET_ACTIVITIES) != 0) {
if (pkg.getActivities() != null) {
final int N = pkg.getActivities().size();
if (N > 0) {
int num = 0;
final ActivityInfo[] res = new ActivityInfo[N];
for (int i = 0; i < N; i++) {
final ParsedActivity a = pkg.getActivities().get(i);
if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), a, flags)) {
if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(
a.className)) {
continue;
}
res[num++] = generateActivityInfo(pkg, a, flags, state, applicationInfo,
userId);
}
}
pi.activities = ArrayUtils.trimToSize(res, num);
}
}
}
if ((flags & PackageManager.GET_RECEIVERS) != 0) {
if (pkg.getReceivers() != null) {
final int size = pkg.getReceivers().size();
if (size > 0) {
int num = 0;
final ActivityInfo[] res = new ActivityInfo[size];
for (int i = 0; i < size; i++) {
final ParsedActivity a = pkg.getReceivers().get(i);
if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), a, flags)) {
res[num++] = generateActivityInfo(pkg, a, flags, state, applicationInfo,
userId);
}
}
pi.receivers = ArrayUtils.trimToSize(res, num);
}
}
}
if ((flags & PackageManager.GET_SERVICES) != 0) {
if (pkg.getServices() != null) {
final int size = pkg.getServices().size();
if (size > 0) {
int num = 0;
final ServiceInfo[] res = new ServiceInfo[size];
for (int i = 0; i < size; i++) {
final ComponentParseUtils.ParsedService s = pkg.getServices().get(i);
if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), s, flags)) {
res[num++] = generateServiceInfo(pkg, s, flags, state, applicationInfo,
userId);
}
}
pi.services = ArrayUtils.trimToSize(res, num);
}
}
}
if ((flags & PackageManager.GET_PROVIDERS) != 0) {
if (pkg.getProviders() != null) {
final int size = pkg.getProviders().size();
if (size > 0) {
int num = 0;
final ProviderInfo[] res = new ProviderInfo[size];
for (int i = 0; i < size; i++) {
final ComponentParseUtils.ParsedProvider pr = pkg.getProviders()
.get(i);
if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), pr, flags)) {
res[num++] = generateProviderInfo(pkg, pr, flags, state,
applicationInfo, userId);
}
}
pi.providers = ArrayUtils.trimToSize(res, num);
}
}
}
if ((flags & PackageManager.GET_INSTRUMENTATION) != 0) {
if (pkg.getInstrumentations() != null) {
int N = pkg.getInstrumentations().size();
if (N > 0) {
pi.instrumentation = new InstrumentationInfo[N];
for (int i = 0; i < N; i++) {
pi.instrumentation[i] = generateInstrumentationInfo(
pkg.getInstrumentations().get(i), pkg, flags);
}
}
}
}
if ((flags & PackageManager.GET_PERMISSIONS) != 0) {
if (pkg.getPermissions() != null) {
int N = ArrayUtils.size(pkg.getPermissions());
if (N > 0) {
pi.permissions = new PermissionInfo[N];
for (int i = 0; i < N; i++) {
pi.permissions[i] = generatePermissionInfo(
pkg.getPermissions().get(i),
flags
);
}
}
}
if (pkg.getRequestedPermissions() != null) {
int N = pkg.getRequestedPermissions().size();
if (N > 0) {
pi.requestedPermissions = new String[N];
pi.requestedPermissionsFlags = new int[N];
for (int i = 0; i < N; i++) {
final String perm = pkg.getRequestedPermissions().get(i);
pi.requestedPermissions[i] = perm;
// The notion of required permissions is deprecated but for compatibility.
pi.requestedPermissionsFlags[i] |=
PackageInfo.REQUESTED_PERMISSION_REQUIRED;
if (grantedPermissions != null && grantedPermissions.contains(perm)) {
pi.requestedPermissionsFlags[i] |=
PackageInfo.REQUESTED_PERMISSION_GRANTED;
}
}
}
}
}
PackageParser.SigningDetails signingDetails = pkg.getSigningDetails();
// deprecated method of getting signing certificates
if ((flags & PackageManager.GET_SIGNATURES) != 0) {
if (signingDetails.hasPastSigningCertificates()) {
// Package has included signing certificate rotation information. Return the oldest
// cert so that programmatic checks keep working even if unaware of key rotation.
pi.signatures = new Signature[1];
pi.signatures[0] = signingDetails.pastSigningCertificates[0];
} else if (signingDetails.hasSignatures()) {
// otherwise keep old behavior
int numberOfSigs = signingDetails.signatures.length;
pi.signatures = new Signature[numberOfSigs];
System.arraycopy(signingDetails.signatures, 0, pi.signatures, 0,
numberOfSigs);
}
}
// replacement for GET_SIGNATURES
if ((flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0) {
if (signingDetails != PackageParser.SigningDetails.UNKNOWN) {
// only return a valid SigningInfo if there is signing information to report
pi.signingInfo = new SigningInfo(signingDetails);
} else {
pi.signingInfo = null;
}
}
return pi;
}
@Nullable
public static ApplicationInfo generateApplicationInfo(AndroidPackage pkg,
@PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId) {
if (pkg == null) return null;
if (!checkUseInstalledOrHidden(pkg, state, flags) || !pkg.isMatch(flags)) {
return null;
}
// Make shallow copy so we can store the metadata/libraries safely
ApplicationInfo ai = pkg.toAppInfoWithoutState();
ai.initForUser(userId);
if ((flags & PackageManager.GET_META_DATA) == 0) {
ai.metaData = null;
}
if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) == 0) {
ai.sharedLibraryFiles = null;
ai.sharedLibraryInfos = null;
}
if (state.stopped) {
ai.flags |= ApplicationInfo.FLAG_STOPPED;
} else {
ai.flags &= ~ApplicationInfo.FLAG_STOPPED;
}
updateApplicationInfo(ai, flags, state);
return ai;
}
private static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a,
@PackageManager.ComponentInfoFlags int flags, PackageUserState state,
@Nullable ApplicationInfo applicationInfo, int userId) {
if (a == null) return null;
if (!checkUseInstalledOrHidden(pkg, state, flags)) {
return null;
}
if (applicationInfo == null) {
applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
}
// Make shallow copies so we can store the metadata safely
ActivityInfo ai = new ActivityInfo();
assignSharedFieldsForComponentInfo(ai, a);
ai.targetActivity = a.targetActivity;
ai.processName = a.getProcessName();
ai.exported = a.exported;
ai.theme = a.theme;
ai.uiOptions = a.uiOptions;
ai.parentActivityName = a.parentActivityName;
ai.permission = a.getPermission();
ai.taskAffinity = a.taskAffinity;
ai.flags = a.flags;
ai.privateFlags = a.privateFlags;
ai.launchMode = a.launchMode;
ai.documentLaunchMode = a.documentLaunchMode;
ai.maxRecents = a.maxRecents;
ai.configChanges = a.configChanges;
ai.softInputMode = a.softInputMode;
ai.persistableMode = a.persistableMode;
ai.lockTaskLaunchMode = a.lockTaskLaunchMode;
ai.screenOrientation = a.screenOrientation;
ai.resizeMode = a.resizeMode;
ai.maxAspectRatio = a.maxAspectRatio;
ai.minAspectRatio = a.minAspectRatio;
ai.requestedVrComponent = a.requestedVrComponent;
ai.rotationAnimation = a.rotationAnimation;
ai.colorMode = a.colorMode;
ai.preferMinimalPostProcessing = a.preferMinimalPostProcessing;
ai.windowLayout = a.windowLayout;
ai.metaData = a.metaData;
ai.applicationInfo = applicationInfo;
return ai;
}
public static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a,
@PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) {
return generateActivityInfo(pkg, a, flags, state, null, userId);
}
private static ServiceInfo generateServiceInfo(AndroidPackage pkg,
ComponentParseUtils.ParsedService s, @PackageManager.ComponentInfoFlags int flags,
PackageUserState state, @Nullable ApplicationInfo applicationInfo, int userId) {
if (s == null) return null;
if (!checkUseInstalledOrHidden(pkg, state, flags)) {
return null;
}
if (applicationInfo == null) {
applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
}
// Make shallow copies so we can store the metadata safely
ServiceInfo si = new ServiceInfo();
assignSharedFieldsForComponentInfo(si, s);
si.exported = s.exported;
si.flags = s.flags;
si.metaData = s.metaData;
si.permission = s.getPermission();
si.processName = s.getProcessName();
si.mForegroundServiceType = s.foregroundServiceType;
si.metaData = s.metaData;
si.applicationInfo = applicationInfo;
return si;
}
public static ServiceInfo generateServiceInfo(AndroidPackage pkg,
ComponentParseUtils.ParsedService s, @PackageManager.ComponentInfoFlags int flags,
PackageUserState state, int userId) {
return generateServiceInfo(pkg, s, flags, state, null, userId);
}
private static ProviderInfo generateProviderInfo(AndroidPackage pkg,
ComponentParseUtils.ParsedProvider p, @PackageManager.ComponentInfoFlags int flags,
PackageUserState state, @Nullable ApplicationInfo applicationInfo, int userId) {
if (p == null) return null;
if (!checkUseInstalledOrHidden(pkg, state, flags)) {
return null;
}
if (applicationInfo == null) {
applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
}
// Make shallow copies so we can store the metadata safely
ProviderInfo pi = new ProviderInfo();
assignSharedFieldsForComponentInfo(pi, p);
pi.exported = p.exported;
pi.flags = p.flags;
pi.processName = p.getProcessName();
pi.authority = p.getAuthority();
pi.isSyncable = p.isSyncable;
pi.readPermission = p.getReadPermission();
pi.writePermission = p.getWritePermission();
pi.grantUriPermissions = p.grantUriPermissions;
pi.forceUriPermissions = p.forceUriPermissions;
pi.multiprocess = p.multiProcess;
pi.initOrder = p.initOrder;
pi.uriPermissionPatterns = p.uriPermissionPatterns;
pi.pathPermissions = p.pathPermissions;
pi.metaData = p.metaData;
if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) {
pi.uriPermissionPatterns = null;
}
pi.applicationInfo = applicationInfo;
return pi;
}
public static ProviderInfo generateProviderInfo(AndroidPackage pkg,
ComponentParseUtils.ParsedProvider p, @PackageManager.ComponentInfoFlags int flags,
PackageUserState state, int userId) {
return generateProviderInfo(pkg, p, flags, state, null, userId);
}
public static InstrumentationInfo generateInstrumentationInfo(ParsedInstrumentation i,
AndroidPackage pkg, @PackageManager.ComponentInfoFlags int flags) {
if (i == null) return null;
InstrumentationInfo ii = new InstrumentationInfo();
assignSharedFieldsForPackageItemInfo(ii, i);
ii.targetPackage = i.getTargetPackage();
ii.targetProcesses = i.getTargetProcesses();
ii.handleProfiling = i.handleProfiling;
ii.functionalTest = i.functionalTest;
ii.sourceDir = pkg.getBaseCodePath();
ii.publicSourceDir = pkg.getBaseCodePath();
ii.splitNames = pkg.getSplitNames();
ii.splitSourceDirs = pkg.getSplitCodePaths();
ii.splitPublicSourceDirs = pkg.getSplitCodePaths();
ii.splitDependencies = pkg.getSplitDependencies();
ii.dataDir = pkg.getDataDir();
ii.deviceProtectedDataDir = pkg.getDeviceProtectedDataDir();
ii.credentialProtectedDataDir = pkg.getCredentialProtectedDataDir();
ii.primaryCpuAbi = pkg.getPrimaryCpuAbi();
ii.secondaryCpuAbi = pkg.getSecondaryCpuAbi();
ii.nativeLibraryDir = pkg.getNativeLibraryDir();
ii.secondaryNativeLibraryDir = pkg.getSecondaryNativeLibraryDir();
if ((flags & PackageManager.GET_META_DATA) == 0) {
return ii;
}
ii.metaData = i.metaData;
return ii;
}
public static ArrayMap<String, ProcessInfo> generateProcessInfo(
ArrayMap<String, ComponentParseUtils.ParsedProcess> procs,
@PackageManager.ComponentInfoFlags int flags) {
if (procs == null) {
return null;
}
final int numProcs = procs.size();
ArrayMap<String, ProcessInfo> retProcs = new ArrayMap(numProcs);
for (int i = 0; i < numProcs; i++) {
ComponentParseUtils.ParsedProcess proc = procs.valueAt(i);
retProcs.put(proc.name, new ProcessInfo(proc.name,
proc.deniedPermissions != null
? new ArraySet<>(proc.deniedPermissions) : null));
}
return retProcs;
}
public static PermissionInfo generatePermissionInfo(ParsedPermission p,
@PackageManager.ComponentInfoFlags int flags) {
if (p == null) return null;
PermissionInfo pi = new PermissionInfo(p.backgroundPermission);
assignSharedFieldsForPackageItemInfo(pi, p);
pi.group = p.getGroup();
pi.requestRes = p.requestRes;
pi.protectionLevel = p.protectionLevel;
pi.descriptionRes = p.descriptionRes;
pi.flags = p.flags;
if ((flags & PackageManager.GET_META_DATA) == 0) {
return pi;
}
pi.metaData = p.metaData;
return pi;
}
public static PermissionGroupInfo generatePermissionGroupInfo(ParsedPermissionGroup pg,
@PackageManager.ComponentInfoFlags int flags) {
if (pg == null) return null;
PermissionGroupInfo pgi = new PermissionGroupInfo(
pg.requestDetailResourceId,
pg.backgroundRequestResourceId,
pg.backgroundRequestDetailResourceId
);
assignSharedFieldsForPackageItemInfo(pgi, pg);
pgi.descriptionRes = pg.descriptionRes;
pgi.priority = pg.priority;
pgi.requestRes = pg.requestRes;
pgi.flags = pg.flags;
if ((flags & PackageManager.GET_META_DATA) == 0) {
return pgi;
}
pgi.metaData = pg.metaData;
return pgi;
}
private static void updateApplicationInfo(ApplicationInfo ai,
@PackageManager.ApplicationInfoFlags int flags,
PackageUserState state) {
// CompatibilityMode is global state.
if (!PackageParser.sCompatibilityModeEnabled) {
ai.disableCompatibilityMode();
}
if (state.installed) {
ai.flags |= ApplicationInfo.FLAG_INSTALLED;
} else {
ai.flags &= ~ApplicationInfo.FLAG_INSTALLED;
}
if (state.suspended) {
ai.flags |= ApplicationInfo.FLAG_SUSPENDED;
} else {
ai.flags &= ~ApplicationInfo.FLAG_SUSPENDED;
}
if (state.instantApp) {
ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_INSTANT;
} else {
ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_INSTANT;
}
if (state.virtualPreload) {
ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD;
} else {
ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD;
}
if (state.hidden) {
ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
} else {
ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN;
}
if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
ai.enabled = true;
} else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
ai.enabled = (flags & PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0;
} else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
|| state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
ai.enabled = false;
}
ai.enabledSetting = state.enabled;
if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
ai.category = state.categoryHint;
}
if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName);
}
ai.seInfoUser = SELinuxUtil.assignSeinfoUser(state);
ai.resourceDirs = state.getAllOverlayPaths();
ai.icon = (PackageParser.sUseRoundIcon && ai.roundIconRes != 0)
? ai.roundIconRes : ai.iconRes;
}
private static void assignSharedFieldsForPackageItemInfo(PackageItemInfo packageItemInfo,
ComponentParseUtils.ParsedComponent parsedComponent) {
packageItemInfo.banner = parsedComponent.banner;
packageItemInfo.icon = parsedComponent.icon;
packageItemInfo.labelRes = parsedComponent.labelRes;
packageItemInfo.logo = parsedComponent.logo;
packageItemInfo.name = parsedComponent.className;
packageItemInfo.nonLocalizedLabel = parsedComponent.nonLocalizedLabel;
packageItemInfo.packageName = parsedComponent.getPackageName();
}
private static void assignSharedFieldsForComponentInfo(ComponentInfo componentInfo,
ComponentParseUtils.ParsedComponent parsedComponent) {
assignSharedFieldsForPackageItemInfo(componentInfo, parsedComponent);
componentInfo.descriptionRes = parsedComponent.descriptionRes;
componentInfo.directBootAware = parsedComponent.directBootAware;
componentInfo.enabled = parsedComponent.enabled;
componentInfo.splitName = parsedComponent.getSplitName();
}
}

View File

@@ -0,0 +1,691 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.content.pm.parsing;
import android.annotation.CheckResult;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.apex.ApexInfo;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ComponentInfo;
import android.content.pm.ConfigurationInfo;
import android.content.pm.FallbackCategoryProvider;
import android.content.pm.FeatureGroupInfo;
import android.content.pm.FeatureInfo;
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.PackageUserState;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.SELinuxUtil;
import android.content.pm.ServiceInfo;
import android.content.pm.Signature;
import android.content.pm.SigningInfo;
import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
import android.content.pm.parsing.ComponentParseUtils.ParsedComponent;
import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
import android.content.pm.parsing.ComponentParseUtils.ParsedMainComponent;
import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
import android.content.pm.parsing.ComponentParseUtils.ParsedService;
import android.os.Environment;
import android.os.UserHandle;
import com.android.internal.util.ArrayUtils;
import libcore.util.EmptyArray;
import java.io.File;
import java.util.Collections;
import java.util.Set;
/** @hide **/
public class PackageInfoWithoutStateUtils {
@Nullable
public static PackageInfo generate(ParsingPackageRead pkg, int[] gids,
@PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
Set<String> grantedPermissions, PackageUserState state, int userId) {
return generateWithComponents(pkg, gids, flags, firstInstallTime, lastUpdateTime, grantedPermissions,
state, userId, null);
}
@Nullable
public static PackageInfo generate(ParsingPackageRead pkg, ApexInfo apexInfo, int flags) {
return generateWithComponents(pkg, EmptyArray.INT, flags, 0, 0, Collections.emptySet(),
new PackageUserState(), UserHandle.getCallingUserId(), apexInfo);
}
@Nullable
private static PackageInfo generateWithComponents(ParsingPackageRead pkg, int[] gids,
@PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
Set<String> grantedPermissions, PackageUserState state, int userId,
@Nullable ApexInfo apexInfo) {
ApplicationInfo applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
if (applicationInfo == null) {
return null;
}
PackageInfo info = generateWithoutComponents(pkg, gids, flags, firstInstallTime,
lastUpdateTime, grantedPermissions, state, userId, apexInfo, applicationInfo);
if (info == null) {
return null;
}
if ((flags & PackageManager.GET_ACTIVITIES) != 0) {
final int N = pkg.getActivities().size();
if (N > 0) {
int num = 0;
final ActivityInfo[] res = new ActivityInfo[N];
for (int i = 0; i < N; i++) {
final ParsedActivity a = pkg.getActivities().get(i);
if (state.isMatch(false, pkg.isEnabled(), a, flags)) {
if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(
a.getName())) {
continue;
}
res[num++] = generateActivityInfo(pkg, a, flags, state,
applicationInfo, userId);
}
}
info.activities = ArrayUtils.trimToSize(res, num);
}
}
if ((flags & PackageManager.GET_RECEIVERS) != 0) {
final int size = pkg.getReceivers().size();
if (size > 0) {
int num = 0;
final ActivityInfo[] res = new ActivityInfo[size];
for (int i = 0; i < size; i++) {
final ParsedActivity a = pkg.getReceivers().get(i);
if (state.isMatch(false, pkg.isEnabled(), a, flags)) {
res[num++] = generateActivityInfo(pkg, a, flags, state,
applicationInfo, userId);
}
}
info.receivers = ArrayUtils.trimToSize(res, num);
}
}
if ((flags & PackageManager.GET_SERVICES) != 0) {
final int size = pkg.getServices().size();
if (size > 0) {
int num = 0;
final ServiceInfo[] res = new ServiceInfo[size];
for (int i = 0; i < size; i++) {
final ParsedService s = pkg.getServices().get(i);
if (state.isMatch(false, pkg.isEnabled(), s, flags)) {
res[num++] = generateServiceInfo(pkg, s, flags, state,
applicationInfo, userId);
}
}
info.services = ArrayUtils.trimToSize(res, num);
}
}
if ((flags & PackageManager.GET_PROVIDERS) != 0) {
final int size = pkg.getProviders().size();
if (size > 0) {
int num = 0;
final ProviderInfo[] res = new ProviderInfo[size];
for (int i = 0; i < size; i++) {
final ParsedProvider pr = pkg.getProviders()
.get(i);
if (state.isMatch(false, pkg.isEnabled(), pr, flags)) {
res[num++] = generateProviderInfo(pkg, pr, flags, state,
applicationInfo, userId);
}
}
info.providers = ArrayUtils.trimToSize(res, num);
}
}
if ((flags & PackageManager.GET_INSTRUMENTATION) != 0) {
int N = pkg.getInstrumentations().size();
if (N > 0) {
info.instrumentation = new InstrumentationInfo[N];
for (int i = 0; i < N; i++) {
info.instrumentation[i] = generateInstrumentationInfo(
pkg.getInstrumentations().get(i), pkg, flags, userId);
}
}
}
return info;
}
@Nullable
public static PackageInfo generateWithoutComponents(ParsingPackageRead pkg, int[] gids,
@PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
Set<String> grantedPermissions, PackageUserState state, int userId,
@Nullable ApexInfo apexInfo, @NonNull ApplicationInfo applicationInfo) {
if (!checkUseInstalled(pkg, state, flags)) {
return null;
}
PackageInfo pi = new PackageInfo();
pi.packageName = pkg.getPackageName();
pi.splitNames = pkg.getSplitNames();
pi.versionCode = pkg.getVersionCode();
pi.versionCodeMajor = pkg.getVersionCodeMajor();
pi.baseRevisionCode = pkg.getBaseRevisionCode();
pi.splitRevisionCodes = pkg.getSplitRevisionCodes();
pi.versionName = pkg.getVersionName();
pi.sharedUserId = pkg.getSharedUserId();
pi.sharedUserLabel = pkg.getSharedUserLabel();
pi.applicationInfo = applicationInfo;
pi.installLocation = pkg.getInstallLocation();
if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
|| (pi.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
pi.requiredForAllUsers = pkg.isRequiredForAllUsers();
}
pi.restrictedAccountType = pkg.getRestrictedAccountType();
pi.requiredAccountType = pkg.getRequiredAccountType();
pi.overlayTarget = pkg.getOverlayTarget();
pi.targetOverlayableName = pkg.getOverlayTargetName();
pi.overlayCategory = pkg.getOverlayCategory();
pi.overlayPriority = pkg.getOverlayPriority();
pi.mOverlayIsStatic = pkg.isOverlayIsStatic();
pi.compileSdkVersion = pkg.getCompileSdkVersion();
pi.compileSdkVersionCodename = pkg.getCompileSdkVersionCodeName();
pi.firstInstallTime = firstInstallTime;
pi.lastUpdateTime = lastUpdateTime;
if ((flags & PackageManager.GET_GIDS) != 0) {
pi.gids = gids;
}
if ((flags & PackageManager.GET_CONFIGURATIONS) != 0) {
int size = pkg.getConfigPreferences().size();
if (size > 0) {
pi.configPreferences = new ConfigurationInfo[size];
pkg.getConfigPreferences().toArray(pi.configPreferences);
}
size = pkg.getReqFeatures().size();
if (size > 0) {
pi.reqFeatures = new FeatureInfo[size];
pkg.getReqFeatures().toArray(pi.reqFeatures);
}
size = pkg.getFeatureGroups().size();
if (size > 0) {
pi.featureGroups = new FeatureGroupInfo[size];
pkg.getFeatureGroups().toArray(pi.featureGroups);
}
}
if ((flags & PackageManager.GET_PERMISSIONS) != 0) {
int size = ArrayUtils.size(pkg.getPermissions());
if (size > 0) {
pi.permissions = new PermissionInfo[size];
for (int i = 0; i < size; i++) {
pi.permissions[i] = generatePermissionInfo(pkg.getPermissions().get(i),
flags);
}
}
size = pkg.getRequestedPermissions().size();
if (size > 0) {
pi.requestedPermissions = new String[size];
pi.requestedPermissionsFlags = new int[size];
for (int i = 0; i < size; i++) {
final String perm = pkg.getRequestedPermissions().get(i);
pi.requestedPermissions[i] = perm;
// The notion of required permissions is deprecated but for compatibility.
pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_REQUIRED;
if (grantedPermissions != null && grantedPermissions.contains(perm)) {
pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_GRANTED;
}
}
}
}
if (apexInfo != null) {
File apexFile = new File(apexInfo.modulePath);
pi.applicationInfo.sourceDir = apexFile.getPath();
pi.applicationInfo.publicSourceDir = apexFile.getPath();
if (apexInfo.isFactory) {
pi.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
} else {
pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;
}
if (apexInfo.isActive) {
pi.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
} else {
pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
}
pi.isApex = true;
}
PackageParser.SigningDetails signingDetails = pkg.getSigningDetails();
// deprecated method of getting signing certificates
if ((flags & PackageManager.GET_SIGNATURES) != 0) {
if (signingDetails.hasPastSigningCertificates()) {
// Package has included signing certificate rotation information. Return the oldest
// cert so that programmatic checks keep working even if unaware of key rotation.
pi.signatures = new Signature[1];
pi.signatures[0] = signingDetails.pastSigningCertificates[0];
} else if (signingDetails.hasSignatures()) {
// otherwise keep old behavior
int numberOfSigs = signingDetails.signatures.length;
pi.signatures = new Signature[numberOfSigs];
System.arraycopy(signingDetails.signatures, 0, pi.signatures, 0,
numberOfSigs);
}
}
// replacement for GET_SIGNATURES
if ((flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0) {
if (signingDetails != PackageParser.SigningDetails.UNKNOWN) {
// only return a valid SigningInfo if there is signing information to report
pi.signingInfo = new SigningInfo(signingDetails);
} else {
pi.signingInfo = null;
}
}
return pi;
}
@Nullable
public static ApplicationInfo generateApplicationInfo(ParsingPackageRead pkg,
@PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId) {
if (pkg == null) {
return null;
}
if (!checkUseInstalled(pkg, state, flags)) {
return null;
}
// Make shallow copy so we can store the metadata/libraries safely
ApplicationInfo ai = pkg.toAppInfoWithoutState();
// Init handles data directories
// TODO(b/135203078): Consolidate the data directory logic, remove initForUser
ai.initForUser(userId);
ai.flags = appInfoFlags(pkg);
ai.privateFlags = appInfoPrivateFlags(pkg);
if ((flags & PackageManager.GET_META_DATA) == 0) {
ai.metaData = null;
}
if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) == 0) {
ai.sharedLibraryFiles = null;
ai.sharedLibraryInfos = null;
}
// CompatibilityMode is global state.
if (!PackageParser.sCompatibilityModeEnabled) {
ai.disableCompatibilityMode();
}
ai.flags |= flag(state.stopped, ApplicationInfo.FLAG_STOPPED)
| flag(state.installed, ApplicationInfo.FLAG_INSTALLED)
| flag(state.suspended, ApplicationInfo.FLAG_SUSPENDED);
ai.privateFlags |= flag(state.instantApp, ApplicationInfo.PRIVATE_FLAG_INSTANT)
| flag(state.virtualPreload, ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD)
| flag(state.hidden, ApplicationInfo.PRIVATE_FLAG_HIDDEN);
if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
ai.enabled = true;
} else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
ai.enabled = (flags & PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0;
} else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
|| state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
ai.enabled = false;
}
ai.enabledSetting = state.enabled;
if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
ai.category = state.categoryHint;
}
if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName);
}
ai.seInfoUser = SELinuxUtil.assignSeinfoUser(state);
ai.resourceDirs = state.getOverlayPaths();
return ai;
}
@Nullable
public static ActivityInfo generateActivityInfo(ParsingPackageRead pkg, ParsedActivity a,
@PackageManager.ComponentInfoFlags int flags, PackageUserState state,
@Nullable ApplicationInfo applicationInfo, int userId) {
if (a == null) return null;
if (!checkUseInstalled(pkg, state, flags)) {
return null;
}
if (applicationInfo == null) {
applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
}
// Make shallow copies so we can store the metadata safely
ActivityInfo ai = new ActivityInfo();
assignSharedFieldsForComponentInfo(ai, a);
ai.targetActivity = a.targetActivity;
ai.processName = a.getProcessName();
ai.exported = a.exported;
ai.theme = a.theme;
ai.uiOptions = a.uiOptions;
ai.parentActivityName = a.parentActivityName;
ai.permission = a.getPermission();
ai.taskAffinity = a.taskAffinity;
ai.flags = a.flags;
ai.privateFlags = a.privateFlags;
ai.launchMode = a.launchMode;
ai.documentLaunchMode = a.documentLaunchMode;
ai.maxRecents = a.maxRecents;
ai.configChanges = a.configChanges;
ai.softInputMode = a.softInputMode;
ai.persistableMode = a.persistableMode;
ai.lockTaskLaunchMode = a.lockTaskLaunchMode;
ai.screenOrientation = a.screenOrientation;
ai.resizeMode = a.resizeMode;
ai.maxAspectRatio = a.maxAspectRatio;
ai.minAspectRatio = a.minAspectRatio;
ai.requestedVrComponent = a.requestedVrComponent;
ai.rotationAnimation = a.rotationAnimation;
ai.colorMode = a.colorMode;
ai.preferMinimalPostProcessing = a.preferMinimalPostProcessing;
ai.windowLayout = a.windowLayout;
ai.metaData = a.getMetaData();
ai.applicationInfo = applicationInfo;
return ai;
}
@Nullable
public static ActivityInfo generateActivityInfo(ParsingPackageRead pkg, ParsedActivity a,
@PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) {
return generateActivityInfo(pkg, a, flags, state, null, userId);
}
@Nullable
public static ServiceInfo generateServiceInfo(ParsingPackageRead pkg, ParsedService s,
@PackageManager.ComponentInfoFlags int flags, PackageUserState state,
@Nullable ApplicationInfo applicationInfo, int userId) {
if (s == null) return null;
if (!checkUseInstalled(pkg, state, flags)) {
return null;
}
if (applicationInfo == null) {
applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
}
// Make shallow copies so we can store the metadata safely
ServiceInfo si = new ServiceInfo();
assignSharedFieldsForComponentInfo(si, s);
si.exported = s.exported;
si.flags = s.flags;
si.metaData = s.getMetaData();
si.permission = s.getPermission();
si.processName = s.getProcessName();
si.mForegroundServiceType = s.foregroundServiceType;
si.applicationInfo = applicationInfo;
return si;
}
@Nullable
public static ServiceInfo generateServiceInfo(ParsingPackageRead pkg, ParsedService s,
@PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) {
return generateServiceInfo(pkg, s, flags, state, null, userId);
}
@Nullable
public static ProviderInfo generateProviderInfo(ParsingPackageRead pkg, ParsedProvider p,
@PackageManager.ComponentInfoFlags int flags, PackageUserState state,
@Nullable ApplicationInfo applicationInfo, int userId) {
if (p == null) return null;
if (!checkUseInstalled(pkg, state, flags)) {
return null;
}
if (applicationInfo == null) {
applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
}
// Make shallow copies so we can store the metadata safely
ProviderInfo pi = new ProviderInfo();
assignSharedFieldsForComponentInfo(pi, p);
pi.exported = p.isExported();
pi.flags = p.getFlags();
pi.processName = p.getProcessName();
pi.authority = p.getAuthority();
pi.isSyncable = p.isSyncable();
pi.readPermission = p.getReadPermission();
pi.writePermission = p.getWritePermission();
pi.grantUriPermissions = p.isGrantUriPermissions();
pi.forceUriPermissions = p.isForceUriPermissions();
pi.multiprocess = p.isMultiProcess();
pi.initOrder = p.getInitOrder();
pi.uriPermissionPatterns = p.getUriPermissionPatterns();
pi.pathPermissions = p.getPathPermissions();
pi.metaData = p.getMetaData();
if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) {
pi.uriPermissionPatterns = null;
}
pi.applicationInfo = applicationInfo;
return pi;
}
@Nullable
public static ProviderInfo generateProviderInfo(ParsingPackageRead pkg, ParsedProvider p,
@PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) {
return generateProviderInfo(pkg, p, flags, state, null, userId);
}
@Nullable
public static InstrumentationInfo generateInstrumentationInfo(ParsedInstrumentation i,
ParsingPackageRead pkg, @PackageManager.ComponentInfoFlags int flags, int userId) {
if (i == null) return null;
InstrumentationInfo ii = new InstrumentationInfo();
assignSharedFieldsForPackageItemInfo(ii, i);
ii.targetPackage = i.getTargetPackage();
ii.targetProcesses = i.getTargetProcesses();
ii.handleProfiling = i.handleProfiling;
ii.functionalTest = i.functionalTest;
ii.sourceDir = pkg.getBaseCodePath();
ii.publicSourceDir = pkg.getBaseCodePath();
ii.splitNames = pkg.getSplitNames();
ii.splitSourceDirs = pkg.getSplitCodePaths();
ii.splitPublicSourceDirs = pkg.getSplitCodePaths();
ii.splitDependencies = pkg.getSplitDependencies();
ii.dataDir = getDataDir(pkg, UserHandle.myUserId()).getAbsolutePath();
ii.deviceProtectedDataDir = getDeviceProtectedDataDir(pkg, userId)
.getAbsolutePath();
ii.credentialProtectedDataDir = getCredentialProtectedDataDir(pkg,
userId).getAbsolutePath();
if ((flags & PackageManager.GET_META_DATA) == 0) {
return ii;
}
ii.metaData = i.getMetaData();
return ii;
}
@Nullable
public static PermissionInfo generatePermissionInfo(ParsedPermission p,
@PackageManager.ComponentInfoFlags int flags) {
if (p == null) return null;
PermissionInfo pi = new PermissionInfo(p.backgroundPermission);
assignSharedFieldsForPackageItemInfo(pi, p);
pi.group = p.getGroup();
pi.requestRes = p.requestRes;
pi.protectionLevel = p.protectionLevel;
pi.descriptionRes = p.descriptionRes;
pi.flags = p.flags;
if ((flags & PackageManager.GET_META_DATA) == 0) {
return pi;
}
pi.metaData = p.getMetaData();
return pi;
}
@Nullable
public static PermissionGroupInfo generatePermissionGroupInfo(ParsedPermissionGroup pg,
@PackageManager.ComponentInfoFlags int flags) {
if (pg == null) return null;
PermissionGroupInfo pgi = new PermissionGroupInfo(
pg.requestDetailResourceId,
pg.backgroundRequestResourceId,
pg.backgroundRequestDetailResourceId
);
assignSharedFieldsForPackageItemInfo(pgi, pg);
pgi.descriptionRes = pg.descriptionRes;
pgi.priority = pg.priority;
pgi.requestRes = pg.requestRes;
pgi.flags = pg.flags;
if ((flags & PackageManager.GET_META_DATA) == 0) {
return pgi;
}
pgi.metaData = pg.getMetaData();
return pgi;
}
private static void assignSharedFieldsForComponentInfo(@NonNull ComponentInfo componentInfo,
@NonNull ParsedMainComponent mainComponent) {
assignSharedFieldsForPackageItemInfo(componentInfo, mainComponent);
componentInfo.descriptionRes = mainComponent.descriptionRes;
componentInfo.directBootAware = mainComponent.isDirectBootAware();
componentInfo.enabled = mainComponent.isEnabled();
componentInfo.splitName = mainComponent.getSplitName();
}
private static void assignSharedFieldsForPackageItemInfo(
@NonNull PackageItemInfo packageItemInfo, @NonNull ParsedComponent component) {
packageItemInfo.nonLocalizedLabel = component.nonLocalizedLabel;
packageItemInfo.icon = component.icon;
packageItemInfo.banner = component.banner;
packageItemInfo.labelRes = component.labelRes;
packageItemInfo.logo = component.logo;
packageItemInfo.name = component.getName();
packageItemInfo.packageName = component.getPackageName();
}
@CheckResult
private static int flag(boolean hasFlag, int flag) {
if (hasFlag) {
return flag;
} else {
return 0;
}
}
/** @see ApplicationInfo#flags */
public static int appInfoFlags(ParsingPackageRead pkg) {
// @formatter:off
return flag(pkg.isExternalStorage(), ApplicationInfo.FLAG_EXTERNAL_STORAGE)
| flag(pkg.isBaseHardwareAccelerated(), ApplicationInfo.FLAG_HARDWARE_ACCELERATED)
| flag(pkg.isAllowBackup(), ApplicationInfo.FLAG_ALLOW_BACKUP)
| flag(pkg.isKillAfterRestore(), ApplicationInfo.FLAG_KILL_AFTER_RESTORE)
| flag(pkg.isRestoreAnyVersion(), ApplicationInfo.FLAG_RESTORE_ANY_VERSION)
| flag(pkg.isFullBackupOnly(), ApplicationInfo.FLAG_FULL_BACKUP_ONLY)
| flag(pkg.isPersistent(), ApplicationInfo.FLAG_PERSISTENT)
| flag(pkg.isDebuggable(), ApplicationInfo.FLAG_DEBUGGABLE)
| flag(pkg.isVmSafeMode(), ApplicationInfo.FLAG_VM_SAFE_MODE)
| flag(pkg.isHasCode(), ApplicationInfo.FLAG_HAS_CODE)
| flag(pkg.isAllowTaskReparenting(), ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING)
| flag(pkg.isAllowClearUserData(), ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA)
| flag(pkg.isLargeHeap(), ApplicationInfo.FLAG_LARGE_HEAP)
| flag(pkg.isUsesCleartextTraffic(), ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC)
| flag(pkg.isSupportsRtl(), ApplicationInfo.FLAG_SUPPORTS_RTL)
| flag(pkg.isTestOnly(), ApplicationInfo.FLAG_TEST_ONLY)
| flag(pkg.isMultiArch(), ApplicationInfo.FLAG_MULTIARCH)
| flag(pkg.isExtractNativeLibs(), ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS)
| flag(pkg.isGame(), ApplicationInfo.FLAG_IS_GAME)
| flag(pkg.isSupportsSmallScreens(), ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS)
| flag(pkg.isSupportsNormalScreens(), ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS)
| flag(pkg.isSupportsLargeScreens(), ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS)
| flag(pkg.isSupportsExtraLargeScreens(), ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS)
| flag(pkg.isResizeable(), ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS)
| flag(pkg.isAnyDensity(), ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES);
// @formatter:on
}
/** @see ApplicationInfo#privateFlags */
public static int appInfoPrivateFlags(ParsingPackageRead pkg) {
// @formatter:off
int privateFlags = flag(pkg.isStaticSharedLibrary(), ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY)
| flag(pkg.isOverlay(), ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY)
| flag(pkg.isIsolatedSplitLoading(), ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING)
| flag(pkg.isHasDomainUrls(), ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS)
| flag(pkg.isProfileableByShell(), ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL)
| flag(pkg.isBackupInForeground(), ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND)
| flag(pkg.isUseEmbeddedDex(), ApplicationInfo.PRIVATE_FLAG_USE_EMBEDDED_DEX)
| flag(pkg.isDefaultToDeviceProtectedStorage(), ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE)
| flag(pkg.isDirectBootAware(), ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE)
| flag(pkg.isPartiallyDirectBootAware(), ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE)
| flag(pkg.isAllowClearUserDataOnFailedRestore(), ApplicationInfo.PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE)
| flag(pkg.isAllowAudioPlaybackCapture(), ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE)
| flag(pkg.isRequestLegacyExternalStorage(), ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE)
| flag(pkg.isUsesNonSdkApi(), ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API)
| flag(pkg.isHasFragileUserData(), ApplicationInfo.PRIVATE_FLAG_HAS_FRAGILE_USER_DATA)
| flag(pkg.isCantSaveState(), ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
| flag(pkg.isResizeableActivityViaSdkVersion(), ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION)
| flag(pkg.isAllowNativeHeapPointerTagging(), ApplicationInfo.PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING);
// @formatter:on
Boolean resizeableActivity = pkg.getResizeableActivity();
if (resizeableActivity != null) {
if (resizeableActivity) {
privateFlags |= ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE;
} else {
privateFlags |= ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE;
}
}
return privateFlags;
}
private static boolean checkUseInstalled(ParsingPackageRead pkg, PackageUserState state,
@PackageManager.PackageInfoFlags int flags) {
// If available for the target user
return state.isAvailable(flags);
}
@NonNull
public static File getDataDir(ParsingPackageRead pkg, int userId) {
if ("android".equals(pkg.getPackageName())) {
return Environment.getDataSystemDirectory();
}
if (pkg.isDefaultToDeviceProtectedStorage()
&& PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) {
return getDeviceProtectedDataDir(pkg, userId);
} else {
return getCredentialProtectedDataDir(pkg, userId);
}
}
@NonNull
public static File getDeviceProtectedDataDir(ParsingPackageRead pkg, int userId) {
return Environment.getDataUserDePackageDirectory(pkg.getVolumeUuid(), userId,
pkg.getPackageName());
}
@NonNull
public static File getCredentialProtectedDataDir(ParsingPackageRead pkg, int userId) {
return Environment.getDataUserCePackageDirectory(pkg.getVolumeUuid(), userId,
pkg.getPackageName());
}
}

View File

@@ -61,7 +61,7 @@ import com.android.internal.util.Parcelling.BuiltIn.ForBoolean;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedStringArray;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedStringList;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedStringMap;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedStringValueMap;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedStringSet;
import java.security.PublicKey;
@@ -159,7 +159,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
private int overlayPriority;
private boolean overlayIsStatic;
@NonNull
@DataClass.ParcelWith(ForInternedStringMap.class)
@DataClass.ParcelWith(ForInternedStringValueMap.class)
private Map<String, String> overlayables = emptyMap();
@Nullable

View File

@@ -26,6 +26,7 @@ import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTEN
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
import static android.os.Build.VERSION_CODES.DONUT;
import static android.os.Build.VERSION_CODES.O;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
@@ -99,10 +100,10 @@ import java.util.Set;
import java.util.StringTokenizer;
/** @hide */
public class ApkParseUtils {
public class ParsingPackageUtils {
// TODO(b/135203078): Consolidate log tags
static final String TAG = "PackageParsing";
public static final String TAG = "PackageParsing";
/**
* Parse the package at the given location. Automatically detects if the
@@ -114,7 +115,7 @@ public class ApkParseUtils {
* and unique split names.
* <p>
* Note that this <em>does not</em> perform signature verification; that
* must be done separately in {@link #collectCertificates(ParsedPackage, boolean)}.
* must be done separately in {@link #collectCertificates(ParsingPackageRead, boolean)}.
*
* If {@code useCaches} is true, the package parser might return a cached
* result from a previous parse of the same {@code packageFile} with the same
@@ -126,7 +127,7 @@ public class ApkParseUtils {
public static ParsingPackage parsePackage(
ParseInput parseInput,
String[] separateProcesses,
PackageParser.Callback callback,
Callback callback,
DisplayMetrics displayMetrics,
boolean onlyCoreApps,
File packageFile,
@@ -148,12 +149,12 @@ public class ApkParseUtils {
* split names.
* <p>
* Note that this <em>does not</em> perform signature verification; that
* must be done separately in {@link #collectCertificates(ParsedPackage, boolean)}.
* must be done separately in {@link #collectCertificates(ParsingPackageRead, boolean)}.
*/
private static ParsingPackage parseClusterPackage(
ParseInput parseInput,
String[] separateProcesses,
PackageParser.Callback callback,
Callback callback,
DisplayMetrics displayMetrics,
boolean onlyCoreApps,
File packageDir,
@@ -184,7 +185,7 @@ public class ApkParseUtils {
final AssetManager assets = assetLoader.getBaseAssetManager();
final File baseApk = new File(lite.baseCodePath);
ParsingPackage parsingPackage = parseBaseApk(parseInput, separateProcesses, callback,
displayMetrics, baseApk, assets, flags);
displayMetrics, baseApk, lite.codePath, assets, flags);
if (parsingPackage == null) {
throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
"Failed to parse base APK: " + baseApk);
@@ -206,8 +207,7 @@ public class ApkParseUtils {
}
}
return parsingPackage.setCodePath(lite.codePath)
.setUse32BitAbi(lite.use32bitAbi);
return parsingPackage.setUse32BitAbi(lite.use32bitAbi);
} finally {
IoUtils.closeQuietly(assetLoader);
}
@@ -217,12 +217,12 @@ public class ApkParseUtils {
* Parse the given APK file, treating it as as a single monolithic package.
* <p>
* Note that this <em>does not</em> perform signature verification; that
* must be done separately in {@link #collectCertificates(AndroidPackage, boolean)}.
* must be done separately in {@link #collectCertificates(ParsingPackageRead, boolean)}.
*/
public static ParsingPackage parseMonolithicPackage(
ParseInput parseInput,
String[] separateProcesses,
PackageParser.Callback callback,
Callback callback,
DisplayMetrics displayMetrics,
boolean onlyCoreApps,
File apkFile,
@@ -240,8 +240,8 @@ public class ApkParseUtils {
final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags);
try {
return parseBaseApk(parseInput, separateProcesses, callback,
displayMetrics, apkFile, assetLoader.getBaseAssetManager(), flags)
.setCodePath(apkFile.getCanonicalPath())
displayMetrics, apkFile, apkFile.getCanonicalPath(),
assetLoader.getBaseAssetManager(), flags)
.setUse32BitAbi(lite.use32bitAbi);
} catch (IOException e) {
throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
@@ -251,14 +251,9 @@ public class ApkParseUtils {
}
}
private static ParsingPackage parseBaseApk(
ParseInput parseInput,
String[] separateProcesses,
PackageParser.Callback callback,
DisplayMetrics displayMetrics,
File apkFile,
AssetManager assets,
int flags
private static ParsingPackage parseBaseApk(ParseInput parseInput, String[] separateProcesses,
Callback callback, DisplayMetrics displayMetrics, File apkFile,
String codePath, AssetManager assets, int flags
) throws PackageParserException {
final String apkPath = apkFile.getAbsolutePath();
@@ -280,8 +275,8 @@ public class ApkParseUtils {
parser = assets.openXmlResourceParser(cookie, PackageParser.ANDROID_MANIFEST_FILENAME);
final Resources res = new Resources(assets, displayMetrics, null);
ParseResult result = parseBaseApk(parseInput, separateProcesses, callback, apkPath, res,
parser, flags);
ParseResult result = parseBaseApk(parseInput, separateProcesses, callback, apkPath,
codePath, res, parser, flags);
if (!result.isSuccess()) {
throw new PackageParserException(result.getParseError(),
apkPath + " (at " + parser.getPositionDescription() + "): "
@@ -305,7 +300,6 @@ public class ApkParseUtils {
}
return pkg.setVolumeUuid(volumeUuid)
.setApplicationVolumeUuid(volumeUuid)
.setSigningDetails(SigningDetails.UNKNOWN);
} catch (PackageParserException e) {
throw e;
@@ -372,14 +366,9 @@ public class ApkParseUtils {
* @param flags Flags how to parse
* @return Parsed package or null on error.
*/
private static ParseResult parseBaseApk(
ParseInput parseInput,
String[] separateProcesses,
PackageParser.Callback callback,
String apkPath,
Resources res,
XmlResourceParser parser,
int flags
private static ParseResult parseBaseApk(ParseInput parseInput, String[] separateProcesses,
Callback callback, String apkPath, String codePath, Resources res,
XmlResourceParser parser, int flags
) throws XmlPullParserException, IOException {
final String splitName;
final String pkgName;
@@ -407,12 +396,8 @@ public class ApkParseUtils {
boolean isCoreApp = parser.getAttributeBooleanValue(null, "coreApp", false);
ParsingPackage parsingPackage = PackageImpl.forParsing(
pkgName,
apkPath,
manifestArray,
isCoreApp
);
ParsingPackage parsingPackage = callback.startParsingPackage(pkgName, apkPath, codePath,
manifestArray, isCoreApp);
ParseResult result = parseBaseApkTags(parseInput, separateProcesses, callback,
parsingPackage, manifestArray, res, parser, flags);
@@ -645,7 +630,7 @@ public class ApkParseUtils {
// remain null in the primary copy (we like to avoid extra copies because
// it can be large)
Bundle appMetaData = parseMetaData(parsingPackage, res, parser,
parsingPackage.getAppMetaData(),
parsingPackage.getMetaData(),
outError);
if (appMetaData == null) {
return parseInput.error(
@@ -654,7 +639,7 @@ public class ApkParseUtils {
);
}
parsingPackage.setAppMetaData(appMetaData);
parsingPackage.setMetaData(appMetaData);
break;
case "uses-static-library":
ParseResult parseResult = parseUsesStaticLibrary(parseInput, parsingPackage,
@@ -727,7 +712,7 @@ public class ApkParseUtils {
private static ParseResult parseBaseApkTags(
ParseInput parseInput,
String[] separateProcesses,
PackageParser.Callback callback,
Callback callback,
ParsingPackage parsingPackage,
TypedArray manifestArray,
Resources res,
@@ -897,13 +882,23 @@ public class ApkParseUtils {
// At this point we can check if an application is not supporting densities and hence
// cannot be windowed / resized. Note that an SDK version of 0 is common for
// pre-Doughnut applications.
if (parsingPackage.usesCompatibilityMode()) {
if (usesCompatibilityMode(parsingPackage)) {
adjustPackageToBeUnresizeableAndUnpipable(parsingPackage);
}
return parseInput.success(parsingPackage);
}
public static boolean usesCompatibilityMode(ParsingPackage pkg) {
return pkg.getTargetSdkVersion() < DONUT
|| (!pkg.isSupportsSmallScreens()
&& !pkg.isSupportsNormalScreens()
&& !pkg.isSupportsLargeScreens()
&& !pkg.isSupportsExtraLargeScreens()
&& !pkg.isResizeable()
&& !pkg.isAnyDensity());
}
private static ParseResult parseUnknownTag(
ParseInput parseInput,
ParsingPackage parsingPackage,
@@ -1234,20 +1229,11 @@ public class ApkParseUtils {
);
}
parsingPackage.setName(outInfoName);
parsingPackage.setClassName(outInfoName);
}
int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(roundIconRes, 0) : 0;
if (roundIconVal != 0) {
parsingPackage.setIcon(roundIconVal)
.setNonLocalizedLabel(null);
} else {
int iconVal = sa.getResourceId(iconRes, 0);
if (iconVal != 0) {
parsingPackage.setIcon(iconVal)
.setNonLocalizedLabel(null);
}
}
parsingPackage.setRoundIconRes(sa.getResourceId(roundIconRes, 0))
.setIconRes(sa.getResourceId(iconRes, 0));
int logoVal = sa.getResourceId(logoRes, 0);
if (logoVal != 0) {
@@ -1375,7 +1361,7 @@ public class ApkParseUtils {
ParsingPackage parsingPackage,
Resources res,
XmlResourceParser parser,
PackageParser.Callback callback
Callback callback
)
throws XmlPullParserException, IOException {
TypedArray sa = res.obtainAttributes(parser,
@@ -1854,7 +1840,7 @@ public class ApkParseUtils {
public static ParseResult parseBaseApplication(
ParseInput parseInput,
String[] separateProcesses,
PackageParser.Callback callback,
Callback callback,
ParsingPackage parsingPackage,
Resources res,
XmlResourceParser parser,
@@ -1893,11 +1879,6 @@ public class ApkParseUtils {
return result;
}
String name = parsingPackage.getName();
if (name != null) {
parsingPackage.setClassName(name);
}
String manageSpaceActivity = sa.getNonConfigurationString(
R.styleable.AndroidManifestApplication_manageSpaceActivity,
Configuration.NATIVE_CONFIG_VERSION);
@@ -2078,10 +2059,10 @@ public class ApkParseUtils {
R.styleable.AndroidManifestApplication_directBootAware, false));
if (sa.hasValueOrEmpty(R.styleable.AndroidManifestApplication_resizeableActivity)) {
parsingPackage.setActivitiesResizeModeResizeable(sa.getBoolean(
parsingPackage.setResizeableActivity(sa.getBoolean(
R.styleable.AndroidManifestApplication_resizeableActivity, true));
} else {
parsingPackage.setActivitiesResizeModeResizeableViaSdkVersion(
parsingPackage.setResizeableActivityViaSdkVersion(
parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.N);
}
@@ -2195,7 +2176,7 @@ public class ApkParseUtils {
parsingPackage.setCrossProfile(
sa.getBoolean(R.styleable.AndroidManifestApplication_crossProfile, false));
parsingPackage.setIsGame(sa.getBoolean(
parsingPackage.setGame(sa.getBoolean(
R.styleable.AndroidManifestApplication_isGame, false));
boolean cantSaveState = sa.getBoolean(
@@ -2334,7 +2315,7 @@ public class ApkParseUtils {
// remain null in the primary copy (we like to avoid extra copies because
// it can be large)
Bundle appMetaData = parseMetaData(parsingPackage, res, parser,
parsingPackage.getAppMetaData(),
parsingPackage.getMetaData(),
outError);
if (appMetaData == null) {
return parseInput.error(
@@ -2343,7 +2324,7 @@ public class ApkParseUtils {
);
}
parsingPackage.setAppMetaData(appMetaData);
parsingPackage.setMetaData(appMetaData);
break;
case "static-library":
sa = res.obtainAttributes(parser,
@@ -2728,7 +2709,7 @@ public class ApkParseUtils {
// Use the application max aspect ration as default if set.
maxAspectRatio = packageMaxAspectRatio;
} else {
Bundle appMetaData = parsingPackage.getAppMetaData();
Bundle appMetaData = parsingPackage.getMetaData();
if (appMetaData != null && appMetaData.containsKey(
PackageParser.METADATA_MAX_ASPECT_RATIO)) {
maxAspectRatio = appMetaData.getFloat(PackageParser.METADATA_MAX_ASPECT_RATIO,
@@ -2764,7 +2745,7 @@ public class ApkParseUtils {
*/
private static void setMinAspectRatio(
ParsingPackage parsingPackage,
PackageParser.Callback callback
Callback callback
) {
final float minAspectRatio;
float packageMinAspectRatio = parsingPackage.getMinAspectRatio();
@@ -2845,7 +2826,7 @@ public class ApkParseUtils {
}
parsingPackage
.setIsOverlay(true)
.setOverlay(true)
.setOverlayTarget(target)
.setOverlayTargetName(targetName)
.setOverlayCategory(category)
@@ -2907,7 +2888,7 @@ public class ApkParseUtils {
sa.getInteger(R.styleable.AndroidManifestSupportsScreens_normalScreens, 1))
.setSupportsLargeScreens(
sa.getInteger(R.styleable.AndroidManifestSupportsScreens_largeScreens, 1))
.setSupportsXLargeScreens(
.setSupportsExtraLargeScreens(
sa.getInteger(R.styleable.AndroidManifestSupportsScreens_xlargeScreens, 1))
.setResizeable(
sa.getInteger(R.styleable.AndroidManifestSupportsScreens_resizeable, 1))
@@ -2960,7 +2941,7 @@ public class ApkParseUtils {
R.styleable.AndroidManifestOriginalPackage_name,
0);
if (!parsingPackage.getPackageName().equals(orig)) {
if (parsingPackage.getOriginalPackages() == null) {
if (parsingPackage.getOriginalPackages().isEmpty()) {
parsingPackage.setRealPackage(parsingPackage.getPackageName());
}
parsingPackage.addOriginalPackage(orig);
@@ -3186,36 +3167,36 @@ public class ApkParseUtils {
}
/**
* Collect certificates from all the APKs described in the given package,
* populating {@link AndroidPackageWrite#setSigningDetails(SigningDetails)}. Also asserts that
* Collect certificates from all the APKs described in the given package. Also asserts that
* all APK contents are signed correctly and consistently.
*/
public static void collectCertificates(AndroidPackage pkg, boolean skipVerify)
public static SigningDetails collectCertificates(ParsingPackageRead pkg, boolean skipVerify)
throws PackageParserException {
pkg.mutate().setSigningDetails(SigningDetails.UNKNOWN);
SigningDetails signingDetails = SigningDetails.UNKNOWN;
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
try {
pkg.mutate().setSigningDetails(collectCertificates(
signingDetails = collectCertificates(
pkg.getBaseCodePath(),
skipVerify,
pkg.isStaticSharedLibrary(),
pkg.getSigningDetails(),
signingDetails,
pkg.getTargetSdkVersion()
));
);
String[] splitCodePaths = pkg.getSplitCodePaths();
if (!ArrayUtils.isEmpty(splitCodePaths)) {
for (int i = 0; i < splitCodePaths.length; i++) {
pkg.mutate().setSigningDetails(collectCertificates(
signingDetails = collectCertificates(
splitCodePaths[i],
skipVerify,
pkg.isStaticSharedLibrary(),
pkg.getSigningDetails(),
signingDetails,
pkg.getTargetSdkVersion()
));
);
}
}
return signingDetails;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
@@ -3346,4 +3327,15 @@ public class ApkParseUtils {
return errorMessage;
}
}
/**
* Callback interface for retrieving information that may be needed while parsing
* a package.
*/
public interface Callback {
boolean hasFeature(String feature);
ParsingPackage startParsingPackage(String packageName, String baseCodePath, String codePath,
TypedArray manifestArray, boolean isCoreApp);
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.content.pm.parsing;
import android.annotation.Nullable;
/** @hide **/
public class ParsingUtils {
// TODO(b/135203078): Consolidate log tags
public static final String TAG = "PackageParsing";
@Nullable
public static String buildClassName(String pkg, CharSequence clsSeq) {
if (clsSeq == null || clsSeq.length() <= 0) {
return null;
}
String cls = clsSeq.toString();
char c = cls.charAt(0);
if (c == '.') {
return pkg + cls;
}
if (cls.indexOf('.') < 0) {
StringBuilder b = new StringBuilder(pkg);
b.append('.');
b.append(cls);
return b.toString();
}
return cls;
}
}

View File

@@ -19,7 +19,7 @@ package com.android.internal.content.om;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.PackagePartitions;
import android.content.pm.parsing.AndroidPackage;
import android.content.pm.parsing.ParsingPackageRead;
import android.os.Build;
import android.os.Process;
import android.os.Trace;
@@ -36,7 +36,7 @@ import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.function.Consumer;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
/**
@@ -71,10 +71,10 @@ public class OverlayConfig {
* Interface for providing information on scanned packages.
* TODO(147840005): Remove this when android:isStatic and android:priority are fully deprecated
*/
public interface AndroidPackageProvider {
public interface PackageProvider {
/** Performs the given action for each package. */
void forEachPackage(Consumer<AndroidPackage> p);
void forEachPackage(BiConsumer<ParsingPackageRead, Boolean> p);
}
private static final Comparator<ParsedConfiguration> sStaticOverlayComparator = (c1, c2) -> {
@@ -100,7 +100,7 @@ public class OverlayConfig {
@VisibleForTesting
public OverlayConfig(@Nullable File rootDirectory,
@Nullable Supplier<OverlayScanner> scannerFactory,
@Nullable AndroidPackageProvider packageProvider) {
@Nullable PackageProvider packageProvider) {
Preconditions.checkArgument((scannerFactory == null) != (packageProvider == null),
"scannerFactory and packageProvider cannot be both null or both non-null");
@@ -208,7 +208,7 @@ public class OverlayConfig {
* {@link #getSystemInstance()} will return the initialized instance.
*/
@NonNull
public static OverlayConfig initializeSystemInstance(AndroidPackageProvider packageProvider) {
public static OverlayConfig initializeSystemInstance(PackageProvider packageProvider) {
if (Process.myUid() != Process.SYSTEM_UID) {
throw new IllegalStateException("Can only be invoked in the system process");
}
@@ -221,7 +221,7 @@ public class OverlayConfig {
/**
* Retrieves the singleton instance initialized by
* {@link #initializeSystemInstance(AndroidPackageProvider)}.
* {@link #initializeSystemInstance(PackageProvider)}.
*/
@NonNull
public static OverlayConfig getSystemInstance() {
@@ -291,10 +291,10 @@ public class OverlayConfig {
@NonNull
private static ArrayList<ParsedOverlayInfo> getOverlayPackageInfos(
@NonNull AndroidPackageProvider packageManager) {
@NonNull PackageProvider packageManager) {
final ArrayList<ParsedOverlayInfo> overlays = new ArrayList<>();
packageManager.forEachPackage((AndroidPackage p) -> {
if (p.getOverlayTarget() != null && p.isSystem()) {
packageManager.forEachPackage((ParsingPackageRead p, Boolean isSystem) -> {
if (p.getOverlayTarget() != null && isSystem) {
overlays.add(new ParsedOverlayInfo(p.getPackageName(), p.getOverlayTarget(),
p.getTargetSdkVersion(), p.isOverlayIsStatic(), p.getOverlayPriority(),
new File(p.getBaseCodePath())));

View File

@@ -15,10 +15,18 @@
*/
package com.android.internal.util;
import static java.util.Collections.emptySet;
import android.annotation.Nullable;
import android.os.Parcel;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
/**
@@ -90,6 +98,132 @@ public interface Parcelling<T> {
*/
interface BuiltIn {
class ForInternedString implements Parcelling<String> {
@Override
public void parcel(@Nullable String item, Parcel dest, int parcelFlags) {
dest.writeString(item);
}
@Nullable
@Override
public String unparcel(Parcel source) {
return TextUtils.safeIntern(source.readString());
}
}
class ForInternedStringArray implements Parcelling<String[]> {
@Override
public void parcel(String[] item, Parcel dest, int parcelFlags) {
dest.writeStringArray(item);
}
@Nullable
@Override
public String[] unparcel(Parcel source) {
String[] array = source.readStringArray();
if (array != null) {
int size = ArrayUtils.size(array);
for (int index = 0; index < size; index++) {
array[index] = TextUtils.safeIntern(array[index]);
}
}
return array;
}
}
class ForInternedStringList implements Parcelling<List<String>> {
@Override
public void parcel(List<String> item, Parcel dest, int parcelFlags) {
dest.writeStringList(item);
}
@Override
public List<String> unparcel(Parcel source) {
ArrayList<String> list = source.createStringArrayList();
if (list != null) {
int size = list.size();
for (int index = 0; index < size; index++) {
list.set(index, list.get(index).intern());
}
}
return CollectionUtils.emptyIfNull(list);
}
}
class ForInternedStringValueMap implements Parcelling<Map<String, String>> {
@Override
public void parcel(Map<String, String> item, Parcel dest, int parcelFlags) {
dest.writeMap(item);
}
@Override
public Map<String, String> unparcel(Parcel source) {
ArrayMap<String, String> map = new ArrayMap<>();
source.readMap(map, String.class.getClassLoader());
for (int index = 0; index < map.size(); index++) {
map.setValueAt(index, TextUtils.safeIntern(map.valueAt(index)));
}
return map;
}
}
class ForInternedStringSet implements Parcelling<Set<String>> {
@Override
public void parcel(Set<String> item, Parcel dest, int parcelFlags) {
if (item == null) {
dest.writeInt(-1);
} else {
dest.writeInt(item.size());
for (String string : item) {
dest.writeString(string);
}
}
}
@Override
public Set<String> unparcel(Parcel source) {
final int size = source.readInt();
if (size < 0) {
return emptySet();
}
Set<String> set = new ArraySet<>();
for (int count = 0; count < size; count++) {
set.add(TextUtils.safeIntern(source.readString()));
}
return set;
}
}
class ForBoolean implements Parcelling<Boolean> {
@Override
public void parcel(@Nullable Boolean item, Parcel dest, int parcelFlags) {
if (item == null) {
// This writes 1 for null to mirror TypedArray.getInteger(booleanResId, 1)
dest.writeInt(1);
} else if (!item) {
dest.writeInt(0);
} else {
dest.writeInt(-1);
}
}
@Nullable
@Override
public Boolean unparcel(Parcel source) {
switch (source.readInt()) {
default:
throw new IllegalStateException("Malformed Parcel reading Boolean: "
+ source);
case 1:
return null;
case 0:
return Boolean.FALSE;
case -1:
return Boolean.TRUE;
}
}
}
class ForPattern implements Parcelling<Pattern> {
@Override

View File

@@ -21,11 +21,11 @@ import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.when;
import android.content.pm.parsing.AndroidPackage;
import android.content.pm.parsing.ParsingPackageRead;
import android.os.Build;
import android.util.ArrayMap;
import com.android.internal.content.om.OverlayConfig.AndroidPackageProvider;
import com.android.internal.content.om.OverlayConfig.PackageProvider;
import com.android.internal.content.om.OverlayScanner;
import com.android.internal.content.om.OverlayScanner.ParsedOverlayInfo;
@@ -39,14 +39,14 @@ import org.mockito.invocation.InvocationOnMock;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
/**
* A {@link TestRule} that runs a test case twice. First, the test case runs with a non-null
* {@link OverlayScanner} as if the zygote process is scanning the overlay packages
* and parsing configuration files. The test case then runs with a non-null
* {@link AndroidPackageProvider} as if the system server is parsing configuration files.
* {@link PackageProvider} as if the system server is parsing configuration files.
*
* This simulates what will happen on device. If an exception would be thrown in the zygote, then
* the exception should be thrown in the first run of the test case.
@@ -60,7 +60,7 @@ public class OverlayConfigIterationRule implements TestRule {
private final ArrayMap<File, ParsedOverlayInfo> mOverlayStubResults = new ArrayMap<>();
private Supplier<OverlayScanner> mOverlayScanner;
private AndroidPackageProvider mAndroidPackageProvider;
private PackageProvider mPkgProvider;
private Iteration mIteration;
/**
@@ -96,9 +96,9 @@ public class OverlayConfigIterationRule implements TestRule {
return mOverlayScanner;
}
/** Retrieves the {@link AndroidPackageProvider} for the current run of the test. */
AndroidPackageProvider getPackageProvider() {
return mAndroidPackageProvider;
/** Retrieves the {@link PackageProvider} for the current run of the test. */
PackageProvider getPackageProvider() {
return mPkgProvider;
}
/** Retrieves the current iteration of the test. */
@@ -123,7 +123,7 @@ public class OverlayConfigIterationRule implements TestRule {
}
return scanner;
};
mAndroidPackageProvider = null;
mPkgProvider = null;
mIteration = Iteration.ZYGOTE;
base.evaluate();
@@ -131,14 +131,15 @@ public class OverlayConfigIterationRule implements TestRule {
// the system server is parsing the configuration files and using PackageManager to
// retrieving information of overlays.
mOverlayScanner = null;
mAndroidPackageProvider = Mockito.mock(AndroidPackageProvider.class);
mPkgProvider = Mockito.mock(PackageProvider.class);
mIteration = Iteration.SYSTEM_SERVER;
doAnswer((InvocationOnMock invocation) -> {
final Object[] args = invocation.getArguments();
final Consumer<AndroidPackage> f = (Consumer<AndroidPackage>) args[0];
final BiConsumer<ParsingPackageRead, Boolean> f =
(BiConsumer<ParsingPackageRead, Boolean>) args[0];
for (Map.Entry<File, ParsedOverlayInfo> overlay :
mOverlayStubResults.entrySet()) {
final AndroidPackage a = Mockito.mock(AndroidPackage.class);
final ParsingPackageRead a = Mockito.mock(ParsingPackageRead.class);
final ParsedOverlayInfo info = overlay.getValue();
when(a.getPackageName()).thenReturn(info.packageName);
when(a.getOverlayTarget()).thenReturn(info.targetPackageName);
@@ -146,12 +147,10 @@ public class OverlayConfigIterationRule implements TestRule {
when(a.isOverlayIsStatic()).thenReturn(info.isStatic);
when(a.getOverlayPriority()).thenReturn(info.priority);
when(a.getBaseCodePath()).thenReturn(info.path.getPath());
when(a.isSystem()).thenReturn(
!info.path.getPath().contains("data/overlay"));
f.accept(a);
f.accept(a, !info.path.getPath().contains("data/overlay"));
}
return null;
}).when(mAndroidPackageProvider).forEachPackage(any());
}).when(mPkgProvider).forEachPackage(any());
base.evaluate();
}

View File

@@ -29,8 +29,10 @@ import android.content.pm.PackageManager.ApplicationInfoFlags;
import android.content.pm.PackageManager.ComponentInfoFlags;
import android.content.pm.PackageManager.PackageInfoFlags;
import android.content.pm.PackageManager.ResolveInfoFlags;
import android.content.pm.parsing.AndroidPackage;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import android.content.pm.parsing.ComponentParseUtils;
import android.content.pm.parsing.ComponentParseUtils.ParsedMainComponent;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.util.ArrayMap;
@@ -763,8 +765,8 @@ public abstract class PackageManagerInternal {
throws IOException;
/** Returns {@code true} if the specified component is enabled and matches the given flags. */
public abstract boolean isEnabledAndMatches(
@NonNull ComponentParseUtils.ParsedComponent component, int flags, int userId);
public abstract boolean isEnabledAndMatches(@NonNull ParsedMainComponent component, int flags,
int userId);
/** Returns {@code true} if the given user requires extra badging for icons. */
public abstract boolean userNeedsBadging(int userId);

View File

@@ -512,7 +512,7 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
try {
ParsedPackage pkg = parser.parseParsedPackage(installationPath, 0, false);
int flags = PackageManager.GET_SIGNING_CERTIFICATES | PackageManager.GET_META_DATA;
ApkParseUtils.collectCertificates(pkg, false);
pkg.setSigningDetails(ApkParseUtils.collectCertificates(pkg, false));
return PackageInfoUtils.generate(pkg, null, flags, 0, 0, null, new PackageUserState(),
UserHandle.getCallingUserId());
} catch (Exception e) {

View File

@@ -207,14 +207,14 @@ public class AppsFilter {
/** Returns true if the querying package may query for the potential target package */
private static boolean canQueryViaComponents(AndroidPackage querying,
AndroidPackage potentialTarget) {
if (querying.getQueriesIntents() != null) {
if (!querying.getQueriesIntents().isEmpty()) {
for (Intent intent : querying.getQueriesIntents()) {
if (matchesIntentFilters(intent, potentialTarget)) {
return true;
}
}
}
if (querying.getQueriesProviders() != null
if (!querying.getQueriesProviders().isEmpty()
&& matchesProviders(querying.getQueriesProviders(), potentialTarget)) {
return true;
}
@@ -223,7 +223,7 @@ public class AppsFilter {
private static boolean canQueryViaPackage(AndroidPackage querying,
AndroidPackage potentialTarget) {
return querying.getQueriesPackages() != null
return !querying.getQueriesPackages().isEmpty()
&& querying.getQueriesPackages().contains(potentialTarget.getPackageName());
}

View File

@@ -209,20 +209,16 @@ import android.content.pm.VersionedPackage;
import android.content.pm.dex.ArtManager;
import android.content.pm.dex.DexMetadataHelper;
import android.content.pm.dex.IArtManager;
import android.content.pm.parsing.AndroidPackage;
import android.content.pm.parsing.ApkParseUtils;
import android.content.pm.parsing.ComponentParseUtils;
import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
import android.content.pm.parsing.ComponentParseUtils.ParsedComponent;
import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
import android.content.pm.parsing.ComponentParseUtils.ParsedMainComponent;
import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
import android.content.pm.parsing.ComponentParseUtils.ParsedService;
import android.content.pm.parsing.PackageImpl;
import android.content.pm.parsing.PackageInfoUtils;
import android.content.pm.parsing.ParsedPackage;
import android.content.pm.parsing.library.PackageBackwardCompatibility;
import android.content.pm.parsing.ParsingPackageRead;
import android.content.pm.parsing.ParsingPackageUtils;
import android.content.res.Resources;
import android.content.rollback.IRollbackManager;
import android.database.ContentObserver;
@@ -341,6 +337,13 @@ import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.DexoptOptions;
import com.android.server.pm.dex.PackageDexUsage;
import com.android.server.pm.dex.ViewCompiler;
import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.parsing.library.PackageBackwardCompatibility;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.permission.BasePermission;
import com.android.server.pm.permission.PermissionManagerService;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
@@ -1011,13 +1014,13 @@ public class PackageManagerService extends IPackageManager.Stub
private final AppsFilter mAppsFilter;
class PackageParserCallback implements PackageParser.Callback {
class PackageParserCallback extends PackageParser2.Callback {
@Override public final boolean hasFeature(String feature) {
return PackageManagerService.this.hasSystemFeature(feature, 0);
}
}
final PackageParser.Callback mPackageParserCallback = new PackageParserCallback();
final PackageParser2.Callback mPackageParserCallback = new PackageParserCallback();
// Currently known shared libraries.
final ArrayMap<String, LongSparseArray<SharedLibraryInfo>> mSharedLibraries = new ArrayMap<>();
@@ -2033,7 +2036,7 @@ public class PackageManagerService extends IPackageManager.Stub
mInstantAppRegistry.onPackageInstalledLPw(res.pkg, res.newUsers);
}
final String packageName = res.pkg.getAppInfoPackageName();
final String packageName = res.pkg.getPackageName();
// Determine the set of users who are adding this package for
// the first time vs. those who are seeing an update.
@@ -2083,7 +2086,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Send added for users that see the package for the first time
// sendPackageAddedForNewUsers also deals with system apps
int appId = UserHandle.getAppId(res.uid);
boolean isSystem = res.pkg.isSystemApp();
boolean isSystem = res.pkg.isSystem();
sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload,
virtualPreload /*startReceiver*/, appId, firstUserIds, firstInstantUserIds);
@@ -2859,12 +2862,8 @@ public class PackageManagerService extends IPackageManager.Stub
final int systemParseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR;
final int systemScanFlags = scanFlags | SCAN_AS_SYSTEM;
PackageParser packageParser = new PackageParser();
packageParser.setSeparateProcesses(mSeparateProcesses);
packageParser.setOnlyCoreApps(mOnlyCore);
packageParser.setDisplayMetrics(mMetrics);
packageParser.setCacheDir(mCacheDir);
packageParser.setCallback(mPackageParserCallback);
PackageParser2 packageParser = new PackageParser2(mSeparateProcesses, mOnlyCore,
mMetrics, mCacheDir, mPackageParserCallback);
ExecutorService executorService = ParallelPackageParser.makeExecutorService();
// Collect vendor/product/system_ext overlay packages. (Do this before scanning
@@ -2902,7 +2901,9 @@ public class PackageManagerService extends IPackageManager.Stub
// Parse overlay configuration files to set default enable state, mutability, and
// priority of system overlays.
mOverlayConfig = OverlayConfig.initializeSystemInstance(mPmInternal::forEachPackage);
mOverlayConfig = OverlayConfig.initializeSystemInstance(
consumer -> mPmInternal.forEachPackage(
pkg -> consumer.accept(pkg, pkg.isSystem())));
// Prune any system packages that no longer exist.
final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>();
@@ -3044,7 +3045,7 @@ public class PackageManagerService extends IPackageManager.Stub
// special privileges
removePackageLI(pkg, true);
try {
final File codePath = new File(pkg.getAppInfoCodePath());
final File codePath = new File(pkg.getCodePath());
scanPackageTracedLI(codePath, 0, scanFlags, 0, null);
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse updated, ex-system package: "
@@ -4208,7 +4209,7 @@ public class PackageManagerService extends IPackageManager.Stub
throw new SecurityException("Package " + packageName + " is currently frozen!");
}
if (!userKeyUnlocked && !ps.pkg.isEncryptionAware()) {
if (!userKeyUnlocked && !AndroidPackageUtils.isEncryptionAware(ps.pkg)) {
throw new SecurityException("Package " + packageName + " is not encryption aware!");
}
}
@@ -4574,7 +4575,7 @@ public class PackageManagerService extends IPackageManager.Stub
// reader
synchronized (mLock) {
final AndroidPackage p = mPackages.get(packageName);
if (p != null && p.isMatch(flags)) {
if (p != null && AndroidPackageUtils.isMatchForSystemOnly(p, flags)) {
PackageSetting ps = getPackageSettingInternal(p.getPackageName(), callingUid);
if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
return -1;
@@ -4604,7 +4605,7 @@ public class PackageManagerService extends IPackageManager.Stub
// reader
synchronized (mLock) {
final AndroidPackage p = mPackages.get(packageName);
if (p != null && p.isMatch(flags)) {
if (p != null && AndroidPackageUtils.isMatchForSystemOnly(p, flags)) {
PackageSetting ps = getPackageSetting(p.getPackageName());
if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
return null;
@@ -8563,7 +8564,7 @@ public class PackageManagerService extends IPackageManager.Stub
return null;
}
final ParsedInstrumentation i = mInstrumentation.get(component);
return PackageInfoUtils.generateInstrumentationInfo(i, pkg, flags);
return PackageInfoUtils.generateInstrumentationInfo(i, pkg, flags, callingUserId);
}
}
@@ -8576,11 +8577,12 @@ public class PackageManagerService extends IPackageManager.Stub
if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
return ParceledListSlice.emptyList();
}
return new ParceledListSlice<>(queryInstrumentationInternal(targetPackage, flags));
return new ParceledListSlice<>(queryInstrumentationInternal(targetPackage, flags,
callingUserId));
}
private @NonNull List<InstrumentationInfo> queryInstrumentationInternal(String targetPackage,
int flags) {
int flags, int userId) {
ArrayList<InstrumentationInfo> finalList = new ArrayList<>();
// reader
@@ -8593,7 +8595,7 @@ public class PackageManagerService extends IPackageManager.Stub
AndroidPackage pkg = mPackages.get(p.getPackageName());
if (pkg != null) {
InstrumentationInfo ii = PackageInfoUtils.generateInstrumentationInfo(p,
pkg, flags);
pkg, flags, userId);
if (ii != null) {
finalList.add(ii);
}
@@ -8606,7 +8608,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags,
long currentTime, PackageParser packageParser, ExecutorService executorService) {
long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
try {
scanDirLI(scanDir, parseFlags, scanFlags, currentTime, packageParser, executorService);
@@ -8616,7 +8618,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime,
PackageParser packageParser, ExecutorService executorService) {
PackageParser2 packageParser, ExecutorService executorService) {
final File[] files = scanDir.listFiles();
if (ArrayUtils.isEmpty(files)) {
Log.d(TAG, "No files in app dir " + scanDir);
@@ -8720,7 +8722,8 @@ public class PackageManagerService extends IPackageManager.Stub
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
ApkParseUtils.collectCertificates(parsedPackage, skipVerify);
parsedPackage.setSigningDetails(
ParsingPackageUtils.collectCertificates(parsedPackage, skipVerify));
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
} finally {
@@ -8774,16 +8777,13 @@ public class PackageManagerService extends IPackageManager.Stub
private AndroidPackage scanPackageLI(File scanFile, int parseFlags, int scanFlags,
long currentTime, UserHandle user) throws PackageManagerException {
if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setOnlyCoreApps(mOnlyCore);
pp.setDisplayMetrics(mMetrics);
pp.setCallback(mPackageParserCallback);
PackageParser2 pp = new PackageParser2(mSeparateProcesses, mOnlyCore, mMetrics, null,
mPackageParserCallback);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
final ParsedPackage parsedPackage;
try {
parsedPackage = pp.parseParsedPackage(scanFile, parseFlags, false);
parsedPackage = pp.parsePackage(scanFile, parseFlags, false);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
} finally {
@@ -8869,18 +8869,6 @@ public class PackageManagerService extends IPackageManager.Stub
final boolean pkgAlreadyExists;
PackageSetting pkgSetting;
// NOTE: installPackageLI() has the same code to setup the package's
// application info. This probably should be done lower in the call
// stack [such as scanPackageOnly()]. However, we verify the application
// info prior to that [in scanPackageNew()] and thus have to setup
// the application info early.
// TODO(b/135203078): Remove all of these application info calls
parsedPackage.setApplicationVolumeUuid(parsedPackage.getVolumeUuid())
.setApplicationInfoCodePath(parsedPackage.getCodePath())
.setApplicationInfoResourcePath(parsedPackage.getCodePath())
.setApplicationInfoBaseResourcePath(parsedPackage.getBaseCodePath())
.setApplicationInfoSplitResourcePaths(parsedPackage.getSplitCodePaths());
synchronized (mLock) {
renamedPkgName = mSettings.getRenamedPackageLPr(parsedPackage.getRealPackage());
final String realPkgName = getRealPackageName(parsedPackage, renamedPkgName);
@@ -9957,7 +9945,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Or:
// - Package manager is in a state where package isn't scanned yet. This will
// get called again after scanning to fix the dependencies.
if (pkg.isLibrary()) {
if (AndroidPackageUtils.isLibrary(pkg)) {
if (pkg.getStaticSharedLibName() != null) {
SharedLibraryInfo definedLibrary = getSharedLibraryInfoLPr(
pkg.getStaticSharedLibName(), pkg.getStaticSharedLibVersion());
@@ -9994,7 +9982,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
if (p != null) {
usesLibraryFiles.addAll(p.getAllCodePaths());
usesLibraryFiles.addAll(AndroidPackageUtils.getAllCodePaths(p));
// If the package provides libraries, add the dependency to them.
applyDefiningSharedLibraryUpdateLocked(pkg, libInfo, (definingLibrary, dependency) -> {
definingLibrary.addDependency(dependency);
@@ -10026,18 +10014,18 @@ public class PackageManagerService extends IPackageManager.Stub
// that libraries are searched in the correct order) and must have no
// duplicates.
ArrayList<SharedLibraryInfo> usesLibraryInfos = null;
if (pkg.getUsesLibraries() != null) {
if (!pkg.getUsesLibraries().isEmpty()) {
usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesLibraries(), null, null,
pkg.getPackageName(), true, pkg.getTargetSdkVersion(), null,
availablePackages, existingLibraries, newLibraries);
}
if (pkg.getUsesStaticLibraries() != null) {
if (!pkg.getUsesStaticLibraries().isEmpty()) {
usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesStaticLibraries(),
pkg.getUsesStaticLibrariesVersions(), pkg.getUsesStaticLibrariesCertDigests(),
pkg.getPackageName(), true, pkg.getTargetSdkVersion(), usesLibraryInfos,
availablePackages, existingLibraries, newLibraries);
}
if (pkg.getUsesOptionalLibraries() != null) {
if (!pkg.getUsesOptionalLibraries().isEmpty()) {
usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesOptionalLibraries(),
null, null, pkg.getPackageName(), false, pkg.getTargetSdkVersion(),
usesLibraryInfos, availablePackages, existingLibraries, newLibraries);
@@ -10607,7 +10595,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
pkgSetting.signatures.mSigningDetails = reconciledPkg.signingDetails;
if (pkg.getAdoptPermissions() != null) {
if (!pkg.getAdoptPermissions().isEmpty()) {
// This package wants to adopt ownership of permissions from
// another package.
for (int i = pkg.getAdoptPermissions().size() - 1; i >= 0; i--) {
@@ -10848,8 +10836,8 @@ public class PackageManagerService extends IPackageManager.Stub
}
// Initialize package source and resource directories
final File destCodeFile = new File(parsedPackage.getAppInfoCodePath());
final File destResourceFile = new File(parsedPackage.getAppInfoResourcePath());
final File destCodeFile = new File(parsedPackage.getCodePath());
final File destResourceFile = new File(parsedPackage.getCodePath());
// We keep references to the derived CPU Abis from settings in oder to reuse
// them in the case where we're not upgrading or booting for the first time.
@@ -10878,7 +10866,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
String[] usesStaticLibraries = null;
if (parsedPackage.getUsesStaticLibraries() != null) {
if (!parsedPackage.getUsesStaticLibraries().isEmpty()) {
usesStaticLibraries = new String[parsedPackage.getUsesStaticLibraries().size()];
parsedPackage.getUsesStaticLibraries().toArray(usesStaticLibraries);
}
@@ -10898,8 +10886,7 @@ public class PackageManagerService extends IPackageManager.Stub
} else {
// make a deep copy to avoid modifying any existing system state.
pkgSetting = new PackageSetting(pkgSetting);
// TODO(b/135203078): Remove entirely. Set package directly.
parsedPackage.setPackageSettingCallback(pkgSetting);
pkgSetting.pkg = parsedPackage;
// REMOVE SharedUserSetting from method; update in a separate call.
//
@@ -10945,9 +10932,7 @@ public class PackageManagerService extends IPackageManager.Stub
.setSeInfo(SELinuxMMAC.getSeInfo(parsedPackage, sharedUserSetting,
injector.getCompatibility()))
.setSeInfoUser(SELinuxUtil.assignSeinfoUser(pkgSetting.readUserState(
userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId)))
.setProcessName(fixProcessName(parsedPackage.getPackageName(),
parsedPackage.getProcessName()));
userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId)));
if (!isPlatformPackage) {
// Get all of our default paths setup
@@ -10964,7 +10949,7 @@ public class PackageManagerService extends IPackageManager.Stub
if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
if (needToDeriveAbi) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
final boolean extractNativeLibs = !parsedPackage.isLibrary();
final boolean extractNativeLibs = !AndroidPackageUtils.isLibrary(parsedPackage);
final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths> derivedAbi =
packageAbiHelper.derivePackageAbi(parsedPackage, cpuAbiOverride,
extractNativeLibs);
@@ -11104,13 +11089,13 @@ public class PackageManagerService extends IPackageManager.Stub
}
pkgSetting.setTimeStamp(scanFileTime);
// TODO(b/135203078): Remove, move to constructor
parsedPackage.setPackageSettingCallback(pkgSetting);
pkgSetting.pkg = parsedPackage;
pkgSetting.pkgFlags = parsedPackage.getFlags();
if (parsedPackage.getLongVersionCode() != pkgSetting.versionCode) {
pkgSetting.versionCode = parsedPackage.getLongVersionCode();
}
// Update volume if needed
final String volumeUuid = parsedPackage.getApplicationInfoVolumeUuid();
final String volumeUuid = parsedPackage.getVolumeUuid();
if (!Objects.equals(volumeUuid, pkgSetting.volumeUuid)) {
Slog.i(PackageManagerService.TAG,
"Update" + (pkgSetting.isSystem() ? " system" : "")
@@ -11122,14 +11107,15 @@ public class PackageManagerService extends IPackageManager.Stub
SharedLibraryInfo staticSharedLibraryInfo = null;
if (!TextUtils.isEmpty(parsedPackage.getStaticSharedLibName())) {
staticSharedLibraryInfo = SharedLibraryInfo.createForStatic(parsedPackage);
staticSharedLibraryInfo =
AndroidPackageUtils.createSharedLibraryForStatic(parsedPackage);
}
List<SharedLibraryInfo> dynamicSharedLibraryInfos = null;
if (!ArrayUtils.isEmpty(parsedPackage.getLibraryNames())) {
dynamicSharedLibraryInfos = new ArrayList<>(parsedPackage.getLibraryNames().size());
for (String name : parsedPackage.getLibraryNames()) {
dynamicSharedLibraryInfos.add(
SharedLibraryInfo.createForDynamic(parsedPackage, name));
AndroidPackageUtils.createSharedLibraryForDynamic(parsedPackage, name));
}
}
@@ -11202,7 +11188,7 @@ public class PackageManagerService extends IPackageManager.Stub
parsedPackage.setAllComponentsDirectBootAware(true);
}
if (compressedFileExists(parsedPackage.getCodePath())) {
parsedPackage.setIsStub(true);
parsedPackage.setStub(true);
}
} else {
parsedPackage
@@ -11257,7 +11243,7 @@ public class PackageManagerService extends IPackageManager.Stub
private <T extends ComponentParseUtils.ParsedMainComponent>
void assertPackageProcesses(AndroidPackage pkg, List<T> components,
ArrayMap<String, ComponentParseUtils.ParsedProcess> procs, String compName)
Map<String, ComponentParseUtils.ParsedProcess> procs, String compName)
throws PackageManagerException {
if (components == null) {
return;
@@ -11291,8 +11277,7 @@ public class PackageManagerService extends IPackageManager.Stub
assertCodePolicy(pkg);
}
if (pkg.getAppInfoCodePath() == null ||
pkg.getAppInfoResourcePath() == null) {
if (pkg.getCodePath() == null) {
// Bail out. The resource and code paths haven't been set.
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Code and resource paths haven't been set correctly");
@@ -11375,49 +11360,49 @@ public class PackageManagerService extends IPackageManager.Stub
}
// Static shared libs cannot declare activities
if (pkg.getActivities() != null && !pkg.getActivities().isEmpty()) {
if (!pkg.getActivities().isEmpty()) {
throw new PackageManagerException(
"Static shared libs cannot declare activities");
}
// Static shared libs cannot declare services
if (pkg.getServices() != null && !pkg.getServices().isEmpty()) {
if (!pkg.getServices().isEmpty()) {
throw new PackageManagerException(
"Static shared libs cannot declare services");
}
// Static shared libs cannot declare providers
if (pkg.getProviders() != null && !pkg.getProviders().isEmpty()) {
if (!pkg.getProviders().isEmpty()) {
throw new PackageManagerException(
"Static shared libs cannot declare content providers");
}
// Static shared libs cannot declare receivers
if (pkg.getReceivers() != null && !pkg.getReceivers().isEmpty()) {
if (!pkg.getReceivers().isEmpty()) {
throw new PackageManagerException(
"Static shared libs cannot declare broadcast receivers");
}
// Static shared libs cannot declare permission groups
if (pkg.getPermissionGroups() != null && !pkg.getPermissionGroups().isEmpty()) {
if (!pkg.getPermissionGroups().isEmpty()) {
throw new PackageManagerException(
"Static shared libs cannot declare permission groups");
}
// Static shared libs cannot declare features
if (pkg.getFeatures() != null && !pkg.getFeatures().isEmpty()) {
if (!pkg.getFeatures().isEmpty()) {
throw new PackageManagerException(
"Static shared libs cannot declare features");
}
// Static shared libs cannot declare permissions
if (pkg.getPermissions() != null && !pkg.getPermissions().isEmpty()) {
if (!pkg.getPermissions().isEmpty()) {
throw new PackageManagerException(
"Static shared libs cannot declare permissions");
}
// Static shared libs cannot declare protected broadcasts
if (pkg.getProtectedBroadcasts() != null) {
if (!pkg.getProtectedBroadcasts().isEmpty()) {
throw new PackageManagerException(
"Static shared libs cannot declare protected broadcasts");
}
@@ -11479,12 +11464,11 @@ public class PackageManagerService extends IPackageManager.Stub
+ " and requiring known paths " + known.codePathString
+ " & " + known.resourcePathString);
}
if (!pkg.getAppInfoCodePath().equals(known.codePathString)
|| !pkg.getAppInfoResourcePath().equals(
known.resourcePathString)) {
if (!pkg.getCodePath().equals(known.codePathString)
|| !pkg.getCodePath().equals(known.resourcePathString)) {
throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED,
"Application package " + pkg.getPackageName()
+ " found at " + pkg.getAppInfoCodePath()
+ " found at " + pkg.getCodePath()
+ " but expected at " + known.codePathString
+ "; ignoring.");
}
@@ -11506,8 +11490,8 @@ public class PackageManagerService extends IPackageManager.Stub
// If this package has defined explicit processes, then ensure that these are
// the only processes used by its components.
final ArrayMap<String, ComponentParseUtils.ParsedProcess> procs = pkg.getProcesses();
if (procs != null) {
final Map<String, ComponentParseUtils.ParsedProcess> procs = pkg.getProcesses();
if (!procs.isEmpty()) {
if (!procs.containsKey(pkg.getProcessName())) {
throw new PackageManagerException(
INSTALL_FAILED_PROCESS_NOT_DEFINED,
@@ -11793,7 +11777,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (clientLibPkgs != null) {
for (int i=0; i<clientLibPkgs.size(); i++) {
AndroidPackage clientPkg = clientLibPkgs.get(i);
killApplication(clientPkg.getAppInfoPackageName(),
killApplication(clientPkg.getPackageName(),
clientPkg.getUid(), "update lib");
}
}
@@ -11807,7 +11791,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Add the new setting to mSettings
mSettings.insertPackageSettingLPw(pkgSetting, pkg);
// Add the new setting to mPackages
mPackages.put(pkg.getAppInfoPackageName(), pkg);
mPackages.put(pkg.getPackageName(), pkg);
if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) {
mApexManager.registerApkInApex(pkg);
}
@@ -11887,8 +11871,8 @@ public class PackageManagerService extends IPackageManager.Stub
// Set up information for custom user intent resolution activity.
mResolveActivity.applicationInfo = pkg.toAppInfoWithoutState();
mResolveActivity.name = mCustomResolverComponentName.getClassName();
mResolveActivity.packageName = pkg.getAppInfoPackageName();
mResolveActivity.processName = pkg.getAppInfoProcessName();
mResolveActivity.packageName = pkg.getPackageName();
mResolveActivity.processName = pkg.getProcessName();
mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS |
ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
@@ -13727,7 +13711,7 @@ public class PackageManagerService extends IPackageManager.Stub
try {
if (bm.isUserReadyForBackup(userId)) {
bm.restoreAtInstallForUser(
userId, res.pkg.getAppInfoPackageName(), token);
userId, res.pkg.getPackageName(), token);
} else {
Slog.w(TAG, "User " + userId + " is not ready. Restore at install "
+ "didn't take place.");
@@ -13755,7 +13739,7 @@ public class PackageManagerService extends IPackageManager.Stub
IRollbackManager rm = IRollbackManager.Stub.asInterface(
ServiceManager.getService(Context.ROLLBACK_SERVICE));
final String packageName = res.pkg.getAppInfoPackageName();
final String packageName = res.pkg.getPackageName();
final String seInfo = res.pkg.getSeInfo();
final int[] allUsers = mUserManager.getUserIds();
final int[] installedUsers;
@@ -13815,7 +13799,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (data.res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
continue;
}
if (packageName.equals(data.res.pkg.getAppInfoPackageName())) {
if (packageName.equals(data.res.pkg.getPackageName())) {
// right package; but is it for the right user?
for (int uIndex = 0; uIndex < data.res.newUsers.length; uIndex++) {
if (userId == data.res.newUsers[uIndex]) {
@@ -15000,14 +14984,6 @@ public class PackageManagerService extends IPackageManager.Stub
parsedPackage.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,
afterCodeFile, parsedPackage.getSplitCodePaths()));
// Reflect the rename in app info
// TODO(b/135203078): Remove all of these application info calls
parsedPackage.setApplicationVolumeUuid(parsedPackage.getVolumeUuid())
.setApplicationInfoCodePath(parsedPackage.getCodePath())
.setApplicationInfoResourcePath(parsedPackage.getCodePath())
.setApplicationInfoBaseResourcePath(parsedPackage.getBaseCodePath())
.setApplicationInfoSplitResourcePaths(parsedPackage.getSplitCodePaths());
return true;
}
@@ -15117,14 +15093,6 @@ public class PackageManagerService extends IPackageManager.Stub
return false;
}
// Reflect the move in app info
// TODO(b/135203078): Remove all of these application info calls
parsedPackage.setApplicationVolumeUuid(parsedPackage.getVolumeUuid())
.setApplicationInfoCodePath(parsedPackage.getCodePath())
.setApplicationInfoResourcePath(parsedPackage.getCodePath())
.setApplicationInfoBaseResourcePath(parsedPackage.getBaseCodePath())
.setApplicationInfoSplitResourcePaths(parsedPackage.getSplitCodePaths());
return true;
}
@@ -15922,8 +15890,8 @@ public class PackageManagerService extends IPackageManager.Stub
// which means we are replacing another update that is already
// installed. We need to make sure to delete the older one's .apk.
res.removedInfo.args = createInstallArgsForExisting(
oldPackage.getAppInfoCodePath(),
oldPackage.getAppInfoResourcePath(),
oldPackage.getCodePath(),
oldPackage.getCodePath(),
getAppDexInstructionSets(oldPackage.getPrimaryCpuAbi(),
oldPackage.getSecondaryCpuAbi()));
} else {
@@ -15944,14 +15912,14 @@ public class PackageManagerService extends IPackageManager.Stub
// If deleted package lived in a container, give users a chance to
// relinquish resources before killing.
if (oldPackage.isForwardLocked() || isExternal(oldPackage)) {
if (isExternal(oldPackage)) {
if (DEBUG_INSTALL) {
Slog.i(TAG, "upgrading pkg " + oldPackage
+ " is ASEC-hosted -> UNAVAILABLE");
}
final int[] uidArray = new int[]{oldPackage.getUid()};
final ArrayList<String> pkgList = new ArrayList<>(1);
pkgList.add(oldPackage.getAppInfoPackageName());
pkgList.add(oldPackage.getPackageName());
sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null);
}
@@ -16328,16 +16296,14 @@ public class PackageManagerService extends IPackageManager.Stub
| PackageParser.PARSE_ENFORCE_CODE
| (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setDisplayMetrics(mMetrics);
pp.setCallback(mPackageParserCallback);
PackageParser2 pp = new PackageParser2(mSeparateProcesses, false, mMetrics, null,
mPackageParserCallback);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
ParsedPackage parsedPackage;
try {
parsedPackage = pp.parseParsedPackage(tmpPackageFile, parseFlags, false);
DexMetadataHelper.validatePackageDexMetadata(parsedPackage);
parsedPackage = pp.parsePackage(tmpPackageFile, parseFlags, false);
AndroidPackageUtils.validatePackageDexMetadata(parsedPackage);
} catch (PackageParserException e) {
throw new PrepareFailure("Failed parse during installPackageLI", e);
} finally {
@@ -16393,7 +16359,8 @@ public class PackageManagerService extends IPackageManager.Stub
parsedPackage.setSigningDetails(args.signingDetails);
} else {
// TODO(b/136132412): skip for Incremental installation
ApkParseUtils.collectCertificates(parsedPackage, false /* skipVerify */);
parsedPackage.setSigningDetails(
ParsingPackageUtils.collectCertificates(parsedPackage, false /* skipVerify */));
}
} catch (PackageParserException e) {
throw new PrepareFailure("Failed collect during installPackageLI", e);
@@ -16636,7 +16603,7 @@ public class PackageManagerService extends IPackageManager.Stub
try {
String abiOverride = (TextUtils.isEmpty(parsedPackage.getCpuAbiOverride())
? args.abiOverride : parsedPackage.getCpuAbiOverride());
final boolean extractNativeLibs = !parsedPackage.isLibrary();
final boolean extractNativeLibs = !AndroidPackageUtils.isLibrary(parsedPackage);
final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
derivedAbi = mInjector.getAbiHelper().derivePackageAbi(
parsedPackage, abiOverride, extractNativeLibs);
@@ -19980,7 +19947,7 @@ public class PackageManagerService extends IPackageManager.Stub
// We're dealing with a component level state change
// First, verify that this is a valid class name.
AndroidPackage pkg = pkgSetting.pkg;
if (pkg == null || !pkg.hasComponentClassName(className)) {
if (pkg == null || !AndroidPackageUtils.hasComponentClassName(pkg, className)) {
if (pkg != null &&
pkg.getTargetSdkVersion() >=
Build.VERSION_CODES.JELLY_BEAN) {
@@ -21336,7 +21303,7 @@ public class PackageManagerService extends IPackageManager.Stub
final int[] packageUids = new int[size];
for (int i = 0; i < size; i++) {
final AndroidPackage pkg = packages.get(i);
packageNames[i] = pkg.getAppInfoPackageName();
packageNames[i] = pkg.getPackageName();
packageUids[i] = pkg.getUid();
}
sendResourcesChangedBroadcast(mediaStatus, replacing, packageNames, packageUids,
@@ -21801,7 +21768,7 @@ public class PackageManagerService extends IPackageManager.Stub
ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,
appId, seInfo, pkg.getTargetSdkVersion());
} catch (InstallerException e) {
if (pkg.isSystemApp()) {
if (pkg.isSystem()) {
logCriticalInfo(Log.ERROR, "Failed to create app data for " + packageName
+ ", but trying to recover: " + e);
destroyAppDataLeafLIF(pkg, userId, flags);
@@ -22054,7 +22021,7 @@ public class PackageManagerService extends IPackageManager.Stub
|| shouldFilterApplicationLocked(ps, callingUid, user.getIdentifier())) {
throw new PackageManagerException(MOVE_FAILED_DOESNT_EXIST, "Missing package");
}
if (pkg.isSystemApp()) {
if (pkg.isSystem()) {
throw new PackageManagerException(MOVE_FAILED_SYSTEM_PACKAGE,
"Cannot move system application");
}
@@ -22080,7 +22047,7 @@ public class PackageManagerService extends IPackageManager.Stub
throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
"Package already moved to " + volumeUuid);
}
if (pkg.isInternal() && isPackageDeviceAdminOnAnyUser(packageName)) {
if (!pkg.isExternalStorage() && isPackageDeviceAdminOnAnyUser(packageName)) {
throw new PackageManagerException(MOVE_FAILED_DEVICE_ADMIN,
"Device admin cannot be moved");
}
@@ -23352,7 +23319,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
public boolean isEnabledAndMatches(ParsedComponent component, int flags, int userId) {
public boolean isEnabledAndMatches(ParsedMainComponent component, int flags, int userId) {
synchronized (mLock) {
AndroidPackage pkg = getPackage(component.getPackageName());
return mSettings.isEnabledAndMatchLPr(pkg, component, flags, userId);
@@ -24177,12 +24144,12 @@ public class PackageManagerService extends IPackageManager.Stub
if (p == null) {
return false;
}
return p.canHaveOatDir();
return AndroidPackageUtils.canHaveOatDir(p, p.isUpdatedSystemApp());
}
}
private String getOatDir(AndroidPackage pkg) {
if (!pkg.canHaveOatDir()) {
if (!AndroidPackageUtils.canHaveOatDir(pkg, pkg.isUpdatedSystemApp())) {
return null;
}
File codePath = new File(pkg.getCodePath());
@@ -24202,7 +24169,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
instructionSets = getAppDexInstructionSets(pkg.getPrimaryCpuAbi(),
pkg.getSecondaryCpuAbi());
codePaths = pkg.getAllCodePaths();
codePaths = AndroidPackageUtils.getAllCodePaths(pkg);
oatDir = getOatDir(pkg);
for (String codePath : codePaths) {

View File

@@ -40,8 +40,7 @@ import android.content.pm.PackageParser;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
import android.content.pm.parsing.AndroidPackage;
import android.content.pm.parsing.ApkParseUtils;
import android.content.pm.parsing.ParsingPackageUtils;
import android.os.Build;
import android.os.Debug;
import android.os.Environment;
@@ -66,6 +65,7 @@ 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 com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.permission.PermissionsState;
import dalvik.system.VMRuntime;
@@ -544,7 +544,8 @@ public class PackageManagerServiceUtils {
private static boolean matchSignatureInSystem(PackageSetting pkgSetting,
PackageSetting disabledPkgSetting) {
try {
ApkParseUtils.collectCertificates(disabledPkgSetting.pkg, true /* skipVerify */);
disabledPkgSetting.pkg.mutate().setSigningDetails(
ParsingPackageUtils.collectCertificates(disabledPkgSetting.pkg, true /* skipVerify */));
if (pkgSetting.signatures.mSigningDetails.checkCapability(
disabledPkgSetting.signatures.mSigningDetails,
PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)

View File

@@ -20,13 +20,12 @@ import android.annotation.Nullable;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.content.pm.parsing.AndroidPackage;
import android.content.pm.parsing.ParsedPackage;
import android.service.pm.PackageProto;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.proto.ProtoOutputStream;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.permission.PermissionsState;
import java.io.File;
@@ -39,8 +38,7 @@ import java.util.Set;
/**
* Settings data for a particular package we know about.
*/
public final class PackageSetting extends PackageSettingBase implements
ParsedPackage.PackageSettingCallback {
public final class PackageSetting extends PackageSettingBase {
int appId;
public AndroidPackage pkg;
@@ -323,10 +321,4 @@ public final class PackageSetting extends PackageSettingBase implements
Set<String> mimeGroupNames = other.mimeGroups != null ? other.mimeGroups.keySet() : null;
updateMimeGroups(mimeGroupNames);
}
// TODO(b/135203078): Move to constructor
@Override
public void setAndroidPackage(AndroidPackage pkg) {
this.pkg = pkg;
}
}

View File

@@ -19,12 +19,13 @@ package com.android.server.pm;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import android.content.pm.PackageParser;
import android.content.pm.parsing.ParsedPackage;
import android.os.Process;
import android.os.Trace;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ConcurrentUtils;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.parsing.pkg.ParsedPackage;
import java.io.File;
import java.util.concurrent.ArrayBlockingQueue;
@@ -50,11 +51,11 @@ class ParallelPackageParser {
Process.THREAD_PRIORITY_FOREGROUND);
}
private final PackageParser mPackageParser;
private final PackageParser2 mPackageParser;
private final ExecutorService mExecutorService;
ParallelPackageParser(PackageParser packageParser, ExecutorService executorService) {
ParallelPackageParser(PackageParser2 packageParser, ExecutorService executorService) {
mPackageParser = packageParser;
mExecutorService = executorService;
}
@@ -125,6 +126,6 @@ class ParallelPackageParser {
@VisibleForTesting
protected ParsedPackage parsePackage(File scanFile, int parseFlags)
throws PackageParser.PackageParserException {
return mPackageParser.parseParsedPackage(scanFile, parseFlags, true);
return mPackageParser.parsePackage(scanFile, parseFlags, true);
}
}

View File

@@ -3155,7 +3155,7 @@ public final class Settings {
LocalServices.getService(PackageManagerInternal.class);
for (PackageSetting ps : mPackages.values()) {
if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0 && ps.pkg != null
&& ps.pkg.getPreferredActivityFilters() != null) {
&& !ps.pkg.getPreferredActivityFilters().isEmpty()) {
List<ComponentParseUtils.ParsedActivityIntentInfo> intents
= ps.pkg.getPreferredActivityFilters();
for (int i=0; i<intents.size(); i++) {
@@ -4608,10 +4608,10 @@ public final class Settings {
pw.print(" (override=true)");
}
pw.println();
if (ps.pkg.getQueriesPackages() != null) {
if (ps.pkg.getQueriesPackages().isEmpty()) {
pw.append(prefix).append(" queriesPackages=").println(ps.pkg.getQueriesPackages());
}
if (ps.pkg.getQueriesIntents() != null) {
if (!ps.pkg.getQueriesIntents().isEmpty()) {
pw.append(prefix).append(" queriesIntents=").println(ps.pkg.getQueriesIntents());
}
pw.print(prefix); pw.print(" dataDir="); pw.println(ps.pkg.getDataDir());
@@ -4707,11 +4707,10 @@ public final class Settings {
pw.print(prefix); pw.print(" "); pw.println(usesLibraryFiles[i]);
}
}
final ArrayMap<String, ComponentParseUtils.ParsedProcess> procs = pkg.getProcesses();
if (procs != null) {
final Map<String, ComponentParseUtils.ParsedProcess> procs = pkg.getProcesses();
if (!procs.isEmpty()) {
pw.print(prefix); pw.println(" processes:");
for (int i = 0; i < procs.size(); i++) {
final ComponentParseUtils.ParsedProcess proc = procs.valueAt(i);
for (ComponentParseUtils.ParsedProcess proc : procs.values()) {
pw.print(prefix); pw.print(" "); pw.println(proc.name);
if (proc.deniedPermissions != null) {
for (int j = 0; j < proc.deniedPermissions.size(); j++) {
@@ -4751,7 +4750,7 @@ public final class Settings {
pw.print(prefix); pw.print(" overlayCategory="); pw.println(pkg.getOverlayCategory());
}
if (pkg != null && pkg.getPermissions() != null && pkg.getPermissions().size() > 0) {
if (pkg != null && !pkg.getPermissions().isEmpty()) {
final List<ParsedPermission> perms = pkg.getPermissions();
pw.print(prefix); pw.println(" declared permissions:");
for (int i=0; i<perms.size(); i++) {

View File

@@ -0,0 +1,200 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.pm.parsing;
import android.annotation.NonNull;
import android.content.pm.PackageParserCacheHelper;
import android.os.Parcel;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
import android.system.StructStat;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.parsing.pkg.ParsedPackage;
import libcore.io.IoUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;
public class PackageCacher {
private static final String TAG = "PackageCacher";
/**
* Total number of packages that were read from the cache. We use it only for logging.
*/
public static final AtomicInteger sCachedPackageReadCount = new AtomicInteger();
@NonNull
private File mCacheDir;
public PackageCacher(@NonNull File cacheDir) {
this.mCacheDir = cacheDir;
}
/**
* Returns the cache key for a specified {@code packageFile} and {@code flags}.
*/
private String getCacheKey(File packageFile, int flags) {
StringBuilder sb = new StringBuilder(packageFile.getName());
sb.append('-');
sb.append(flags);
return sb.toString();
}
@VisibleForTesting
protected ParsedPackage fromCacheEntry(byte[] bytes) {
return fromCacheEntryStatic(bytes);
}
/** static version of {@link #fromCacheEntry} for unit tests. */
@VisibleForTesting
public static ParsedPackage fromCacheEntryStatic(byte[] bytes) {
final Parcel p = Parcel.obtain();
p.unmarshall(bytes, 0, bytes.length);
p.setDataPosition(0);
final PackageParserCacheHelper.ReadHelper helper = new PackageParserCacheHelper.ReadHelper(p);
helper.startAndInstall();
// TODO(b/135203078): Hide PackageImpl constructor?
ParsedPackage pkg = new PackageImpl(p);
p.recycle();
sCachedPackageReadCount.incrementAndGet();
return pkg;
}
@VisibleForTesting
protected byte[] toCacheEntry(ParsedPackage pkg) {
return toCacheEntryStatic(pkg);
}
/** static version of {@link #toCacheEntry} for unit tests. */
@VisibleForTesting
public static byte[] toCacheEntryStatic(ParsedPackage pkg) {
final Parcel p = Parcel.obtain();
final PackageParserCacheHelper.WriteHelper helper = new PackageParserCacheHelper.WriteHelper(p);
pkg.writeToParcel(p, 0 /* flags */);
helper.finishAndUninstall();
byte[] serialized = p.marshall();
p.recycle();
return serialized;
}
/**
* Given a {@code packageFile} and a {@code cacheFile} returns whether the
* cache file is up to date based on the mod-time of both files.
*/
private static boolean isCacheUpToDate(File packageFile, File cacheFile) {
try {
// NOTE: We don't use the File.lastModified API because it has the very
// non-ideal failure mode of returning 0 with no excepions thrown.
// The nio2 Files API is a little better but is considerably more expensive.
final StructStat pkg = Os.stat(packageFile.getAbsolutePath());
final StructStat cache = Os.stat(cacheFile.getAbsolutePath());
return pkg.st_mtime < cache.st_mtime;
} catch (ErrnoException ee) {
// The most common reason why stat fails is that a given cache file doesn't
// exist. We ignore that here. It's easy to reason that it's safe to say the
// cache isn't up to date if we see any sort of exception here.
//
// (1) Exception while stating the package file : This should never happen,
// and if it does, we do a full package parse (which is likely to throw the
// same exception).
// (2) Exception while stating the cache file : If the file doesn't exist, the
// cache is obviously out of date. If the file *does* exist, we can't read it.
// We will attempt to delete and recreate it after parsing the package.
if (ee.errno != OsConstants.ENOENT) {
Slog.w("Error while stating package cache : ", ee);
}
return false;
}
}
/**
* Returns the cached parse result for {@code packageFile} for parse flags {@code flags},
* or {@code null} if no cached result exists.
*/
public ParsedPackage getCachedResult(File packageFile, int flags) {
final String cacheKey = getCacheKey(packageFile, flags);
final File cacheFile = new File(mCacheDir, cacheKey);
try {
// If the cache is not up to date, return null.
if (!isCacheUpToDate(packageFile, cacheFile)) {
return null;
}
final byte[] bytes = IoUtils.readFileAsByteArray(cacheFile.getAbsolutePath());
return fromCacheEntry(bytes);
} catch (Throwable e) {
Slog.w(TAG, "Error reading package cache: ", e);
// If something went wrong while reading the cache entry, delete the cache file
// so that we regenerate it the next time.
cacheFile.delete();
return null;
}
}
/**
* Caches the parse result for {@code packageFile} with flags {@code flags}.
*/
public void cacheResult(File packageFile, int flags, ParsedPackage parsed) {
try {
final String cacheKey = getCacheKey(packageFile, flags);
final File cacheFile = new File(mCacheDir, cacheKey);
if (cacheFile.exists()) {
if (!cacheFile.delete()) {
Slog.e(TAG, "Unable to delete cache file: " + cacheFile);
}
}
final byte[] cacheEntry = toCacheEntry(parsed);
if (cacheEntry == null) {
return;
}
try (FileOutputStream fos = new FileOutputStream(cacheFile)) {
fos.write(cacheEntry);
} catch (IOException ioe) {
Slog.w(TAG, "Error writing cache entry.", ioe);
cacheFile.delete();
}
} catch (Throwable e) {
Slog.w(TAG, "Error saving package cache.", e);
}
}
}

View File

@@ -0,0 +1,419 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.pm.parsing;
import android.annotation.CheckResult;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.apex.ApexInfo;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ComponentInfo;
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageUserState;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.ProcessInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
import android.content.pm.parsing.ComponentParseUtils.ParsedComponent;
import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
import android.content.pm.parsing.ComponentParseUtils.ParsedMainComponent;
import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
import android.content.pm.parsing.ComponentParseUtils.ParsedProcess;
import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
import android.content.pm.parsing.ComponentParseUtils.ParsedService;
import android.content.pm.parsing.PackageInfoWithoutStateUtils;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
import com.android.internal.util.ArrayUtils;
import com.android.server.pm.PackageSetting;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import libcore.util.EmptyArray;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
/** @hide **/
public class PackageInfoUtils {
@Nullable
public static PackageInfo generate(AndroidPackage pkg, int[] gids,
@PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
Set<String> grantedPermissions, PackageUserState state, int userId) {
PackageSetting pkgSetting = null;
return generateWithComponents(pkg, gids, flags, firstInstallTime, lastUpdateTime,
grantedPermissions, state, userId, null, pkgSetting);
}
@Nullable
public static PackageInfo generate(AndroidPackage pkg, ApexInfo apexInfo, int flags,
PackageSetting pkgSetting) {
return generateWithComponents(pkg, EmptyArray.INT, flags, 0, 0, Collections.emptySet(),
new PackageUserState(), UserHandle.getCallingUserId(), apexInfo, pkgSetting);
}
private static PackageInfo generateWithComponents(AndroidPackage pkg, int[] gids,
@PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
Set<String> grantedPermissions, PackageUserState state, int userId,
@Nullable ApexInfo apexInfo, @Nullable PackageSetting pkgSetting) {
ApplicationInfo applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
if (applicationInfo == null) {
return null;
}
PackageInfo info = PackageInfoWithoutStateUtils.generateWithoutComponents(pkg, gids, flags,
firstInstallTime, lastUpdateTime, grantedPermissions, state, userId, apexInfo,
applicationInfo);
if (info == null) {
return null;
}
info.isStub = pkg.isStub();
info.coreApp = pkg.isCoreApp();
if ((flags & PackageManager.GET_ACTIVITIES) != 0) {
final int N = pkg.getActivities().size();
if (N > 0) {
int num = 0;
final ActivityInfo[] res = new ActivityInfo[N];
for (int i = 0; i < N; i++) {
final ParsedActivity a = pkg.getActivities().get(i);
if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), a, flags)) {
if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(
a.getName())) {
continue;
}
res[num++] = generateActivityInfo(pkg, a, flags, state,
applicationInfo, userId, pkgSetting);
}
}
info.activities = ArrayUtils.trimToSize(res, num);
}
}
if ((flags & PackageManager.GET_RECEIVERS) != 0) {
final int size = pkg.getReceivers().size();
if (size > 0) {
int num = 0;
final ActivityInfo[] res = new ActivityInfo[size];
for (int i = 0; i < size; i++) {
final ParsedActivity a = pkg.getReceivers().get(i);
if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), a, flags)) {
res[num++] = generateActivityInfo(pkg, a, flags, state, applicationInfo,
userId, pkgSetting);
}
}
info.receivers = ArrayUtils.trimToSize(res, num);
}
}
if ((flags & PackageManager.GET_SERVICES) != 0) {
final int size = pkg.getServices().size();
if (size > 0) {
int num = 0;
final ServiceInfo[] res = new ServiceInfo[size];
for (int i = 0; i < size; i++) {
final ParsedService s = pkg.getServices().get(i);
if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), s, flags)) {
res[num++] = generateServiceInfo(pkg, s, flags, state, applicationInfo,
userId, pkgSetting);
}
}
info.services = ArrayUtils.trimToSize(res, num);
}
}
if ((flags & PackageManager.GET_PROVIDERS) != 0) {
final int size = pkg.getProviders().size();
if (size > 0) {
int num = 0;
final ProviderInfo[] res = new ProviderInfo[size];
for (int i = 0; i < size; i++) {
final ParsedProvider pr = pkg.getProviders()
.get(i);
if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), pr, flags)) {
res[num++] = generateProviderInfo(pkg, pr, flags, state, applicationInfo,
userId, pkgSetting);
}
}
info.providers = ArrayUtils.trimToSize(res, num);
}
}
if ((flags & PackageManager.GET_INSTRUMENTATION) != 0) {
int N = pkg.getInstrumentations().size();
if (N > 0) {
info.instrumentation = new InstrumentationInfo[N];
for (int i = 0; i < N; i++) {
info.instrumentation[i] = generateInstrumentationInfo(
pkg.getInstrumentations().get(i), pkg, flags, userId);
}
}
}
return info;
}
@Nullable
public static ApplicationInfo generateApplicationInfo(AndroidPackage pkg,
@PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId) {
PackageSetting pkgSetting = null;
// TODO(b/135203078): Consider cases where we don't have a PkgSetting
if (pkg == null) {
return null;
}
if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)
|| !AndroidPackageUtils.isMatchForSystemOnly(pkg, flags)) {
return null;
}
ApplicationInfo info = PackageInfoWithoutStateUtils.generateApplicationInfo(pkg, flags,
state, userId);
if (info == null) {
return null;
}
info.flags |= appInfoFlags(pkg, pkgSetting);
info.privateFlags |= appInfoPrivateFlags(pkg, pkgSetting);
return info;
}
@Nullable
public static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a,
@PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) {
PackageSetting pkgSetting = null;
return generateActivityInfo(pkg, a, flags, state, null, userId, pkgSetting);
}
@Nullable
private static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a,
@PackageManager.ComponentInfoFlags int flags, PackageUserState state,
@Nullable ApplicationInfo applicationInfo, int userId,
@Nullable PackageSetting pkgSetting) {
if (a == null) return null;
if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)) {
return null;
}
if (applicationInfo == null) {
applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
}
ActivityInfo info = PackageInfoWithoutStateUtils.generateActivityInfo(pkg, a, flags, state,
applicationInfo, userId);
if (info == null) {
return null;
}
assignSharedFieldsForComponentInfo(info, a, pkgSetting);
return info;
}
@Nullable
public static ServiceInfo generateServiceInfo(AndroidPackage pkg, ParsedService s,
@PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) {
PackageSetting pkgSetting = null;
return generateServiceInfo(pkg, s, flags, state, null, userId, pkgSetting);
}
@Nullable
private static ServiceInfo generateServiceInfo(AndroidPackage pkg, ParsedService s,
@PackageManager.ComponentInfoFlags int flags, PackageUserState state,
@Nullable ApplicationInfo applicationInfo, int userId,
@Nullable PackageSetting pkgSetting) {
if (s == null) return null;
if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)) {
return null;
}
if (applicationInfo == null) {
applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
}
ServiceInfo info = PackageInfoWithoutStateUtils.generateServiceInfo(pkg, s, flags, state,
applicationInfo, userId);
if (info == null) {
return null;
}
assignSharedFieldsForComponentInfo(info, s, pkgSetting);
return info;
}
@Nullable
public static ProviderInfo generateProviderInfo(AndroidPackage pkg, ParsedProvider p,
@PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) {
PackageSetting pkgSetting = null;
return generateProviderInfo(pkg, p, flags, state, null, userId, pkgSetting);
}
@Nullable
private static ProviderInfo generateProviderInfo(AndroidPackage pkg, ParsedProvider p,
@PackageManager.ComponentInfoFlags int flags, PackageUserState state,
@Nullable ApplicationInfo applicationInfo, int userId,
@Nullable PackageSetting pkgSetting) {
if (p == null) return null;
if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)) {
return null;
}
if (applicationInfo == null) {
applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
}
ProviderInfo info = PackageInfoWithoutStateUtils.generateProviderInfo(pkg, p, flags, state,
applicationInfo, userId);
if (info == null) {
return null;
}
assignSharedFieldsForComponentInfo(info, p, pkgSetting);
return info;
}
@Nullable
public static InstrumentationInfo generateInstrumentationInfo(ParsedInstrumentation i,
AndroidPackage pkg, @PackageManager.ComponentInfoFlags int flags, int userId) {
PackageSetting pkgSetting = null;
if (i == null) return null;
InstrumentationInfo info =
PackageInfoWithoutStateUtils.generateInstrumentationInfo(i, pkg, flags, userId);
if (info == null) {
return null;
}
// TODO(b/135203078): Add setting related state
info.primaryCpuAbi = pkg.getPrimaryCpuAbi();
info.secondaryCpuAbi = pkg.getSecondaryCpuAbi();
info.nativeLibraryDir = pkg.getNativeLibraryDir();
info.secondaryNativeLibraryDir = pkg.getSecondaryNativeLibraryDir();
assignStateFieldsForPackageItemInfo(info, i, pkgSetting);
return info;
}
// TODO(b/135203078): Determine if permission methods need to pass in a non-null PackageSetting
// os that checkUseInstalledOrHidden filter can apply
@Nullable
public static PermissionInfo generatePermissionInfo(ParsedPermission p,
@PackageManager.ComponentInfoFlags int flags) {
// TODO(b/135203078): Remove null checks and make all usages @NonNull
if (p == null) return null;
// For now, permissions don't have state-adjustable fields; return directly
return PackageInfoWithoutStateUtils.generatePermissionInfo(p, flags);
}
@Nullable
public static PermissionGroupInfo generatePermissionGroupInfo(ParsedPermissionGroup pg,
@PackageManager.ComponentInfoFlags int flags) {
if (pg == null) return null;
// For now, permissions don't have state-adjustable fields; return directly
return PackageInfoWithoutStateUtils.generatePermissionGroupInfo(pg, flags);
}
@Nullable
public static ArrayMap<String, ProcessInfo> generateProcessInfo(
Map<String, ParsedProcess> procs, @PackageManager.ComponentInfoFlags int flags) {
if (procs == null) {
return null;
}
final int numProcs = procs.size();
ArrayMap<String, ProcessInfo> retProcs = new ArrayMap<>(numProcs);
for (String key : procs.keySet()) {
ParsedProcess proc = procs.get(key);
retProcs.put(proc.name, new ProcessInfo(proc.name,
proc.deniedPermissions != null
? new ArraySet<>(proc.deniedPermissions) : null));
}
return retProcs;
}
/**
* Returns true if the package is installed and not hidden, or if the caller
* explicitly wanted all uninstalled and hidden packages as well.
*/
private static boolean checkUseInstalledOrHidden(AndroidPackage pkg,
PackageSetting pkgSetting, PackageUserState state,
@PackageManager.PackageInfoFlags int flags) {
// Returns false if the package is hidden system app until installed.
if ((flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) == 0
&& !state.installed
&& pkg.isHiddenUntilInstalled()) {
return false;
}
// If available for the target user, or trying to match uninstalled packages and it's
// a system app.
return state.isAvailable(flags)
|| (pkg.isSystem()
&& ((flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0
|| (flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) != 0));
}
private static void assignSharedFieldsForComponentInfo(@NonNull ComponentInfo componentInfo,
@NonNull ParsedMainComponent mainComponent, @Nullable PackageSetting pkgSetting) {
assignStateFieldsForPackageItemInfo(componentInfo, mainComponent, pkgSetting);
componentInfo.descriptionRes = mainComponent.descriptionRes;
componentInfo.directBootAware = mainComponent.isDirectBootAware();
componentInfo.enabled = mainComponent.isEnabled();
componentInfo.splitName = mainComponent.getSplitName();
}
private static void assignStateFieldsForPackageItemInfo(
@NonNull PackageItemInfo packageItemInfo, @NonNull ParsedComponent component,
@Nullable PackageSetting pkgSetting) {
// TODO(b/135203078): Add setting related state
}
@CheckResult
private static int flag(boolean hasFlag, int flag) {
return hasFlag ? flag : 0;
}
/** @see ApplicationInfo#flags */
public static int appInfoFlags(AndroidPackage pkg, @Nullable PackageSetting pkgSetting) {
// TODO(b/135203078): Add setting related state
// @formatter:off
return PackageInfoWithoutStateUtils.appInfoFlags(pkg)
| flag(pkg.isSystem(), ApplicationInfo.FLAG_SYSTEM)
| flag(pkg.isFactoryTest(), ApplicationInfo.FLAG_FACTORY_TEST)
| flag(pkg.isUpdatedSystemApp(), ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
// @formatter:on
}
/** @see ApplicationInfo#privateFlags */
public static int appInfoPrivateFlags(AndroidPackage pkg, @Nullable PackageSetting pkgSetting) {
// TODO(b/135203078): Add setting related state
// @formatter:off
return PackageInfoWithoutStateUtils.appInfoPrivateFlags(pkg)
| flag(pkg.isSystemExt(), ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT)
| flag(pkg.isPrivileged(), ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
| flag(pkg.isOem(), ApplicationInfo.PRIVATE_FLAG_OEM)
| flag(pkg.isVendor(), ApplicationInfo.PRIVATE_FLAG_VENDOR)
| flag(pkg.isProduct(), ApplicationInfo.PRIVATE_FLAG_PRODUCT)
| flag(pkg.isOdm(), ApplicationInfo.PRIVATE_FLAG_ODM)
| flag(pkg.isSignedWithPlatformKey(), ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY);
// @formatter:on
}
}

View File

@@ -0,0 +1,128 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.pm.parsing;
import android.annotation.AnyThread;
import android.annotation.Nullable;
import android.content.pm.PackageParser;
import android.content.pm.parsing.ParsingPackage;
import android.content.pm.parsing.ParsingPackageUtils;
import android.content.res.TypedArray;
import android.os.Build;
import android.os.SystemClock;
import android.util.DisplayMetrics;
import android.util.Slog;
import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.parsing.pkg.ParsedPackage;
import java.io.File;
/**
* The v2 of {@link PackageParser} for use when parsing is initiated in the server and must
* contain state contained by the server.
*/
public class PackageParser2 {
private static final String TAG = "PackageParser2";
private static final boolean LOG_PARSE_TIMINGS = Build.IS_DEBUGGABLE;
private static final int LOG_PARSE_TIMINGS_THRESHOLD_MS = 100;
private ThreadLocal<ParsingPackageUtils.ParseResult> mSharedResult = ThreadLocal.withInitial(
ParsingPackageUtils.ParseResult::new);
private final String[] mSeparateProcesses;
private final boolean mOnlyCoreApps;
private final DisplayMetrics mDisplayMetrics;
private final Callback mCallback;
@Nullable
protected PackageCacher mCacher;
/**
* @param onlyCoreApps Flag indicating this parser should only consider apps with
* {@code coreApp} manifest attribute to be valid apps. This is useful when
* creating a minimalist boot environment.
*/
public PackageParser2(String[] separateProcesses, boolean onlyCoreApps,
DisplayMetrics displayMetrics, @Nullable File cacheDir, Callback callback) {
mSeparateProcesses = separateProcesses;
mOnlyCoreApps = onlyCoreApps;
if (displayMetrics == null) {
mDisplayMetrics = new DisplayMetrics();
mDisplayMetrics.setToDefaults();
} else {
mDisplayMetrics = displayMetrics;
}
mCacher = cacheDir == null ? null : new PackageCacher(cacheDir);
// TODO(b/135203078): Remove nullability of callback
mCallback = callback != null ? callback : new Callback() {
@Override
public boolean hasFeature(String feature) {
return false;
}
};
}
/**
* TODO(b/135203078): Document new package parsing
*/
@AnyThread
public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches)
throws PackageParser.PackageParserException {
if (useCaches && mCacher != null) {
ParsedPackage parsed = mCacher.getCachedResult(packageFile, flags);
if (parsed != null) {
return parsed;
}
}
long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
ParsingPackageUtils.ParseInput parseInput = mSharedResult.get().reset();
ParsedPackage parsed = (ParsedPackage) ParsingPackageUtils.parsePackage(parseInput,
mSeparateProcesses, mCallback, mDisplayMetrics, mOnlyCoreApps, packageFile, flags)
.hideAsParsed();
long cacheTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
if (mCacher != null) {
mCacher.cacheResult(packageFile, flags, parsed);
}
if (LOG_PARSE_TIMINGS) {
parseTime = cacheTime - parseTime;
cacheTime = SystemClock.uptimeMillis() - cacheTime;
if (parseTime + cacheTime > LOG_PARSE_TIMINGS_THRESHOLD_MS) {
Slog.i(TAG, "Parse times for '" + packageFile + "': parse=" + parseTime
+ "ms, update_cache=" + cacheTime + " ms");
}
}
return parsed;
}
public static abstract class Callback implements ParsingPackageUtils.Callback {
@Override
public final ParsingPackage startParsingPackage(String packageName, String baseCodePath,
String codePath, TypedArray manifestArray, boolean isCoreApp) {
return PackageImpl.forParsing(packageName, baseCodePath, codePath, manifestArray,
isCoreApp);
}
}
}

View File

@@ -187,7 +187,7 @@ public interface AndroidPackage extends PkgAppInfo, PkgPackageInfo, ParsingPacka
@NonNull
List<ParsedPermissionGroup> getPermissionGroups();
@Nullable
@NonNull
List<ParsedFeature> getFeatures();
/**

View File

@@ -3612,7 +3612,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return EmptyArray.INT;
}
for (AndroidPackage pkg : pkgList) {
if (pkg.getRequestedPermissions() == null) {
if (pkg.getRequestedPermissions().isEmpty()) {
continue;
}
final int requestedPermCount = pkg.getRequestedPermissions().size();
@@ -4246,7 +4246,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
private static boolean hasPermission(AndroidPackage pkg, String permName) {
if (pkg.getPermissions() == null) {
if (pkg.getPermissions().isEmpty()) {
return false;
}

View File

@@ -17,11 +17,13 @@
package com.android.server.pm;
import android.content.pm.PackageParser;
import android.content.pm.parsing.ParsedPackage;
import android.util.Log;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.parsing.pkg.ParsedPackage;
import junit.framework.Assert;
import org.junit.Before;
@@ -44,7 +46,7 @@ public class ParallelPackageParserTest {
@Before
public void setUp() {
mParser = new TestParallelPackageParser(new PackageParser(),
mParser = new TestParallelPackageParser(new PackageParser2(null, false, null, null, null),
ParallelPackageParser.makeExecutorService());
}
@@ -72,7 +74,7 @@ public class ParallelPackageParserTest {
private class TestParallelPackageParser extends ParallelPackageParser {
TestParallelPackageParser(PackageParser packageParser, ExecutorService executorService) {
TestParallelPackageParser(PackageParser2 packageParser, ExecutorService executorService) {
super(packageParser, executorService);
}