From e23ae20e30f372f7748db5282edb0a73a8851497 Mon Sep 17 00:00:00 2001 From: Winson Date: Fri, 24 Jan 2020 11:56:44 -0800 Subject: [PATCH] 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 --- .../android/content/pm/PackageParser.java | 210 +----- .../content/pm/parsing/ApkLiteParseUtils.java | 4 +- .../pm/parsing/ComponentParseUtils.java | 51 +- .../content/pm/parsing/PackageInfoUtils.java | 595 --------------- .../parsing/PackageInfoWithoutStateUtils.java | 691 ++++++++++++++++++ .../pm/parsing/ParsingPackageImpl.java | 4 +- ...rseUtils.java => ParsingPackageUtils.java} | 154 ++-- .../content/pm/parsing/ParsingUtils.java | 45 ++ .../internal/content/om/OverlayConfig.java | 20 +- .../com/android/internal/util/Parcelling.java | 134 ++++ .../content/OverlayConfigIterationRule.java | 31 +- .../content/pm/PackageManagerInternal.java | 8 +- .../AppIntegrityManagerServiceImpl.java | 2 +- .../com/android/server/pm/AppsFilter.java | 6 +- .../server/pm/PackageManagerService.java | 223 +++--- .../server/pm/PackageManagerServiceUtils.java | 7 +- .../com/android/server/pm/PackageSetting.java | 12 +- .../server/pm/ParallelPackageParser.java | 9 +- .../java/com/android/server/pm/Settings.java | 15 +- .../server/pm/parsing/PackageCacher.java | 200 +++++ .../server/pm/parsing/PackageInfoUtils.java | 419 +++++++++++ .../server/pm/parsing/PackageParser2.java | 128 ++++ .../server/pm/parsing/pkg/AndroidPackage.java | 2 +- .../permission/PermissionManagerService.java | 4 +- .../server/pm/ParallelPackageParserTest.java | 8 +- 25 files changed, 1878 insertions(+), 1104 deletions(-) delete mode 100644 core/java/android/content/pm/parsing/PackageInfoUtils.java create mode 100644 core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java rename core/java/android/content/pm/parsing/{ApkParseUtils.java => ParsingPackageUtils.java} (97%) create mode 100644 core/java/android/content/pm/parsing/ParsingUtils.java create mode 100644 services/core/java/com/android/server/pm/parsing/PackageCacher.java create mode 100644 services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java create mode 100644 services/core/java/com/android/server/pm/parsing/PackageParser2.java diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 168679e793f86..ccb307db08a8b 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -79,14 +79,10 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.PatternMatcher; import android.os.RemoteException; -import android.os.SystemClock; import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; import android.os.storage.StorageManager; -import android.system.ErrnoException; -import android.system.OsConstants; -import android.system.StructStat; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; @@ -118,7 +114,6 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.File; import java.io.FileDescriptor; -import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.lang.annotation.Retention; @@ -316,8 +311,8 @@ public class PackageParser { public int mParseError = PackageManager.INSTALL_SUCCEEDED; - public ThreadLocal mSharedResult - = ThreadLocal.withInitial(ApkParseUtils.ParseResult::new); + public ThreadLocal mSharedResult + = ThreadLocal.withInitial(ParsingPackageUtils.ParseResult::new); public static boolean sCompatibilityModeEnabled = true; public static boolean sUseRoundIcon = false; @@ -1054,7 +1049,7 @@ public class PackageParser { * and unique split names. *

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

* Note that this does not perform signature verification; that * must be done separately in - * {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}. + * {@link #collectCertificates(Package, boolean)} . */ private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException { final PackageLite lite = parseClusterPackageLite(packageDir, 0); @@ -1346,7 +1146,7 @@ public class PackageParser { *

* Note that this does not 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 9087f422cef28..4c6da03b4db30 100644 --- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java +++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java @@ -50,7 +50,7 @@ import java.util.List; /** @hide */ public class ApkLiteParseUtils { - private static final String TAG = ApkParseUtils.TAG; + private static final String TAG = ParsingPackageUtils.TAG; // TODO(b/135203078): Consolidate constants private static final int DEFAULT_MIN_SDK_VERSION = 1; @@ -235,7 +235,7 @@ public class ApkLiteParseUtils { final boolean skipVerify = (flags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0; Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates"); try { - signingDetails = ApkParseUtils.collectCertificates(apkFile.getAbsolutePath(), + signingDetails = ParsingPackageUtils.collectCertificates(apkFile.getAbsolutePath(), skipVerify, false, PackageParser.SigningDetails.UNKNOWN, DEFAULT_TARGET_SDK_VERSION); } finally { diff --git a/core/java/android/content/pm/parsing/ComponentParseUtils.java b/core/java/android/content/pm/parsing/ComponentParseUtils.java index 6852a8c2254d8..48953963fe3fc 100644 --- a/core/java/android/content/pm/parsing/ComponentParseUtils.java +++ b/core/java/android/content/pm/parsing/ComponentParseUtils.java @@ -82,7 +82,7 @@ import java.util.Objects; */ public class ComponentParseUtils { - private static final String TAG = ApkParseUtils.TAG; + private static final String TAG = ParsingUtils.TAG; // TODO(b/135203078): None of this class's subclasses do anything. Remove in favor of base? public static class ParsedIntentInfo extends IntentFilter { @@ -315,7 +315,7 @@ public class ComponentParseUtils { // TODO(b/135203078): Make subclass that contains these fields only for the necessary // subtypes protected boolean enabled = true; - protected boolean directBootAware; + public boolean directBootAware; public int flags; private String packageName; @@ -1460,7 +1460,7 @@ public class ComponentParseUtils { outError[0] = tag + " does not specify android:name"; return null; } else { - String className = ApkParseUtils.buildClassName(packageName, name); + String className = ParsingUtils.buildClassName(packageName, name); if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) { outError[0] = tag + " invalid android:name"; return null; @@ -1537,7 +1537,7 @@ public class ComponentParseUtils { R.styleable.AndroidManifestActivity_parentActivityName, Configuration.NATIVE_CONFIG_VERSION); if (parentName != null) { - String parentClassName = ApkParseUtils.buildClassName(packageName, parentName); + String parentClassName = ParsingUtils.buildClassName(packageName, parentName); if (parentClassName == null) { Log.e(TAG, "Activity " + result.className @@ -1856,9 +1856,8 @@ public class ComponentParseUtils { parsingPackage.addPreferredActivityFilter(intentInfo); } } else if (parser.getName().equals("meta-data")) { - if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser, - result.metaData, - outError)) == null) { + if ((result.metaData = ParsingPackageUtils.parseMetaData(parsingPackage, res, + parser, result.metaData, outError)) == null) { return null; } } else if (!receiver && parser.getName().equals("layout")) { @@ -1969,7 +1968,7 @@ public class ComponentParseUtils { outError[0] = " 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] = " invalid android:name"; return null; @@ -2099,7 +2098,7 @@ public class ComponentParseUtils { } } - if (parsingPackage.cantSaveState()) { + if (parsingPackage.isCantSaveState()) { // A heavy-weight application can not have services in its main process // We can do direct compare because we intern all strings. if (Objects.equals(result.getProcessName(), parsingPackage.getPackageName())) { @@ -2132,9 +2131,8 @@ public class ComponentParseUtils { result.order = Math.max(intent.getOrder(), result.order); result.intents.add(intent); } else if (parser.getName().equals("meta-data")) { - if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser, - result.metaData, - outError)) == null) { + if ((result.metaData = ParsingPackageUtils.parseMetaData(parsingPackage, res, + parser, result.metaData, outError)) == null) { return null; } } else { @@ -2182,7 +2180,7 @@ public class ComponentParseUtils { outError[0] = " 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] = " invalid android:name"; return null; @@ -2413,7 +2411,7 @@ public class ComponentParseUtils { outInfo.intents.add(intent); } else if (parser.getName().equals("meta-data")) { - Bundle metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser, + Bundle metaData = ParsingPackageUtils.parseMetaData(parsingPackage, res, parser, outInfo.metaData, outError); if (metaData == null) { return false; @@ -2607,7 +2605,7 @@ public class ComponentParseUtils { } String packageName = parsingPackage.getPackageName(); - targetActivity = ApkParseUtils.buildClassName(packageName, targetActivity); + targetActivity = ParsingUtils.buildClassName(packageName, targetActivity); if (targetActivity == null) { outError[0] = "Empty class name in package " + packageName; sa.recycle(); @@ -2664,7 +2662,7 @@ public class ComponentParseUtils { result.requestedVrComponent = target.requestedVrComponent; result.directBootAware = target.directBootAware; - result.setProcessName(parsingPackage.getAppInfoProcessName(), target.getProcessName()); + result.setProcessName(parsingPackage.getProcessName(), target.getProcessName()); // Not all attributes from the target ParsedActivity are copied to the alias. // Careful when adding an attribute and determine whether or not it should be copied. @@ -2686,7 +2684,7 @@ public class ComponentParseUtils { outError[0] = " 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] = " invalid android:name"; return null; @@ -2751,7 +2749,7 @@ public class ComponentParseUtils { R.styleable.AndroidManifestActivityAlias_parentActivityName, Configuration.NATIVE_CONFIG_VERSION); if (parentName != null) { - String parentClassName = ApkParseUtils.buildClassName(result.getPackageName(), + String parentClassName = ParsingUtils.buildClassName(result.getPackageName(), parentName); if (parentClassName == null) { Log.e(TAG, "Activity alias " + result.className + @@ -2811,9 +2809,8 @@ public class ComponentParseUtils { result.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP; } } else if (tagName.equals("meta-data")) { - if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser, - result.metaData, - outError)) == null) { + if ((result.metaData = ParsingPackageUtils.parseMetaData(parsingPackage, res, + parser, result.metaData, outError)) == null) { return null; } } else { @@ -2935,7 +2932,7 @@ public class ComponentParseUtils { outError[0] = " 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] = " invalid android:name"; return null; @@ -3073,7 +3070,7 @@ public class ComponentParseUtils { outError[0] = " 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] = " invalid android:name"; return null; @@ -3163,7 +3160,7 @@ public class ComponentParseUtils { outError[0] = " 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] = " invalid android:name"; return null; @@ -3262,7 +3259,7 @@ public class ComponentParseUtils { outError[0] = " 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] = " invalid android:name"; return null; @@ -3764,8 +3761,8 @@ public class ComponentParseUtils { } if (parser.getName().equals("meta-data")) { - if ((outInfo.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser, - outInfo.metaData, outError)) == null) { + if ((outInfo.metaData = ParsingPackageUtils.parseMetaData(parsingPackage, res, + parser, outInfo.metaData, outError)) == null) { return false; } } else { 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 72df189984704..0000000000000 --- 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 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 generateProcessInfo( - ArrayMap procs, - @PackageManager.ComponentInfoFlags int flags) { - if (procs == null) { - return null; - } - - final int numProcs = procs.size(); - ArrayMap 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 0000000000000..0e833b285415a --- /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 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 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 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 840e1af95eb92..f046d383ff7dd 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.ForBoolean; import com.android.internal.util.Parcelling.BuiltIn.ForInternedString; import com.android.internal.util.Parcelling.BuiltIn.ForInternedStringArray; import com.android.internal.util.Parcelling.BuiltIn.ForInternedStringList; -import com.android.internal.util.Parcelling.BuiltIn.ForInternedStringMap; +import com.android.internal.util.Parcelling.BuiltIn.ForInternedStringValueMap; import com.android.internal.util.Parcelling.BuiltIn.ForInternedStringSet; import java.security.PublicKey; @@ -159,7 +159,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { private int overlayPriority; private boolean overlayIsStatic; @NonNull - @DataClass.ParcelWith(ForInternedStringMap.class) + @DataClass.ParcelWith(ForInternedStringValueMap.class) private Map 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 905794bb24de1..dd809f0fe01c1 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_INCONSISTEN import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; +import static android.os.Build.VERSION_CODES.DONUT; import static android.os.Build.VERSION_CODES.O; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED; @@ -99,10 +100,10 @@ import java.util.Set; import java.util.StringTokenizer; /** @hide */ -public class ApkParseUtils { +public class ParsingPackageUtils { // TODO(b/135203078): Consolidate log tags - static final String TAG = "PackageParsing"; + public static final String TAG = "PackageParsing"; /** * Parse the package at the given location. Automatically detects if the @@ -114,7 +115,7 @@ public class ApkParseUtils { * and unique split names. *

* Note that this does not perform signature verification; that - * must be done separately in {@link #collectCertificates(ParsedPackage, boolean)}. + * must be done separately in {@link #collectCertificates(ParsingPackageRead, boolean)}. * * If {@code useCaches} is true, the package parser might return a cached * result from a previous parse of the same {@code packageFile} with the same @@ -126,7 +127,7 @@ public class ApkParseUtils { public static ParsingPackage parsePackage( ParseInput parseInput, String[] separateProcesses, - PackageParser.Callback callback, + Callback callback, DisplayMetrics displayMetrics, boolean onlyCoreApps, File packageFile, @@ -148,12 +149,12 @@ public class ApkParseUtils { * split names. *

* Note that this does not perform signature verification; that - * must be done separately in {@link #collectCertificates(ParsedPackage, boolean)}. + * must be done separately in {@link #collectCertificates(ParsingPackageRead, boolean)}. */ private static ParsingPackage parseClusterPackage( ParseInput parseInput, String[] separateProcesses, - PackageParser.Callback callback, + Callback callback, DisplayMetrics displayMetrics, boolean onlyCoreApps, File packageDir, @@ -184,7 +185,7 @@ public class ApkParseUtils { final AssetManager assets = assetLoader.getBaseAssetManager(); final File baseApk = new File(lite.baseCodePath); ParsingPackage parsingPackage = parseBaseApk(parseInput, separateProcesses, callback, - displayMetrics, baseApk, assets, flags); + displayMetrics, baseApk, lite.codePath, assets, flags); if (parsingPackage == null) { throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, "Failed to parse base APK: " + baseApk); @@ -206,8 +207,7 @@ public class ApkParseUtils { } } - return parsingPackage.setCodePath(lite.codePath) - .setUse32BitAbi(lite.use32bitAbi); + return parsingPackage.setUse32BitAbi(lite.use32bitAbi); } finally { IoUtils.closeQuietly(assetLoader); } @@ -217,12 +217,12 @@ public class ApkParseUtils { * Parse the given APK file, treating it as as a single monolithic package. *

* Note that this does not perform signature verification; that - * must be done separately in {@link #collectCertificates(AndroidPackage, boolean)}. + * must be done separately in {@link #collectCertificates(ParsingPackageRead, boolean)}. */ public static ParsingPackage parseMonolithicPackage( ParseInput parseInput, String[] separateProcesses, - PackageParser.Callback callback, + Callback callback, DisplayMetrics displayMetrics, boolean onlyCoreApps, File apkFile, @@ -240,8 +240,8 @@ public class ApkParseUtils { final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags); try { return parseBaseApk(parseInput, separateProcesses, callback, - displayMetrics, apkFile, assetLoader.getBaseAssetManager(), flags) - .setCodePath(apkFile.getCanonicalPath()) + displayMetrics, apkFile, apkFile.getCanonicalPath(), + assetLoader.getBaseAssetManager(), flags) .setUse32BitAbi(lite.use32bitAbi); } catch (IOException e) { throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, @@ -251,14 +251,9 @@ public class ApkParseUtils { } } - private static ParsingPackage parseBaseApk( - ParseInput parseInput, - String[] separateProcesses, - PackageParser.Callback callback, - DisplayMetrics displayMetrics, - File apkFile, - AssetManager assets, - int flags + private static ParsingPackage parseBaseApk(ParseInput parseInput, String[] separateProcesses, + Callback callback, DisplayMetrics displayMetrics, File apkFile, + String codePath, AssetManager assets, int flags ) throws PackageParserException { final String apkPath = apkFile.getAbsolutePath(); @@ -280,8 +275,8 @@ public class ApkParseUtils { parser = assets.openXmlResourceParser(cookie, PackageParser.ANDROID_MANIFEST_FILENAME); final Resources res = new Resources(assets, displayMetrics, null); - ParseResult result = parseBaseApk(parseInput, separateProcesses, callback, apkPath, res, - parser, flags); + ParseResult result = parseBaseApk(parseInput, separateProcesses, callback, apkPath, + codePath, res, parser, flags); if (!result.isSuccess()) { throw new PackageParserException(result.getParseError(), apkPath + " (at " + parser.getPositionDescription() + "): " @@ -305,7 +300,6 @@ public class ApkParseUtils { } return pkg.setVolumeUuid(volumeUuid) - .setApplicationVolumeUuid(volumeUuid) .setSigningDetails(SigningDetails.UNKNOWN); } catch (PackageParserException e) { throw e; @@ -372,14 +366,9 @@ public class ApkParseUtils { * @param flags Flags how to parse * @return Parsed package or null on error. */ - private static ParseResult parseBaseApk( - ParseInput parseInput, - String[] separateProcesses, - PackageParser.Callback callback, - String apkPath, - Resources res, - XmlResourceParser parser, - int flags + private static ParseResult parseBaseApk(ParseInput parseInput, String[] separateProcesses, + Callback callback, String apkPath, String codePath, Resources res, + XmlResourceParser parser, int flags ) throws XmlPullParserException, IOException { final String splitName; final String pkgName; @@ -407,12 +396,8 @@ public class ApkParseUtils { boolean isCoreApp = parser.getAttributeBooleanValue(null, "coreApp", false); - ParsingPackage parsingPackage = PackageImpl.forParsing( - pkgName, - apkPath, - manifestArray, - isCoreApp - ); + ParsingPackage parsingPackage = callback.startParsingPackage(pkgName, apkPath, codePath, + manifestArray, isCoreApp); ParseResult result = parseBaseApkTags(parseInput, separateProcesses, callback, parsingPackage, manifestArray, res, parser, flags); @@ -645,7 +630,7 @@ public class ApkParseUtils { // remain null in the primary copy (we like to avoid extra copies because // it can be large) Bundle appMetaData = parseMetaData(parsingPackage, res, parser, - parsingPackage.getAppMetaData(), + parsingPackage.getMetaData(), outError); if (appMetaData == null) { return parseInput.error( @@ -654,7 +639,7 @@ public class ApkParseUtils { ); } - parsingPackage.setAppMetaData(appMetaData); + parsingPackage.setMetaData(appMetaData); break; case "uses-static-library": ParseResult parseResult = parseUsesStaticLibrary(parseInput, parsingPackage, @@ -727,7 +712,7 @@ public class ApkParseUtils { private static ParseResult parseBaseApkTags( ParseInput parseInput, String[] separateProcesses, - PackageParser.Callback callback, + Callback callback, ParsingPackage parsingPackage, TypedArray manifestArray, Resources res, @@ -897,13 +882,23 @@ public class ApkParseUtils { // At this point we can check if an application is not supporting densities and hence // cannot be windowed / resized. Note that an SDK version of 0 is common for // pre-Doughnut applications. - if (parsingPackage.usesCompatibilityMode()) { + if (usesCompatibilityMode(parsingPackage)) { adjustPackageToBeUnresizeableAndUnpipable(parsingPackage); } return parseInput.success(parsingPackage); } + public static boolean usesCompatibilityMode(ParsingPackage pkg) { + return pkg.getTargetSdkVersion() < DONUT + || (!pkg.isSupportsSmallScreens() + && !pkg.isSupportsNormalScreens() + && !pkg.isSupportsLargeScreens() + && !pkg.isSupportsExtraLargeScreens() + && !pkg.isResizeable() + && !pkg.isAnyDensity()); + } + private static ParseResult parseUnknownTag( ParseInput parseInput, ParsingPackage parsingPackage, @@ -1234,20 +1229,11 @@ public class ApkParseUtils { ); } - parsingPackage.setName(outInfoName); + parsingPackage.setClassName(outInfoName); } - int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(roundIconRes, 0) : 0; - if (roundIconVal != 0) { - parsingPackage.setIcon(roundIconVal) - .setNonLocalizedLabel(null); - } else { - int iconVal = sa.getResourceId(iconRes, 0); - if (iconVal != 0) { - parsingPackage.setIcon(iconVal) - .setNonLocalizedLabel(null); - } - } + parsingPackage.setRoundIconRes(sa.getResourceId(roundIconRes, 0)) + .setIconRes(sa.getResourceId(iconRes, 0)); int logoVal = sa.getResourceId(logoRes, 0); if (logoVal != 0) { @@ -1375,7 +1361,7 @@ public class ApkParseUtils { ParsingPackage parsingPackage, Resources res, XmlResourceParser parser, - PackageParser.Callback callback + Callback callback ) throws XmlPullParserException, IOException { TypedArray sa = res.obtainAttributes(parser, @@ -1854,7 +1840,7 @@ public class ApkParseUtils { public static ParseResult parseBaseApplication( ParseInput parseInput, String[] separateProcesses, - PackageParser.Callback callback, + Callback callback, ParsingPackage parsingPackage, Resources res, XmlResourceParser parser, @@ -1893,11 +1879,6 @@ public class ApkParseUtils { return result; } - String name = parsingPackage.getName(); - if (name != null) { - parsingPackage.setClassName(name); - } - String manageSpaceActivity = sa.getNonConfigurationString( R.styleable.AndroidManifestApplication_manageSpaceActivity, Configuration.NATIVE_CONFIG_VERSION); @@ -2078,10 +2059,10 @@ public class ApkParseUtils { R.styleable.AndroidManifestApplication_directBootAware, false)); if (sa.hasValueOrEmpty(R.styleable.AndroidManifestApplication_resizeableActivity)) { - parsingPackage.setActivitiesResizeModeResizeable(sa.getBoolean( + parsingPackage.setResizeableActivity(sa.getBoolean( R.styleable.AndroidManifestApplication_resizeableActivity, true)); } else { - parsingPackage.setActivitiesResizeModeResizeableViaSdkVersion( + parsingPackage.setResizeableActivityViaSdkVersion( parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.N); } @@ -2195,7 +2176,7 @@ public class ApkParseUtils { parsingPackage.setCrossProfile( sa.getBoolean(R.styleable.AndroidManifestApplication_crossProfile, false)); - parsingPackage.setIsGame(sa.getBoolean( + parsingPackage.setGame(sa.getBoolean( R.styleable.AndroidManifestApplication_isGame, false)); boolean cantSaveState = sa.getBoolean( @@ -2334,7 +2315,7 @@ public class ApkParseUtils { // remain null in the primary copy (we like to avoid extra copies because // it can be large) Bundle appMetaData = parseMetaData(parsingPackage, res, parser, - parsingPackage.getAppMetaData(), + parsingPackage.getMetaData(), outError); if (appMetaData == null) { return parseInput.error( @@ -2343,7 +2324,7 @@ public class ApkParseUtils { ); } - parsingPackage.setAppMetaData(appMetaData); + parsingPackage.setMetaData(appMetaData); break; case "static-library": sa = res.obtainAttributes(parser, @@ -2728,7 +2709,7 @@ public class ApkParseUtils { // Use the application max aspect ration as default if set. maxAspectRatio = packageMaxAspectRatio; } else { - Bundle appMetaData = parsingPackage.getAppMetaData(); + Bundle appMetaData = parsingPackage.getMetaData(); if (appMetaData != null && appMetaData.containsKey( PackageParser.METADATA_MAX_ASPECT_RATIO)) { maxAspectRatio = appMetaData.getFloat(PackageParser.METADATA_MAX_ASPECT_RATIO, @@ -2764,7 +2745,7 @@ public class ApkParseUtils { */ private static void setMinAspectRatio( ParsingPackage parsingPackage, - PackageParser.Callback callback + Callback callback ) { final float minAspectRatio; float packageMinAspectRatio = parsingPackage.getMinAspectRatio(); @@ -2845,7 +2826,7 @@ public class ApkParseUtils { } parsingPackage - .setIsOverlay(true) + .setOverlay(true) .setOverlayTarget(target) .setOverlayTargetName(targetName) .setOverlayCategory(category) @@ -2907,7 +2888,7 @@ public class ApkParseUtils { sa.getInteger(R.styleable.AndroidManifestSupportsScreens_normalScreens, 1)) .setSupportsLargeScreens( sa.getInteger(R.styleable.AndroidManifestSupportsScreens_largeScreens, 1)) - .setSupportsXLargeScreens( + .setSupportsExtraLargeScreens( sa.getInteger(R.styleable.AndroidManifestSupportsScreens_xlargeScreens, 1)) .setResizeable( sa.getInteger(R.styleable.AndroidManifestSupportsScreens_resizeable, 1)) @@ -2960,7 +2941,7 @@ public class ApkParseUtils { R.styleable.AndroidManifestOriginalPackage_name, 0); if (!parsingPackage.getPackageName().equals(orig)) { - if (parsingPackage.getOriginalPackages() == null) { + if (parsingPackage.getOriginalPackages().isEmpty()) { parsingPackage.setRealPackage(parsingPackage.getPackageName()); } parsingPackage.addOriginalPackage(orig); @@ -3186,36 +3167,36 @@ public class ApkParseUtils { } /** - * Collect certificates from all the APKs described in the given package, - * populating {@link AndroidPackageWrite#setSigningDetails(SigningDetails)}. Also asserts that + * Collect certificates from all the APKs described in the given package. Also asserts that * all APK contents are signed correctly and consistently. */ - public static void collectCertificates(AndroidPackage pkg, boolean skipVerify) + public static SigningDetails collectCertificates(ParsingPackageRead pkg, boolean skipVerify) throws PackageParserException { - pkg.mutate().setSigningDetails(SigningDetails.UNKNOWN); + SigningDetails signingDetails = SigningDetails.UNKNOWN; Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates"); try { - pkg.mutate().setSigningDetails(collectCertificates( + signingDetails = collectCertificates( pkg.getBaseCodePath(), skipVerify, pkg.isStaticSharedLibrary(), - pkg.getSigningDetails(), + signingDetails, pkg.getTargetSdkVersion() - )); + ); String[] splitCodePaths = pkg.getSplitCodePaths(); if (!ArrayUtils.isEmpty(splitCodePaths)) { for (int i = 0; i < splitCodePaths.length; i++) { - pkg.mutate().setSigningDetails(collectCertificates( + signingDetails = collectCertificates( splitCodePaths[i], skipVerify, pkg.isStaticSharedLibrary(), - pkg.getSigningDetails(), + signingDetails, pkg.getTargetSdkVersion() - )); + ); } } + return signingDetails; } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } @@ -3346,4 +3327,15 @@ public class ApkParseUtils { return errorMessage; } } + + /** + * Callback interface for retrieving information that may be needed while parsing + * a package. + */ + public interface Callback { + boolean hasFeature(String feature); + + ParsingPackage startParsingPackage(String packageName, String baseCodePath, String codePath, + TypedArray manifestArray, boolean isCoreApp); + } } 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 0000000000000..3ce629db9e73e --- /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 f699eb8c4639a..ffa347c168f65 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 @@ package com.android.internal.content.om; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.pm.PackagePartitions; -import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ParsingPackageRead; import android.os.Build; import android.os.Process; import android.os.Trace; @@ -36,7 +36,7 @@ import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; -import java.util.function.Consumer; +import java.util.function.BiConsumer; import java.util.function.Supplier; /** @@ -71,10 +71,10 @@ public class OverlayConfig { * Interface for providing information on scanned packages. * TODO(147840005): Remove this when android:isStatic and android:priority are fully deprecated */ - public interface AndroidPackageProvider { + public interface PackageProvider { /** Performs the given action for each package. */ - void forEachPackage(Consumer p); + void forEachPackage(BiConsumer p); } private static final Comparator sStaticOverlayComparator = (c1, c2) -> { @@ -100,7 +100,7 @@ public class OverlayConfig { @VisibleForTesting public OverlayConfig(@Nullable File rootDirectory, @Nullable Supplier scannerFactory, - @Nullable AndroidPackageProvider packageProvider) { + @Nullable PackageProvider packageProvider) { Preconditions.checkArgument((scannerFactory == null) != (packageProvider == null), "scannerFactory and packageProvider cannot be both null or both non-null"); @@ -208,7 +208,7 @@ public class OverlayConfig { * {@link #getSystemInstance()} will return the initialized instance. */ @NonNull - public static OverlayConfig initializeSystemInstance(AndroidPackageProvider packageProvider) { + public static OverlayConfig initializeSystemInstance(PackageProvider packageProvider) { if (Process.myUid() != Process.SYSTEM_UID) { throw new IllegalStateException("Can only be invoked in the system process"); } @@ -221,7 +221,7 @@ public class OverlayConfig { /** * Retrieves the singleton instance initialized by - * {@link #initializeSystemInstance(AndroidPackageProvider)}. + * {@link #initializeSystemInstance(PackageProvider)}. */ @NonNull public static OverlayConfig getSystemInstance() { @@ -291,10 +291,10 @@ public class OverlayConfig { @NonNull private static ArrayList getOverlayPackageInfos( - @NonNull AndroidPackageProvider packageManager) { + @NonNull PackageProvider packageManager) { final ArrayList 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 390c5969c08c4..6258a6956b091 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 @@ public interface Parcelling { */ interface BuiltIn { + class ForInternedString implements Parcelling { + @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 { + @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> { + @Override + public void parcel(List item, Parcel dest, int parcelFlags) { + dest.writeStringList(item); + } + + @Override + public List unparcel(Parcel source) { + ArrayList 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> { + @Override + public void parcel(Map item, Parcel dest, int parcelFlags) { + dest.writeMap(item); + } + + @Override + public Map unparcel(Parcel source) { + ArrayMap 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> { + @Override + public void parcel(Set 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 unparcel(Parcel source) { + final int size = source.readInt(); + if (size < 0) { + return emptySet(); + } + Set set = new ArraySet<>(); + for (int count = 0; count < size; count++) { + set.add(TextUtils.safeIntern(source.readString())); + } + return set; + } + } + + class ForBoolean implements Parcelling { + @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 { @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 23655a08397d9..fbf75dfb4979a 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.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.when; -import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ParsingPackageRead; import android.os.Build; import android.util.ArrayMap; -import com.android.internal.content.om.OverlayConfig.AndroidPackageProvider; +import com.android.internal.content.om.OverlayConfig.PackageProvider; import com.android.internal.content.om.OverlayScanner; import com.android.internal.content.om.OverlayScanner.ParsedOverlayInfo; @@ -39,14 +39,14 @@ import org.mockito.invocation.InvocationOnMock; import java.io.File; import java.io.IOException; import java.util.Map; -import java.util.function.Consumer; +import java.util.function.BiConsumer; import java.util.function.Supplier; /** * A {@link TestRule} that runs a test case twice. First, the test case runs with a non-null * {@link OverlayScanner} as if the zygote process is scanning the overlay packages * and parsing configuration files. The test case then runs with a non-null - * {@link AndroidPackageProvider} as if the system server is parsing configuration files. + * {@link PackageProvider} as if the system server is parsing configuration files. * * This simulates what will happen on device. If an exception would be thrown in the zygote, then * the exception should be thrown in the first run of the test case. @@ -60,7 +60,7 @@ public class OverlayConfigIterationRule implements TestRule { private final ArrayMap mOverlayStubResults = new ArrayMap<>(); private Supplier mOverlayScanner; - private AndroidPackageProvider mAndroidPackageProvider; + private PackageProvider mPkgProvider; private Iteration mIteration; /** @@ -96,9 +96,9 @@ public class OverlayConfigIterationRule implements TestRule { return mOverlayScanner; } - /** Retrieves the {@link AndroidPackageProvider} for the current run of the test. */ - AndroidPackageProvider getPackageProvider() { - return mAndroidPackageProvider; + /** Retrieves the {@link PackageProvider} for the current run of the test. */ + PackageProvider getPackageProvider() { + return mPkgProvider; } /** Retrieves the current iteration of the test. */ @@ -123,7 +123,7 @@ public class OverlayConfigIterationRule implements TestRule { } return scanner; }; - mAndroidPackageProvider = null; + mPkgProvider = null; mIteration = Iteration.ZYGOTE; base.evaluate(); @@ -131,14 +131,15 @@ public class OverlayConfigIterationRule implements TestRule { // the system server is parsing the configuration files and using PackageManager to // retrieving information of overlays. mOverlayScanner = null; - mAndroidPackageProvider = Mockito.mock(AndroidPackageProvider.class); + mPkgProvider = Mockito.mock(PackageProvider.class); mIteration = Iteration.SYSTEM_SERVER; doAnswer((InvocationOnMock invocation) -> { final Object[] args = invocation.getArguments(); - final Consumer f = (Consumer) args[0]; + final BiConsumer f = + (BiConsumer) args[0]; for (Map.Entry overlay : mOverlayStubResults.entrySet()) { - final AndroidPackage a = Mockito.mock(AndroidPackage.class); + final ParsingPackageRead a = Mockito.mock(ParsingPackageRead.class); final ParsedOverlayInfo info = overlay.getValue(); when(a.getPackageName()).thenReturn(info.packageName); when(a.getOverlayTarget()).thenReturn(info.targetPackageName); @@ -146,12 +147,10 @@ public class OverlayConfigIterationRule implements TestRule { when(a.isOverlayIsStatic()).thenReturn(info.isStatic); when(a.getOverlayPriority()).thenReturn(info.priority); when(a.getBaseCodePath()).thenReturn(info.path.getPath()); - when(a.isSystem()).thenReturn( - !info.path.getPath().contains("data/overlay")); - f.accept(a); + f.accept(a, !info.path.getPath().contains("data/overlay")); } return null; - }).when(mAndroidPackageProvider).forEachPackage(any()); + }).when(mPkgProvider).forEachPackage(any()); base.evaluate(); } diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java index 76f6ef63ae7e8..4ea637048c29c 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.ApplicationInfoFlags; import android.content.pm.PackageManager.ComponentInfoFlags; import android.content.pm.PackageManager.PackageInfoFlags; import android.content.pm.PackageManager.ResolveInfoFlags; -import android.content.pm.parsing.AndroidPackage; +import com.android.server.pm.parsing.pkg.AndroidPackage; + import android.content.pm.parsing.ComponentParseUtils; +import android.content.pm.parsing.ComponentParseUtils.ParsedMainComponent; import android.os.Bundle; import android.os.PersistableBundle; import android.util.ArrayMap; @@ -763,8 +765,8 @@ public abstract class PackageManagerInternal { throws IOException; /** Returns {@code true} if the specified component is enabled and matches the given flags. */ - public abstract boolean isEnabledAndMatches( - @NonNull ComponentParseUtils.ParsedComponent component, int flags, int userId); + public abstract boolean isEnabledAndMatches(@NonNull ParsedMainComponent component, int flags, + int userId); /** Returns {@code true} if the given user requires extra badging for icons. */ public abstract boolean userNeedsBadging(int userId); diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java index b9a30bb21edbe..72fae77b59c42 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 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { try { ParsedPackage pkg = parser.parseParsedPackage(installationPath, 0, false); int flags = PackageManager.GET_SIGNING_CERTIFICATES | PackageManager.GET_META_DATA; - ApkParseUtils.collectCertificates(pkg, false); + pkg.setSigningDetails(ApkParseUtils.collectCertificates(pkg, false)); return PackageInfoUtils.generate(pkg, null, flags, 0, 0, null, new PackageUserState(), UserHandle.getCallingUserId()); } catch (Exception e) { diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java index a1250cb8849f9..6a582b1f1625f 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 @@ public class AppsFilter { /** Returns true if the querying package may query for the potential target package */ private static boolean canQueryViaComponents(AndroidPackage querying, AndroidPackage potentialTarget) { - if (querying.getQueriesIntents() != null) { + if (!querying.getQueriesIntents().isEmpty()) { for (Intent intent : querying.getQueriesIntents()) { if (matchesIntentFilters(intent, potentialTarget)) { return true; } } } - if (querying.getQueriesProviders() != null + if (!querying.getQueriesProviders().isEmpty() && matchesProviders(querying.getQueriesProviders(), potentialTarget)) { return true; } @@ -223,7 +223,7 @@ public class AppsFilter { private static boolean canQueryViaPackage(AndroidPackage querying, AndroidPackage potentialTarget) { - return querying.getQueriesPackages() != null + return !querying.getQueriesPackages().isEmpty() && querying.getQueriesPackages().contains(potentialTarget.getPackageName()); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index f6eb76bdaf977..d9cb2128e606e 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.VersionedPackage; import android.content.pm.dex.ArtManager; import android.content.pm.dex.DexMetadataHelper; import android.content.pm.dex.IArtManager; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.ApkParseUtils; import android.content.pm.parsing.ComponentParseUtils; import android.content.pm.parsing.ComponentParseUtils.ParsedActivity; import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo; -import android.content.pm.parsing.ComponentParseUtils.ParsedComponent; import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation; +import android.content.pm.parsing.ComponentParseUtils.ParsedMainComponent; import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; import android.content.pm.parsing.ComponentParseUtils.ParsedProvider; import android.content.pm.parsing.ComponentParseUtils.ParsedService; -import android.content.pm.parsing.PackageImpl; -import android.content.pm.parsing.PackageInfoUtils; -import android.content.pm.parsing.ParsedPackage; -import android.content.pm.parsing.library.PackageBackwardCompatibility; +import android.content.pm.parsing.ParsingPackageRead; +import android.content.pm.parsing.ParsingPackageUtils; import android.content.res.Resources; import android.content.rollback.IRollbackManager; import android.database.ContentObserver; @@ -341,6 +337,13 @@ import com.android.server.pm.dex.DexManager; import com.android.server.pm.dex.DexoptOptions; import com.android.server.pm.dex.PackageDexUsage; import com.android.server.pm.dex.ViewCompiler; +import com.android.server.pm.parsing.PackageInfoUtils; +import com.android.server.pm.parsing.PackageParser2; +import com.android.server.pm.parsing.library.PackageBackwardCompatibility; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.AndroidPackageUtils; +import com.android.server.pm.parsing.pkg.PackageImpl; +import com.android.server.pm.parsing.pkg.ParsedPackage; import com.android.server.pm.permission.BasePermission; import com.android.server.pm.permission.PermissionManagerService; import com.android.server.pm.permission.PermissionManagerServiceInternal; @@ -1011,13 +1014,13 @@ public class PackageManagerService extends IPackageManager.Stub private final AppsFilter mAppsFilter; - class PackageParserCallback implements PackageParser.Callback { + class PackageParserCallback extends PackageParser2.Callback { @Override public final boolean hasFeature(String feature) { return PackageManagerService.this.hasSystemFeature(feature, 0); } } - final PackageParser.Callback mPackageParserCallback = new PackageParserCallback(); + final PackageParser2.Callback mPackageParserCallback = new PackageParserCallback(); // Currently known shared libraries. final ArrayMap> mSharedLibraries = new ArrayMap<>(); @@ -2033,7 +2036,7 @@ public class PackageManagerService extends IPackageManager.Stub mInstantAppRegistry.onPackageInstalledLPw(res.pkg, res.newUsers); } - final String packageName = res.pkg.getAppInfoPackageName(); + final String packageName = res.pkg.getPackageName(); // Determine the set of users who are adding this package for // the first time vs. those who are seeing an update. @@ -2083,7 +2086,7 @@ public class PackageManagerService extends IPackageManager.Stub // Send added for users that see the package for the first time // sendPackageAddedForNewUsers also deals with system apps int appId = UserHandle.getAppId(res.uid); - boolean isSystem = res.pkg.isSystemApp(); + boolean isSystem = res.pkg.isSystem(); sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload, virtualPreload /*startReceiver*/, appId, firstUserIds, firstInstantUserIds); @@ -2859,12 +2862,8 @@ public class PackageManagerService extends IPackageManager.Stub final int systemParseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR; final int systemScanFlags = scanFlags | SCAN_AS_SYSTEM; - PackageParser packageParser = new PackageParser(); - packageParser.setSeparateProcesses(mSeparateProcesses); - packageParser.setOnlyCoreApps(mOnlyCore); - packageParser.setDisplayMetrics(mMetrics); - packageParser.setCacheDir(mCacheDir); - packageParser.setCallback(mPackageParserCallback); + PackageParser2 packageParser = new PackageParser2(mSeparateProcesses, mOnlyCore, + mMetrics, mCacheDir, mPackageParserCallback); ExecutorService executorService = ParallelPackageParser.makeExecutorService(); // Collect vendor/product/system_ext overlay packages. (Do this before scanning @@ -2902,7 +2901,9 @@ public class PackageManagerService extends IPackageManager.Stub // Parse overlay configuration files to set default enable state, mutability, and // priority of system overlays. - mOverlayConfig = OverlayConfig.initializeSystemInstance(mPmInternal::forEachPackage); + mOverlayConfig = OverlayConfig.initializeSystemInstance( + consumer -> mPmInternal.forEachPackage( + pkg -> consumer.accept(pkg, pkg.isSystem()))); // Prune any system packages that no longer exist. final List possiblyDeletedUpdatedSystemApps = new ArrayList<>(); @@ -3044,7 +3045,7 @@ public class PackageManagerService extends IPackageManager.Stub // special privileges removePackageLI(pkg, true); try { - final File codePath = new File(pkg.getAppInfoCodePath()); + final File codePath = new File(pkg.getCodePath()); scanPackageTracedLI(codePath, 0, scanFlags, 0, null); } catch (PackageManagerException e) { Slog.e(TAG, "Failed to parse updated, ex-system package: " @@ -4208,7 +4209,7 @@ public class PackageManagerService extends IPackageManager.Stub throw new SecurityException("Package " + packageName + " is currently frozen!"); } - if (!userKeyUnlocked && !ps.pkg.isEncryptionAware()) { + if (!userKeyUnlocked && !AndroidPackageUtils.isEncryptionAware(ps.pkg)) { throw new SecurityException("Package " + packageName + " is not encryption aware!"); } } @@ -4574,7 +4575,7 @@ public class PackageManagerService extends IPackageManager.Stub // reader synchronized (mLock) { final AndroidPackage p = mPackages.get(packageName); - if (p != null && p.isMatch(flags)) { + if (p != null && AndroidPackageUtils.isMatchForSystemOnly(p, flags)) { PackageSetting ps = getPackageSettingInternal(p.getPackageName(), callingUid); if (shouldFilterApplicationLocked(ps, callingUid, userId)) { return -1; @@ -4604,7 +4605,7 @@ public class PackageManagerService extends IPackageManager.Stub // reader synchronized (mLock) { final AndroidPackage p = mPackages.get(packageName); - if (p != null && p.isMatch(flags)) { + if (p != null && AndroidPackageUtils.isMatchForSystemOnly(p, flags)) { PackageSetting ps = getPackageSetting(p.getPackageName()); if (shouldFilterApplicationLocked(ps, callingUid, userId)) { return null; @@ -8563,7 +8564,7 @@ public class PackageManagerService extends IPackageManager.Stub return null; } final ParsedInstrumentation i = mInstrumentation.get(component); - return PackageInfoUtils.generateInstrumentationInfo(i, pkg, flags); + return PackageInfoUtils.generateInstrumentationInfo(i, pkg, flags, callingUserId); } } @@ -8576,11 +8577,12 @@ public class PackageManagerService extends IPackageManager.Stub if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) { return ParceledListSlice.emptyList(); } - return new ParceledListSlice<>(queryInstrumentationInternal(targetPackage, flags)); + return new ParceledListSlice<>(queryInstrumentationInternal(targetPackage, flags, + callingUserId)); } private @NonNull List queryInstrumentationInternal(String targetPackage, - int flags) { + int flags, int userId) { ArrayList finalList = new ArrayList<>(); // reader @@ -8593,7 +8595,7 @@ public class PackageManagerService extends IPackageManager.Stub AndroidPackage pkg = mPackages.get(p.getPackageName()); if (pkg != null) { InstrumentationInfo ii = PackageInfoUtils.generateInstrumentationInfo(p, - pkg, flags); + pkg, flags, userId); if (ii != null) { finalList.add(ii); } @@ -8606,7 +8608,7 @@ public class PackageManagerService extends IPackageManager.Stub } private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags, - long currentTime, PackageParser packageParser, ExecutorService executorService) { + long currentTime, PackageParser2 packageParser, ExecutorService executorService) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]"); try { scanDirLI(scanDir, parseFlags, scanFlags, currentTime, packageParser, executorService); @@ -8616,7 +8618,7 @@ public class PackageManagerService extends IPackageManager.Stub } private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime, - PackageParser packageParser, ExecutorService executorService) { + PackageParser2 packageParser, ExecutorService executorService) { final File[] files = scanDir.listFiles(); if (ArrayUtils.isEmpty(files)) { Log.d(TAG, "No files in app dir " + scanDir); @@ -8720,7 +8722,8 @@ public class PackageManagerService extends IPackageManager.Stub try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates"); - ApkParseUtils.collectCertificates(parsedPackage, skipVerify); + parsedPackage.setSigningDetails( + ParsingPackageUtils.collectCertificates(parsedPackage, skipVerify)); } catch (PackageParserException e) { throw PackageManagerException.from(e); } finally { @@ -8774,16 +8777,13 @@ public class PackageManagerService extends IPackageManager.Stub private AndroidPackage scanPackageLI(File scanFile, int parseFlags, int scanFlags, long currentTime, UserHandle user) throws PackageManagerException { if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile); - PackageParser pp = new PackageParser(); - pp.setSeparateProcesses(mSeparateProcesses); - pp.setOnlyCoreApps(mOnlyCore); - pp.setDisplayMetrics(mMetrics); - pp.setCallback(mPackageParserCallback); + PackageParser2 pp = new PackageParser2(mSeparateProcesses, mOnlyCore, mMetrics, null, + mPackageParserCallback); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage"); final ParsedPackage parsedPackage; try { - parsedPackage = pp.parseParsedPackage(scanFile, parseFlags, false); + parsedPackage = pp.parsePackage(scanFile, parseFlags, false); } catch (PackageParserException e) { throw PackageManagerException.from(e); } finally { @@ -8869,18 +8869,6 @@ public class PackageManagerService extends IPackageManager.Stub final boolean pkgAlreadyExists; PackageSetting pkgSetting; - // NOTE: installPackageLI() has the same code to setup the package's - // application info. This probably should be done lower in the call - // stack [such as scanPackageOnly()]. However, we verify the application - // info prior to that [in scanPackageNew()] and thus have to setup - // the application info early. - // TODO(b/135203078): Remove all of these application info calls - parsedPackage.setApplicationVolumeUuid(parsedPackage.getVolumeUuid()) - .setApplicationInfoCodePath(parsedPackage.getCodePath()) - .setApplicationInfoResourcePath(parsedPackage.getCodePath()) - .setApplicationInfoBaseResourcePath(parsedPackage.getBaseCodePath()) - .setApplicationInfoSplitResourcePaths(parsedPackage.getSplitCodePaths()); - synchronized (mLock) { renamedPkgName = mSettings.getRenamedPackageLPr(parsedPackage.getRealPackage()); final String realPkgName = getRealPackageName(parsedPackage, renamedPkgName); @@ -9957,7 +9945,7 @@ public class PackageManagerService extends IPackageManager.Stub // Or: // - Package manager is in a state where package isn't scanned yet. This will // get called again after scanning to fix the dependencies. - if (pkg.isLibrary()) { + if (AndroidPackageUtils.isLibrary(pkg)) { if (pkg.getStaticSharedLibName() != null) { SharedLibraryInfo definedLibrary = getSharedLibraryInfoLPr( pkg.getStaticSharedLibName(), pkg.getStaticSharedLibVersion()); @@ -9994,7 +9982,7 @@ public class PackageManagerService extends IPackageManager.Stub } } if (p != null) { - usesLibraryFiles.addAll(p.getAllCodePaths()); + usesLibraryFiles.addAll(AndroidPackageUtils.getAllCodePaths(p)); // If the package provides libraries, add the dependency to them. applyDefiningSharedLibraryUpdateLocked(pkg, libInfo, (definingLibrary, dependency) -> { definingLibrary.addDependency(dependency); @@ -10026,18 +10014,18 @@ public class PackageManagerService extends IPackageManager.Stub // that libraries are searched in the correct order) and must have no // duplicates. ArrayList usesLibraryInfos = null; - if (pkg.getUsesLibraries() != null) { + if (!pkg.getUsesLibraries().isEmpty()) { usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesLibraries(), null, null, pkg.getPackageName(), true, pkg.getTargetSdkVersion(), null, availablePackages, existingLibraries, newLibraries); } - if (pkg.getUsesStaticLibraries() != null) { + if (!pkg.getUsesStaticLibraries().isEmpty()) { usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesStaticLibraries(), pkg.getUsesStaticLibrariesVersions(), pkg.getUsesStaticLibrariesCertDigests(), pkg.getPackageName(), true, pkg.getTargetSdkVersion(), usesLibraryInfos, availablePackages, existingLibraries, newLibraries); } - if (pkg.getUsesOptionalLibraries() != null) { + if (!pkg.getUsesOptionalLibraries().isEmpty()) { usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesOptionalLibraries(), null, null, pkg.getPackageName(), false, pkg.getTargetSdkVersion(), usesLibraryInfos, availablePackages, existingLibraries, newLibraries); @@ -10607,7 +10595,7 @@ public class PackageManagerService extends IPackageManager.Stub } pkgSetting.signatures.mSigningDetails = reconciledPkg.signingDetails; - if (pkg.getAdoptPermissions() != null) { + if (!pkg.getAdoptPermissions().isEmpty()) { // This package wants to adopt ownership of permissions from // another package. for (int i = pkg.getAdoptPermissions().size() - 1; i >= 0; i--) { @@ -10848,8 +10836,8 @@ public class PackageManagerService extends IPackageManager.Stub } // Initialize package source and resource directories - final File destCodeFile = new File(parsedPackage.getAppInfoCodePath()); - final File destResourceFile = new File(parsedPackage.getAppInfoResourcePath()); + final File destCodeFile = new File(parsedPackage.getCodePath()); + final File destResourceFile = new File(parsedPackage.getCodePath()); // We keep references to the derived CPU Abis from settings in oder to reuse // them in the case where we're not upgrading or booting for the first time. @@ -10878,7 +10866,7 @@ public class PackageManagerService extends IPackageManager.Stub } String[] usesStaticLibraries = null; - if (parsedPackage.getUsesStaticLibraries() != null) { + if (!parsedPackage.getUsesStaticLibraries().isEmpty()) { usesStaticLibraries = new String[parsedPackage.getUsesStaticLibraries().size()]; parsedPackage.getUsesStaticLibraries().toArray(usesStaticLibraries); } @@ -10898,8 +10886,7 @@ public class PackageManagerService extends IPackageManager.Stub } else { // make a deep copy to avoid modifying any existing system state. pkgSetting = new PackageSetting(pkgSetting); - // TODO(b/135203078): Remove entirely. Set package directly. - parsedPackage.setPackageSettingCallback(pkgSetting); + pkgSetting.pkg = parsedPackage; // REMOVE SharedUserSetting from method; update in a separate call. // @@ -10945,9 +10932,7 @@ public class PackageManagerService extends IPackageManager.Stub .setSeInfo(SELinuxMMAC.getSeInfo(parsedPackage, sharedUserSetting, injector.getCompatibility())) .setSeInfoUser(SELinuxUtil.assignSeinfoUser(pkgSetting.readUserState( - userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId))) - .setProcessName(fixProcessName(parsedPackage.getPackageName(), - parsedPackage.getProcessName())); + userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId))); if (!isPlatformPackage) { // Get all of our default paths setup @@ -10964,7 +10949,7 @@ public class PackageManagerService extends IPackageManager.Stub if ((scanFlags & SCAN_NEW_INSTALL) == 0) { if (needToDeriveAbi) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi"); - final boolean extractNativeLibs = !parsedPackage.isLibrary(); + final boolean extractNativeLibs = !AndroidPackageUtils.isLibrary(parsedPackage); final Pair derivedAbi = packageAbiHelper.derivePackageAbi(parsedPackage, cpuAbiOverride, extractNativeLibs); @@ -11104,13 +11089,13 @@ public class PackageManagerService extends IPackageManager.Stub } pkgSetting.setTimeStamp(scanFileTime); // TODO(b/135203078): Remove, move to constructor - parsedPackage.setPackageSettingCallback(pkgSetting); + pkgSetting.pkg = parsedPackage; pkgSetting.pkgFlags = parsedPackage.getFlags(); if (parsedPackage.getLongVersionCode() != pkgSetting.versionCode) { pkgSetting.versionCode = parsedPackage.getLongVersionCode(); } // Update volume if needed - final String volumeUuid = parsedPackage.getApplicationInfoVolumeUuid(); + final String volumeUuid = parsedPackage.getVolumeUuid(); if (!Objects.equals(volumeUuid, pkgSetting.volumeUuid)) { Slog.i(PackageManagerService.TAG, "Update" + (pkgSetting.isSystem() ? " system" : "") @@ -11122,14 +11107,15 @@ public class PackageManagerService extends IPackageManager.Stub SharedLibraryInfo staticSharedLibraryInfo = null; if (!TextUtils.isEmpty(parsedPackage.getStaticSharedLibName())) { - staticSharedLibraryInfo = SharedLibraryInfo.createForStatic(parsedPackage); + staticSharedLibraryInfo = + AndroidPackageUtils.createSharedLibraryForStatic(parsedPackage); } List dynamicSharedLibraryInfos = null; if (!ArrayUtils.isEmpty(parsedPackage.getLibraryNames())) { dynamicSharedLibraryInfos = new ArrayList<>(parsedPackage.getLibraryNames().size()); for (String name : parsedPackage.getLibraryNames()) { dynamicSharedLibraryInfos.add( - SharedLibraryInfo.createForDynamic(parsedPackage, name)); + AndroidPackageUtils.createSharedLibraryForDynamic(parsedPackage, name)); } } @@ -11202,7 +11188,7 @@ public class PackageManagerService extends IPackageManager.Stub parsedPackage.setAllComponentsDirectBootAware(true); } if (compressedFileExists(parsedPackage.getCodePath())) { - parsedPackage.setIsStub(true); + parsedPackage.setStub(true); } } else { parsedPackage @@ -11257,7 +11243,7 @@ public class PackageManagerService extends IPackageManager.Stub private void assertPackageProcesses(AndroidPackage pkg, List components, - ArrayMap procs, String compName) + Map procs, String compName) throws PackageManagerException { if (components == null) { return; @@ -11291,8 +11277,7 @@ public class PackageManagerService extends IPackageManager.Stub assertCodePolicy(pkg); } - if (pkg.getAppInfoCodePath() == null || - pkg.getAppInfoResourcePath() == null) { + if (pkg.getCodePath() == null) { // Bail out. The resource and code paths haven't been set. throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Code and resource paths haven't been set correctly"); @@ -11375,49 +11360,49 @@ public class PackageManagerService extends IPackageManager.Stub } // Static shared libs cannot declare activities - if (pkg.getActivities() != null && !pkg.getActivities().isEmpty()) { + if (!pkg.getActivities().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare activities"); } // Static shared libs cannot declare services - if (pkg.getServices() != null && !pkg.getServices().isEmpty()) { + if (!pkg.getServices().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare services"); } // Static shared libs cannot declare providers - if (pkg.getProviders() != null && !pkg.getProviders().isEmpty()) { + if (!pkg.getProviders().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare content providers"); } // Static shared libs cannot declare receivers - if (pkg.getReceivers() != null && !pkg.getReceivers().isEmpty()) { + if (!pkg.getReceivers().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare broadcast receivers"); } // Static shared libs cannot declare permission groups - if (pkg.getPermissionGroups() != null && !pkg.getPermissionGroups().isEmpty()) { + if (!pkg.getPermissionGroups().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare permission groups"); } // Static shared libs cannot declare features - if (pkg.getFeatures() != null && !pkg.getFeatures().isEmpty()) { + if (!pkg.getFeatures().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare features"); } // Static shared libs cannot declare permissions - if (pkg.getPermissions() != null && !pkg.getPermissions().isEmpty()) { + if (!pkg.getPermissions().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare permissions"); } // Static shared libs cannot declare protected broadcasts - if (pkg.getProtectedBroadcasts() != null) { + if (!pkg.getProtectedBroadcasts().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare protected broadcasts"); } @@ -11479,12 +11464,11 @@ public class PackageManagerService extends IPackageManager.Stub + " and requiring known paths " + known.codePathString + " & " + known.resourcePathString); } - if (!pkg.getAppInfoCodePath().equals(known.codePathString) - || !pkg.getAppInfoResourcePath().equals( - known.resourcePathString)) { + if (!pkg.getCodePath().equals(known.codePathString) + || !pkg.getCodePath().equals(known.resourcePathString)) { throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED, "Application package " + pkg.getPackageName() - + " found at " + pkg.getAppInfoCodePath() + + " found at " + pkg.getCodePath() + " but expected at " + known.codePathString + "; ignoring."); } @@ -11506,8 +11490,8 @@ public class PackageManagerService extends IPackageManager.Stub // If this package has defined explicit processes, then ensure that these are // the only processes used by its components. - final ArrayMap procs = pkg.getProcesses(); - if (procs != null) { + final Map procs = pkg.getProcesses(); + if (!procs.isEmpty()) { if (!procs.containsKey(pkg.getProcessName())) { throw new PackageManagerException( INSTALL_FAILED_PROCESS_NOT_DEFINED, @@ -11793,7 +11777,7 @@ public class PackageManagerService extends IPackageManager.Stub if (clientLibPkgs != null) { for (int i=0; i UNAVAILABLE"); } final int[] uidArray = new int[]{oldPackage.getUid()}; final ArrayList pkgList = new ArrayList<>(1); - pkgList.add(oldPackage.getAppInfoPackageName()); + pkgList.add(oldPackage.getPackageName()); sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null); } @@ -16328,16 +16296,14 @@ public class PackageManagerService extends IPackageManager.Stub | PackageParser.PARSE_ENFORCE_CODE | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0); - PackageParser pp = new PackageParser(); - pp.setSeparateProcesses(mSeparateProcesses); - pp.setDisplayMetrics(mMetrics); - pp.setCallback(mPackageParserCallback); + PackageParser2 pp = new PackageParser2(mSeparateProcesses, false, mMetrics, null, + mPackageParserCallback); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage"); ParsedPackage parsedPackage; try { - parsedPackage = pp.parseParsedPackage(tmpPackageFile, parseFlags, false); - DexMetadataHelper.validatePackageDexMetadata(parsedPackage); + parsedPackage = pp.parsePackage(tmpPackageFile, parseFlags, false); + AndroidPackageUtils.validatePackageDexMetadata(parsedPackage); } catch (PackageParserException e) { throw new PrepareFailure("Failed parse during installPackageLI", e); } finally { @@ -16393,7 +16359,8 @@ public class PackageManagerService extends IPackageManager.Stub parsedPackage.setSigningDetails(args.signingDetails); } else { // TODO(b/136132412): skip for Incremental installation - ApkParseUtils.collectCertificates(parsedPackage, false /* skipVerify */); + parsedPackage.setSigningDetails( + ParsingPackageUtils.collectCertificates(parsedPackage, false /* skipVerify */)); } } catch (PackageParserException e) { throw new PrepareFailure("Failed collect during installPackageLI", e); @@ -16636,7 +16603,7 @@ public class PackageManagerService extends IPackageManager.Stub try { String abiOverride = (TextUtils.isEmpty(parsedPackage.getCpuAbiOverride()) ? args.abiOverride : parsedPackage.getCpuAbiOverride()); - final boolean extractNativeLibs = !parsedPackage.isLibrary(); + final boolean extractNativeLibs = !AndroidPackageUtils.isLibrary(parsedPackage); final Pair derivedAbi = mInjector.getAbiHelper().derivePackageAbi( parsedPackage, abiOverride, extractNativeLibs); @@ -19980,7 +19947,7 @@ public class PackageManagerService extends IPackageManager.Stub // We're dealing with a component level state change // First, verify that this is a valid class name. AndroidPackage pkg = pkgSetting.pkg; - if (pkg == null || !pkg.hasComponentClassName(className)) { + if (pkg == null || !AndroidPackageUtils.hasComponentClassName(pkg, className)) { if (pkg != null && pkg.getTargetSdkVersion() >= Build.VERSION_CODES.JELLY_BEAN) { @@ -21336,7 +21303,7 @@ public class PackageManagerService extends IPackageManager.Stub final int[] packageUids = new int[size]; for (int i = 0; i < size; i++) { final AndroidPackage pkg = packages.get(i); - packageNames[i] = pkg.getAppInfoPackageName(); + packageNames[i] = pkg.getPackageName(); packageUids[i] = pkg.getUid(); } sendResourcesChangedBroadcast(mediaStatus, replacing, packageNames, packageUids, @@ -21801,7 +21768,7 @@ public class PackageManagerService extends IPackageManager.Stub ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags, appId, seInfo, pkg.getTargetSdkVersion()); } catch (InstallerException e) { - if (pkg.isSystemApp()) { + if (pkg.isSystem()) { logCriticalInfo(Log.ERROR, "Failed to create app data for " + packageName + ", but trying to recover: " + e); destroyAppDataLeafLIF(pkg, userId, flags); @@ -22054,7 +22021,7 @@ public class PackageManagerService extends IPackageManager.Stub || shouldFilterApplicationLocked(ps, callingUid, user.getIdentifier())) { throw new PackageManagerException(MOVE_FAILED_DOESNT_EXIST, "Missing package"); } - if (pkg.isSystemApp()) { + if (pkg.isSystem()) { throw new PackageManagerException(MOVE_FAILED_SYSTEM_PACKAGE, "Cannot move system application"); } @@ -22080,7 +22047,7 @@ public class PackageManagerService extends IPackageManager.Stub throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR, "Package already moved to " + volumeUuid); } - if (pkg.isInternal() && isPackageDeviceAdminOnAnyUser(packageName)) { + if (!pkg.isExternalStorage() && isPackageDeviceAdminOnAnyUser(packageName)) { throw new PackageManagerException(MOVE_FAILED_DEVICE_ADMIN, "Device admin cannot be moved"); } @@ -23352,7 +23319,7 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public boolean isEnabledAndMatches(ParsedComponent component, int flags, int userId) { + public boolean isEnabledAndMatches(ParsedMainComponent component, int flags, int userId) { synchronized (mLock) { AndroidPackage pkg = getPackage(component.getPackageName()); return mSettings.isEnabledAndMatchLPr(pkg, component, flags, userId); @@ -24177,12 +24144,12 @@ public class PackageManagerService extends IPackageManager.Stub if (p == null) { return false; } - return p.canHaveOatDir(); + return AndroidPackageUtils.canHaveOatDir(p, p.isUpdatedSystemApp()); } } private String getOatDir(AndroidPackage pkg) { - if (!pkg.canHaveOatDir()) { + if (!AndroidPackageUtils.canHaveOatDir(pkg, pkg.isUpdatedSystemApp())) { return null; } File codePath = new File(pkg.getCodePath()); @@ -24202,7 +24169,7 @@ public class PackageManagerService extends IPackageManager.Stub } instructionSets = getAppDexInstructionSets(pkg.getPrimaryCpuAbi(), pkg.getSecondaryCpuAbi()); - codePaths = pkg.getAllCodePaths(); + codePaths = AndroidPackageUtils.getAllCodePaths(pkg); oatDir = getOatDir(pkg); for (String codePath : codePaths) { diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java index a9035b21a32b8..60402242a84c5 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; import android.content.pm.PackageParser.PackageParserException; import android.content.pm.ResolveInfo; import android.content.pm.Signature; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.ApkParseUtils; +import android.content.pm.parsing.ParsingPackageUtils; import android.os.Build; import android.os.Debug; import android.os.Environment; @@ -66,6 +65,7 @@ import com.android.internal.util.FastPrintWriter; import com.android.server.EventLogTags; import com.android.server.pm.dex.DexManager; import com.android.server.pm.dex.PackageDexUsage; +import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.pm.permission.PermissionsState; import dalvik.system.VMRuntime; @@ -544,7 +544,8 @@ public class PackageManagerServiceUtils { private static boolean matchSignatureInSystem(PackageSetting pkgSetting, PackageSetting disabledPkgSetting) { try { - ApkParseUtils.collectCertificates(disabledPkgSetting.pkg, true /* skipVerify */); + disabledPkgSetting.pkg.mutate().setSigningDetails( + ParsingPackageUtils.collectCertificates(disabledPkgSetting.pkg, true /* skipVerify */)); if (pkgSetting.signatures.mSigningDetails.checkCapability( disabledPkgSetting.signatures.mSigningDetails, PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA) diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index d83e6f4c74180..97342c0b4713b 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.annotation.Nullable; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.UserInfo; -import android.content.pm.parsing.AndroidPackage; -import android.content.pm.parsing.ParsedPackage; import android.service.pm.PackageProto; import android.util.ArrayMap; import android.util.ArraySet; import android.util.proto.ProtoOutputStream; +import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.pm.permission.PermissionsState; import java.io.File; @@ -39,8 +38,7 @@ import java.util.Set; /** * Settings data for a particular package we know about. */ -public final class PackageSetting extends PackageSettingBase implements - ParsedPackage.PackageSettingCallback { +public final class PackageSetting extends PackageSettingBase { int appId; public AndroidPackage pkg; @@ -323,10 +321,4 @@ public final class PackageSetting extends PackageSettingBase implements Set 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 448dad026e16c..21334c0f4d19f 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 @@ package com.android.server.pm; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; import android.content.pm.PackageParser; -import android.content.pm.parsing.ParsedPackage; import android.os.Process; import android.os.Trace; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ConcurrentUtils; +import com.android.server.pm.parsing.PackageParser2; +import com.android.server.pm.parsing.pkg.ParsedPackage; import java.io.File; import java.util.concurrent.ArrayBlockingQueue; @@ -50,11 +51,11 @@ class ParallelPackageParser { Process.THREAD_PRIORITY_FOREGROUND); } - private final PackageParser mPackageParser; + private final PackageParser2 mPackageParser; private final ExecutorService mExecutorService; - ParallelPackageParser(PackageParser packageParser, ExecutorService executorService) { + ParallelPackageParser(PackageParser2 packageParser, ExecutorService executorService) { mPackageParser = packageParser; mExecutorService = executorService; } @@ -125,6 +126,6 @@ class ParallelPackageParser { @VisibleForTesting protected ParsedPackage parsePackage(File scanFile, int parseFlags) throws PackageParser.PackageParserException { - return mPackageParser.parseParsedPackage(scanFile, parseFlags, true); + return mPackageParser.parsePackage(scanFile, parseFlags, true); } } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 60c8b949ec521..5694428dba716 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 @@ public final class Settings { LocalServices.getService(PackageManagerInternal.class); for (PackageSetting ps : mPackages.values()) { if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0 && ps.pkg != null - && ps.pkg.getPreferredActivityFilters() != null) { + && !ps.pkg.getPreferredActivityFilters().isEmpty()) { List intents = ps.pkg.getPreferredActivityFilters(); for (int i=0; i procs = pkg.getProcesses(); - if (procs != null) { + final Map procs = pkg.getProcesses(); + if (!procs.isEmpty()) { pw.print(prefix); pw.println(" processes:"); - for (int i = 0; i < procs.size(); i++) { - final ComponentParseUtils.ParsedProcess proc = procs.valueAt(i); + for (ComponentParseUtils.ParsedProcess proc : procs.values()) { pw.print(prefix); pw.print(" "); pw.println(proc.name); if (proc.deniedPermissions != null) { for (int j = 0; j < proc.deniedPermissions.size(); j++) { @@ -4751,7 +4750,7 @@ public final class Settings { pw.print(prefix); pw.print(" overlayCategory="); pw.println(pkg.getOverlayCategory()); } - if (pkg != null && pkg.getPermissions() != null && pkg.getPermissions().size() > 0) { + if (pkg != null && !pkg.getPermissions().isEmpty()) { final List perms = pkg.getPermissions(); pw.print(prefix); pw.println(" declared permissions:"); for (int i=0; i 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 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 generateProcessInfo( + Map procs, @PackageManager.ComponentInfoFlags int flags) { + if (procs == null) { + return null; + } + + final int numProcs = procs.size(); + ArrayMap 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 0000000000000..804f110eefa20 --- /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 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 239cf9d2f1ae5..d0ec969dc2e71 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 @@ public interface AndroidPackage extends PkgAppInfo, PkgPackageInfo, ParsingPacka @NonNull List getPermissionGroups(); - @Nullable + @NonNull List 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 36697f9b6d60d..e1d1a1a3c645a 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 @@ public class PermissionManagerService extends IPermissionManager.Stub { return EmptyArray.INT; } for (AndroidPackage pkg : pkgList) { - if (pkg.getRequestedPermissions() == null) { + if (pkg.getRequestedPermissions().isEmpty()) { continue; } final int requestedPermCount = pkg.getRequestedPermissions().size(); @@ -4246,7 +4246,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } private static boolean hasPermission(AndroidPackage pkg, String permName) { - if (pkg.getPermissions() == null) { + if (pkg.getPermissions().isEmpty()) { return false; } 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 da5986f71f116..20f3f3e7f331f 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 @@ public class ParallelPackageParserTest { @Before public void setUp() { - mParser = new TestParallelPackageParser(new PackageParser(), + mParser = new TestParallelPackageParser(new PackageParser2(null, false, null, null, null), ParallelPackageParser.makeExecutorService()); } @@ -72,7 +74,7 @@ public class ParallelPackageParserTest { private class TestParallelPackageParser extends ParallelPackageParser { - TestParallelPackageParser(PackageParser packageParser, ExecutorService executorService) { + TestParallelPackageParser(PackageParser2 packageParser, ExecutorService executorService) { super(packageParser, executorService); }