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
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 168679e..ccb307d 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -79,14 +79,10 @@
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 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 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 @@
* 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
@@ -1082,201 +1077,6 @@
}
/**
- * 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
* identical package name and version codes, a single base APK, and unique
@@ -1284,7 +1084,7 @@
* <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 @@
* <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 {
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index 9087f42..4c6da03 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -50,7 +50,7 @@
/** @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 @@
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 {
diff --git a/core/java/android/content/pm/parsing/ComponentParseUtils.java b/core/java/android/content/pm/parsing/ComponentParseUtils.java
index 6852a8c..4895396 100644
--- a/core/java/android/content/pm/parsing/ComponentParseUtils.java
+++ b/core/java/android/content/pm/parsing/ComponentParseUtils.java
@@ -82,7 +82,7 @@
*/
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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
}
}
- 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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 {
diff --git a/core/java/android/content/pm/parsing/PackageInfoUtils.java b/core/java/android/content/pm/parsing/PackageInfoUtils.java
deleted file mode 100644
index 72df189..0000000
--- a/core/java/android/content/pm/parsing/PackageInfoUtils.java
+++ /dev/null
@@ -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();
- }
-
-}
diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
new file mode 100644
index 0000000..0e833b2
--- /dev/null
+++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
@@ -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());
+ }
+}
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
index 840e1af..f046d383 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -61,7 +61,7 @@
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 @@
private int overlayPriority;
private boolean overlayIsStatic;
@NonNull
- @DataClass.ParcelWith(ForInternedStringMap.class)
+ @DataClass.ParcelWith(ForInternedStringValueMap.class)
private Map<String, String> overlayables = emptyMap();
@Nullable
diff --git a/core/java/android/content/pm/parsing/ApkParseUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
similarity index 97%
rename from core/java/android/content/pm/parsing/ApkParseUtils.java
rename to core/java/android/content/pm/parsing/ParsingPackageUtils.java
index 905794b..dd809f0f 100644
--- a/core/java/android/content/pm/parsing/ApkParseUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -26,6 +26,7 @@
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.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 @@
* 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 static ParsingPackage parsePackage(
ParseInput parseInput,
String[] separateProcesses,
- PackageParser.Callback callback,
+ Callback callback,
DisplayMetrics displayMetrics,
boolean onlyCoreApps,
File packageFile,
@@ -148,12 +149,12 @@
* 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 @@
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 @@
}
}
- return parsingPackage.setCodePath(lite.codePath)
- .setUse32BitAbi(lite.use32bitAbi);
+ return parsingPackage.setUse32BitAbi(lite.use32bitAbi);
} finally {
IoUtils.closeQuietly(assetLoader);
}
@@ -217,12 +217,12 @@
* 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 @@
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 @@
}
}
- 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 @@
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 @@
}
return pkg.setVolumeUuid(volumeUuid)
- .setApplicationVolumeUuid(volumeUuid)
.setSigningDetails(SigningDetails.UNKNOWN);
} catch (PackageParserException e) {
throw e;
@@ -372,14 +366,9 @@
* @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 @@
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 @@
// 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 @@
);
}
- parsingPackage.setAppMetaData(appMetaData);
+ parsingPackage.setMetaData(appMetaData);
break;
case "uses-static-library":
ParseResult parseResult = parseUsesStaticLibrary(parseInput, parsingPackage,
@@ -727,7 +712,7 @@
private static ParseResult parseBaseApkTags(
ParseInput parseInput,
String[] separateProcesses,
- PackageParser.Callback callback,
+ Callback callback,
ParsingPackage parsingPackage,
TypedArray manifestArray,
Resources res,
@@ -897,13 +882,23 @@
// 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 @@
);
}
- 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 @@
ParsingPackage parsingPackage,
Resources res,
XmlResourceParser parser,
- PackageParser.Callback callback
+ Callback callback
)
throws XmlPullParserException, IOException {
TypedArray sa = res.obtainAttributes(parser,
@@ -1854,7 +1840,7 @@
public static ParseResult parseBaseApplication(
ParseInput parseInput,
String[] separateProcesses,
- PackageParser.Callback callback,
+ Callback callback,
ParsingPackage parsingPackage,
Resources res,
XmlResourceParser parser,
@@ -1893,11 +1879,6 @@
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 @@
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 @@
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 @@
// 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 @@
);
}
- parsingPackage.setAppMetaData(appMetaData);
+ parsingPackage.setMetaData(appMetaData);
break;
case "static-library":
sa = res.obtainAttributes(parser,
@@ -2728,7 +2709,7 @@
// 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 @@
*/
private static void setMinAspectRatio(
ParsingPackage parsingPackage,
- PackageParser.Callback callback
+ Callback callback
) {
final float minAspectRatio;
float packageMinAspectRatio = parsingPackage.getMinAspectRatio();
@@ -2845,7 +2826,7 @@
}
parsingPackage
- .setIsOverlay(true)
+ .setOverlay(true)
.setOverlayTarget(target)
.setOverlayTargetName(targetName)
.setOverlayCategory(category)
@@ -2907,7 +2888,7 @@
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 @@
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 @@
}
/**
- * 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 @@
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);
+ }
}
diff --git a/core/java/android/content/pm/parsing/ParsingUtils.java b/core/java/android/content/pm/parsing/ParsingUtils.java
new file mode 100644
index 0000000..3ce629d
--- /dev/null
+++ b/core/java/android/content/pm/parsing/ParsingUtils.java
@@ -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;
+ }
+}
diff --git a/core/java/com/android/internal/content/om/OverlayConfig.java b/core/java/com/android/internal/content/om/OverlayConfig.java
index f699eb8..ffa347c 100644
--- a/core/java/com/android/internal/content/om/OverlayConfig.java
+++ b/core/java/com/android/internal/content/om/OverlayConfig.java
@@ -19,7 +19,7 @@
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.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 @@
* 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 @@
@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 @@
* {@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 @@
/**
* Retrieves the singleton instance initialized by
- * {@link #initializeSystemInstance(AndroidPackageProvider)}.
+ * {@link #initializeSystemInstance(PackageProvider)}.
*/
@NonNull
public static OverlayConfig getSystemInstance() {
@@ -291,10 +291,10 @@
@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())));
diff --git a/core/java/com/android/internal/util/Parcelling.java b/core/java/com/android/internal/util/Parcelling.java
index 390c596..6258a69 100644
--- a/core/java/com/android/internal/util/Parcelling.java
+++ b/core/java/com/android/internal/util/Parcelling.java
@@ -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 @@
*/
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
diff --git a/core/tests/coretests/src/com/android/internal/content/OverlayConfigIterationRule.java b/core/tests/coretests/src/com/android/internal/content/OverlayConfigIterationRule.java
index 23655a0..fbf75df 100644
--- a/core/tests/coretests/src/com/android/internal/content/OverlayConfigIterationRule.java
+++ b/core/tests/coretests/src/com/android/internal/content/OverlayConfigIterationRule.java
@@ -21,11 +21,11 @@
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 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 @@
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 @@
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 @@
}
return scanner;
};
- mAndroidPackageProvider = null;
+ mPkgProvider = null;
mIteration = Iteration.ZYGOTE;
base.evaluate();
@@ -131,14 +131,15 @@
// 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 @@
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();
}
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 76f6ef6..4ea6370 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -29,8 +29,10 @@
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 @@
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);
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index b9a30bb..72fae77 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -512,7 +512,7 @@
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) {
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index a1250cb..6a582b1 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -207,14 +207,14 @@
/** 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 @@
private static boolean canQueryViaPackage(AndroidPackage querying,
AndroidPackage potentialTarget) {
- return querying.getQueriesPackages() != null
+ return !querying.getQueriesPackages().isEmpty()
&& querying.getQueriesPackages().contains(potentialTarget.getPackageName());
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f6eb76b..d9cb212 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -209,20 +209,16 @@
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.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 @@
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 @@
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 @@
// 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 @@
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 @@
// 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 @@
// 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 @@
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 @@
// 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 @@
// 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 @@
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 @@
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 @@
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 @@
}
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 @@
}
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 @@
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 @@
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 @@
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 @@
// 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 @@
}
}
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 @@
// 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 @@
}
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 @@
}
// 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 @@
}
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 @@
} 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 @@
.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 @@
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 @@
}
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 @@
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 @@
parsedPackage.setAllComponentsDirectBootAware(true);
}
if (compressedFileExists(parsedPackage.getCodePath())) {
- parsedPackage.setIsStub(true);
+ parsedPackage.setStub(true);
}
} else {
parsedPackage
@@ -11257,7 +11243,7 @@
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 @@
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 @@
}
// 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 @@
+ " 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 @@
// 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 @@
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 @@
// 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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
// 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 @@
| 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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
|| 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 @@
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 @@
}
@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 @@
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 @@
}
instructionSets = getAppDexInstructionSets(pkg.getPrimaryCpuAbi(),
pkg.getSecondaryCpuAbi());
- codePaths = pkg.getAllCodePaths();
+ codePaths = AndroidPackageUtils.getAllCodePaths(pkg);
oatDir = getOatDir(pkg);
for (String codePath : codePaths) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index a9035b2..6040224 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -40,8 +40,7 @@
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.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 @@
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)
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index d83e6f4..97342c0 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -20,13 +20,12 @@
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 @@
/**
* 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 @@
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;
- }
}
diff --git a/services/core/java/com/android/server/pm/ParallelPackageParser.java b/services/core/java/com/android/server/pm/ParallelPackageParser.java
index 448dad0..21334c0 100644
--- a/services/core/java/com/android/server/pm/ParallelPackageParser.java
+++ b/services/core/java/com/android/server/pm/ParallelPackageParser.java
@@ -19,12 +19,13 @@
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 @@
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 @@
@VisibleForTesting
protected ParsedPackage parsePackage(File scanFile, int parseFlags)
throws PackageParser.PackageParserException {
- return mPackageParser.parseParsedPackage(scanFile, parseFlags, true);
+ return mPackageParser.parsePackage(scanFile, parseFlags, true);
}
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 60c8b94..5694428 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3155,7 +3155,7 @@
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 @@
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 @@
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 @@
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++) {
diff --git a/services/core/java/com/android/server/pm/parsing/PackageCacher.java b/services/core/java/com/android/server/pm/parsing/PackageCacher.java
new file mode 100644
index 0000000..e5e1b0b
--- /dev/null
+++ b/services/core/java/com/android/server/pm/parsing/PackageCacher.java
@@ -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);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
new file mode 100644
index 0000000..3d56962
--- /dev/null
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -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
+ }
+}
diff --git a/services/core/java/com/android/server/pm/parsing/PackageParser2.java b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
new file mode 100644
index 0000000..804f110
--- /dev/null
+++ b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
@@ -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);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
index 239cf9d..d0ec969 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
@@ -187,7 +187,7 @@
@NonNull
List<ParsedPermissionGroup> getPermissionGroups();
- @Nullable
+ @NonNull
List<ParsedFeature> getFeatures();
/**
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 36697f9..e1d1a1a 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -3612,7 +3612,7 @@
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 @@
}
private static boolean hasPermission(AndroidPackage pkg, String permName) {
- if (pkg.getPermissions() == null) {
+ if (pkg.getPermissions().isEmpty()) {
return false;
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
index da5986f7..20f3f3e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
@@ -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 @@
@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 @@
private class TestParallelPackageParser extends ParallelPackageParser {
- TestParallelPackageParser(PackageParser packageParser, ExecutorService executorService) {
+ TestParallelPackageParser(PackageParser2 packageParser, ExecutorService executorService) {
super(packageParser, executorService);
}