Important migration for new ParsingPackage/ParsedPackage split
Part of the Parsing/ParsedPackage split into core/server. This splits all the "important" changes, or those which change significant code/logic and that requires a closer look during review. Bug: 135203078 Test: enumerated in first commit of change ID Ib4fe51d729a56bfb0ea1316e577358ba0dfceccf Change-Id: Ie0e4394de2b3063121d850060fcd58622511c59d
This commit is contained in:
@@ -79,14 +79,10 @@ import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.PatternMatcher;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.os.SystemProperties;
|
||||
import android.os.Trace;
|
||||
import android.os.UserHandle;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.OsConstants;
|
||||
import android.system.StructStat;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
@@ -118,7 +114,6 @@ import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.annotation.Retention;
|
||||
@@ -316,8 +311,8 @@ public class PackageParser {
|
||||
|
||||
public int mParseError = PackageManager.INSTALL_SUCCEEDED;
|
||||
|
||||
public ThreadLocal<ApkParseUtils.ParseResult> mSharedResult
|
||||
= ThreadLocal.withInitial(ApkParseUtils.ParseResult::new);
|
||||
public ThreadLocal<ParsingPackageUtils.ParseResult> mSharedResult
|
||||
= ThreadLocal.withInitial(ParsingPackageUtils.ParseResult::new);
|
||||
|
||||
public static boolean sCompatibilityModeEnabled = true;
|
||||
public static boolean sUseRoundIcon = false;
|
||||
@@ -1054,7 +1049,7 @@ public class PackageParser {
|
||||
* and unique split names.
|
||||
* <p>
|
||||
* Note that this <em>does not</em> perform signature verification; that
|
||||
* must be done separately in {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}.
|
||||
* must be done separately in {@link #collectCertificates(Package, boolean)}.
|
||||
*
|
||||
* If {@code useCaches} is true, the package parser might return a cached
|
||||
* result from a previous parse of the same {@code packageFile} with the same
|
||||
@@ -1081,201 +1076,6 @@ public class PackageParser {
|
||||
return parsePackage(packageFile, flags, false /* useCaches */);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updated method which returns {@link ParsedPackage}, the current representation of a
|
||||
* package parsed from disk.
|
||||
*
|
||||
* @see #parsePackage(File, int, boolean)
|
||||
*/
|
||||
@AnyThread
|
||||
public ParsedPackage parseParsedPackage(File packageFile, int flags, boolean useCaches)
|
||||
throws PackageParserException {
|
||||
ParsedPackage parsed = useCaches ? getCachedResult(packageFile, flags) : null;
|
||||
if (parsed != null) {
|
||||
return parsed;
|
||||
}
|
||||
|
||||
long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
|
||||
ApkParseUtils.ParseInput parseInput = mSharedResult.get().reset();
|
||||
parsed = ApkParseUtils.parsePackage(
|
||||
parseInput,
|
||||
mSeparateProcesses,
|
||||
mCallback,
|
||||
mMetrics,
|
||||
mOnlyCoreApps,
|
||||
packageFile,
|
||||
flags
|
||||
)
|
||||
.hideAsParsed();
|
||||
|
||||
long cacheTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
|
||||
cacheResult(packageFile, flags, parsed);
|
||||
if (LOG_PARSE_TIMINGS) {
|
||||
parseTime = cacheTime - parseTime;
|
||||
cacheTime = SystemClock.uptimeMillis() - cacheTime;
|
||||
if (parseTime + cacheTime > LOG_PARSE_TIMINGS_THRESHOLD_MS) {
|
||||
Slog.i(TAG, "Parse times for '" + packageFile + "': parse=" + parseTime
|
||||
+ "ms, update_cache=" + cacheTime + " ms");
|
||||
}
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cache key for a specified {@code packageFile} and {@code flags}.
|
||||
*/
|
||||
private String getCacheKey(File packageFile, int flags) {
|
||||
StringBuilder sb = new StringBuilder(packageFile.getName());
|
||||
sb.append('-');
|
||||
sb.append(flags);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected ParsedPackage fromCacheEntry(byte[] bytes) {
|
||||
return fromCacheEntryStatic(bytes);
|
||||
}
|
||||
|
||||
/** static version of {@link #fromCacheEntry} for unit tests. */
|
||||
@VisibleForTesting
|
||||
public static ParsedPackage fromCacheEntryStatic(byte[] bytes) {
|
||||
final Parcel p = Parcel.obtain();
|
||||
p.unmarshall(bytes, 0, bytes.length);
|
||||
p.setDataPosition(0);
|
||||
|
||||
final ReadHelper helper = new ReadHelper(p);
|
||||
helper.startAndInstall();
|
||||
|
||||
// TODO(b/135203078): Hide PackageImpl constructor?
|
||||
ParsedPackage pkg = new PackageImpl(p);
|
||||
|
||||
p.recycle();
|
||||
|
||||
sCachedPackageReadCount.incrementAndGet();
|
||||
|
||||
return pkg;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected byte[] toCacheEntry(ParsedPackage pkg) {
|
||||
return toCacheEntryStatic(pkg);
|
||||
|
||||
}
|
||||
|
||||
/** static version of {@link #toCacheEntry} for unit tests. */
|
||||
@VisibleForTesting
|
||||
public static byte[] toCacheEntryStatic(ParsedPackage pkg) {
|
||||
final Parcel p = Parcel.obtain();
|
||||
final WriteHelper helper = new WriteHelper(p);
|
||||
|
||||
pkg.writeToParcel(p, 0 /* flags */);
|
||||
|
||||
helper.finishAndUninstall();
|
||||
|
||||
byte[] serialized = p.marshall();
|
||||
p.recycle();
|
||||
|
||||
return serialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a {@code packageFile} and a {@code cacheFile} returns whether the
|
||||
* cache file is up to date based on the mod-time of both files.
|
||||
*/
|
||||
private static boolean isCacheUpToDate(File packageFile, File cacheFile) {
|
||||
try {
|
||||
// NOTE: We don't use the File.lastModified API because it has the very
|
||||
// non-ideal failure mode of returning 0 with no excepions thrown.
|
||||
// The nio2 Files API is a little better but is considerably more expensive.
|
||||
final StructStat pkg = android.system.Os.stat(packageFile.getAbsolutePath());
|
||||
final StructStat cache = android.system.Os.stat(cacheFile.getAbsolutePath());
|
||||
return pkg.st_mtime < cache.st_mtime;
|
||||
} catch (ErrnoException ee) {
|
||||
// The most common reason why stat fails is that a given cache file doesn't
|
||||
// exist. We ignore that here. It's easy to reason that it's safe to say the
|
||||
// cache isn't up to date if we see any sort of exception here.
|
||||
//
|
||||
// (1) Exception while stating the package file : This should never happen,
|
||||
// and if it does, we do a full package parse (which is likely to throw the
|
||||
// same exception).
|
||||
// (2) Exception while stating the cache file : If the file doesn't exist, the
|
||||
// cache is obviously out of date. If the file *does* exist, we can't read it.
|
||||
// We will attempt to delete and recreate it after parsing the package.
|
||||
if (ee.errno != OsConstants.ENOENT) {
|
||||
Slog.w("Error while stating package cache : ", ee);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cached parse result for {@code packageFile} for parse flags {@code flags},
|
||||
* or {@code null} if no cached result exists.
|
||||
*/
|
||||
public ParsedPackage getCachedResult(File packageFile, int flags) {
|
||||
if (mCacheDir == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final String cacheKey = getCacheKey(packageFile, flags);
|
||||
final File cacheFile = new File(mCacheDir, cacheKey);
|
||||
|
||||
try {
|
||||
// If the cache is not up to date, return null.
|
||||
if (!isCacheUpToDate(packageFile, cacheFile)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final byte[] bytes = IoUtils.readFileAsByteArray(cacheFile.getAbsolutePath());
|
||||
return fromCacheEntry(bytes);
|
||||
} catch (Throwable e) {
|
||||
Slog.w(TAG, "Error reading package cache: ", e);
|
||||
|
||||
// If something went wrong while reading the cache entry, delete the cache file
|
||||
// so that we regenerate it the next time.
|
||||
cacheFile.delete();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches the parse result for {@code packageFile} with flags {@code flags}.
|
||||
*/
|
||||
public void cacheResult(File packageFile, int flags, ParsedPackage parsed) {
|
||||
if (mCacheDir == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final String cacheKey = getCacheKey(packageFile, flags);
|
||||
final File cacheFile = new File(mCacheDir, cacheKey);
|
||||
|
||||
if (cacheFile.exists()) {
|
||||
if (!cacheFile.delete()) {
|
||||
Slog.e(TAG, "Unable to delete cache file: " + cacheFile);
|
||||
}
|
||||
}
|
||||
|
||||
final byte[] cacheEntry = toCacheEntry(parsed);
|
||||
|
||||
if (cacheEntry == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try (FileOutputStream fos = new FileOutputStream(cacheFile)) {
|
||||
fos.write(cacheEntry);
|
||||
} catch (IOException ioe) {
|
||||
Slog.w(TAG, "Error writing cache entry.", ioe);
|
||||
cacheFile.delete();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
Slog.w(TAG, "Error saving package cache.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse all APKs contained in the given directory, treating them as a
|
||||
* single package. This also performs sanity checking, such as requiring
|
||||
@@ -1284,7 +1084,7 @@ public class PackageParser {
|
||||
* <p>
|
||||
* Note that this <em>does not</em> perform signature verification; that
|
||||
* must be done separately in
|
||||
* {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}.
|
||||
* {@link #collectCertificates(Package, boolean)} .
|
||||
*/
|
||||
private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
|
||||
final PackageLite lite = parseClusterPackageLite(packageDir, 0);
|
||||
@@ -1346,7 +1146,7 @@ public class PackageParser {
|
||||
* <p>
|
||||
* Note that this <em>does not</em> perform signature verification; that
|
||||
* must be done separately in
|
||||
* {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}.
|
||||
* {@link #collectCertificates(Package, boolean)}.
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -82,7 +82,7 @@ import java.util.Objects;
|
||||
*/
|
||||
public class ComponentParseUtils {
|
||||
|
||||
private static final String TAG = ApkParseUtils.TAG;
|
||||
private static final String TAG = ParsingUtils.TAG;
|
||||
|
||||
// TODO(b/135203078): None of this class's subclasses do anything. Remove in favor of base?
|
||||
public static class ParsedIntentInfo extends IntentFilter {
|
||||
@@ -315,7 +315,7 @@ public class ComponentParseUtils {
|
||||
// TODO(b/135203078): Make subclass that contains these fields only for the necessary
|
||||
// subtypes
|
||||
protected boolean enabled = true;
|
||||
protected boolean directBootAware;
|
||||
public boolean directBootAware;
|
||||
public int flags;
|
||||
|
||||
private String packageName;
|
||||
@@ -1460,7 +1460,7 @@ public class ComponentParseUtils {
|
||||
outError[0] = tag + " does not specify android:name";
|
||||
return null;
|
||||
} else {
|
||||
String className = ApkParseUtils.buildClassName(packageName, name);
|
||||
String className = ParsingUtils.buildClassName(packageName, name);
|
||||
if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
|
||||
outError[0] = tag + " invalid android:name";
|
||||
return null;
|
||||
@@ -1537,7 +1537,7 @@ public class ComponentParseUtils {
|
||||
R.styleable.AndroidManifestActivity_parentActivityName,
|
||||
Configuration.NATIVE_CONFIG_VERSION);
|
||||
if (parentName != null) {
|
||||
String parentClassName = ApkParseUtils.buildClassName(packageName, parentName);
|
||||
String parentClassName = ParsingUtils.buildClassName(packageName, parentName);
|
||||
if (parentClassName == null) {
|
||||
Log.e(TAG,
|
||||
"Activity " + result.className
|
||||
@@ -1856,9 +1856,8 @@ public class ComponentParseUtils {
|
||||
parsingPackage.addPreferredActivityFilter(intentInfo);
|
||||
}
|
||||
} else if (parser.getName().equals("meta-data")) {
|
||||
if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
|
||||
result.metaData,
|
||||
outError)) == null) {
|
||||
if ((result.metaData = ParsingPackageUtils.parseMetaData(parsingPackage, res,
|
||||
parser, result.metaData, outError)) == null) {
|
||||
return null;
|
||||
}
|
||||
} else if (!receiver && parser.getName().equals("layout")) {
|
||||
@@ -1969,7 +1968,7 @@ public class ComponentParseUtils {
|
||||
outError[0] = "<service> does not specify android:name";
|
||||
return null;
|
||||
} else {
|
||||
String className = ApkParseUtils.buildClassName(packageName, name);
|
||||
String className = ParsingUtils.buildClassName(packageName, name);
|
||||
if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
|
||||
outError[0] = "<service> invalid android:name";
|
||||
return null;
|
||||
@@ -2099,7 +2098,7 @@ public class ComponentParseUtils {
|
||||
}
|
||||
}
|
||||
|
||||
if (parsingPackage.cantSaveState()) {
|
||||
if (parsingPackage.isCantSaveState()) {
|
||||
// A heavy-weight application can not have services in its main process
|
||||
// We can do direct compare because we intern all strings.
|
||||
if (Objects.equals(result.getProcessName(), parsingPackage.getPackageName())) {
|
||||
@@ -2132,9 +2131,8 @@ public class ComponentParseUtils {
|
||||
result.order = Math.max(intent.getOrder(), result.order);
|
||||
result.intents.add(intent);
|
||||
} else if (parser.getName().equals("meta-data")) {
|
||||
if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
|
||||
result.metaData,
|
||||
outError)) == null) {
|
||||
if ((result.metaData = ParsingPackageUtils.parseMetaData(parsingPackage, res,
|
||||
parser, result.metaData, outError)) == null) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
@@ -2182,7 +2180,7 @@ public class ComponentParseUtils {
|
||||
outError[0] = "<provider> does not specify android:name";
|
||||
return null;
|
||||
} else {
|
||||
String className = ApkParseUtils.buildClassName(packageName, name);
|
||||
String className = ParsingUtils.buildClassName(packageName, name);
|
||||
if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
|
||||
outError[0] = "<provider> invalid android:name";
|
||||
return null;
|
||||
@@ -2413,7 +2411,7 @@ public class ComponentParseUtils {
|
||||
outInfo.intents.add(intent);
|
||||
|
||||
} else if (parser.getName().equals("meta-data")) {
|
||||
Bundle metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
|
||||
Bundle metaData = ParsingPackageUtils.parseMetaData(parsingPackage, res, parser,
|
||||
outInfo.metaData, outError);
|
||||
if (metaData == null) {
|
||||
return false;
|
||||
@@ -2607,7 +2605,7 @@ public class ComponentParseUtils {
|
||||
}
|
||||
|
||||
String packageName = parsingPackage.getPackageName();
|
||||
targetActivity = ApkParseUtils.buildClassName(packageName, targetActivity);
|
||||
targetActivity = ParsingUtils.buildClassName(packageName, targetActivity);
|
||||
if (targetActivity == null) {
|
||||
outError[0] = "Empty class name in package " + packageName;
|
||||
sa.recycle();
|
||||
@@ -2664,7 +2662,7 @@ public class ComponentParseUtils {
|
||||
result.requestedVrComponent = target.requestedVrComponent;
|
||||
result.directBootAware = target.directBootAware;
|
||||
|
||||
result.setProcessName(parsingPackage.getAppInfoProcessName(), target.getProcessName());
|
||||
result.setProcessName(parsingPackage.getProcessName(), target.getProcessName());
|
||||
|
||||
// Not all attributes from the target ParsedActivity are copied to the alias.
|
||||
// Careful when adding an attribute and determine whether or not it should be copied.
|
||||
@@ -2686,7 +2684,7 @@ public class ComponentParseUtils {
|
||||
outError[0] = "<activity-alias> does not specify android:name";
|
||||
return null;
|
||||
} else {
|
||||
String className = ApkParseUtils.buildClassName(packageName, name);
|
||||
String className = ParsingUtils.buildClassName(packageName, name);
|
||||
if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
|
||||
outError[0] = "<activity-alias> invalid android:name";
|
||||
return null;
|
||||
@@ -2751,7 +2749,7 @@ public class ComponentParseUtils {
|
||||
R.styleable.AndroidManifestActivityAlias_parentActivityName,
|
||||
Configuration.NATIVE_CONFIG_VERSION);
|
||||
if (parentName != null) {
|
||||
String parentClassName = ApkParseUtils.buildClassName(result.getPackageName(),
|
||||
String parentClassName = ParsingUtils.buildClassName(result.getPackageName(),
|
||||
parentName);
|
||||
if (parentClassName == null) {
|
||||
Log.e(TAG, "Activity alias " + result.className +
|
||||
@@ -2811,9 +2809,8 @@ public class ComponentParseUtils {
|
||||
result.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
|
||||
}
|
||||
} else if (tagName.equals("meta-data")) {
|
||||
if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
|
||||
result.metaData,
|
||||
outError)) == null) {
|
||||
if ((result.metaData = ParsingPackageUtils.parseMetaData(parsingPackage, res,
|
||||
parser, result.metaData, outError)) == null) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
@@ -2935,7 +2932,7 @@ public class ComponentParseUtils {
|
||||
outError[0] = "<permission> does not specify android:name";
|
||||
return null;
|
||||
} else {
|
||||
String className = ApkParseUtils.buildClassName(packageName, name);
|
||||
String className = ParsingUtils.buildClassName(packageName, name);
|
||||
if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
|
||||
outError[0] = "<permission> invalid android:name";
|
||||
return null;
|
||||
@@ -3073,7 +3070,7 @@ public class ComponentParseUtils {
|
||||
outError[0] = "<permission-tree> does not specify android:name";
|
||||
return null;
|
||||
} else {
|
||||
String className = ApkParseUtils.buildClassName(packageName, name);
|
||||
String className = ParsingUtils.buildClassName(packageName, name);
|
||||
if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
|
||||
outError[0] = "<permission-tree> invalid android:name";
|
||||
return null;
|
||||
@@ -3163,7 +3160,7 @@ public class ComponentParseUtils {
|
||||
outError[0] = "<permission> does not specify android:name";
|
||||
return null;
|
||||
} else {
|
||||
String className = ApkParseUtils.buildClassName(packageName, name);
|
||||
String className = ParsingUtils.buildClassName(packageName, name);
|
||||
if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
|
||||
outError[0] = "<permission> invalid android:name";
|
||||
return null;
|
||||
@@ -3262,7 +3259,7 @@ public class ComponentParseUtils {
|
||||
outError[0] = "<instrumentation> does not specify android:name";
|
||||
return null;
|
||||
} else {
|
||||
String className = ApkParseUtils.buildClassName(packageName, name);
|
||||
String className = ParsingUtils.buildClassName(packageName, name);
|
||||
if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
|
||||
outError[0] = "<instrumentation> invalid android:name";
|
||||
return null;
|
||||
@@ -3764,8 +3761,8 @@ public class ComponentParseUtils {
|
||||
}
|
||||
|
||||
if (parser.getName().equals("meta-data")) {
|
||||
if ((outInfo.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
|
||||
outInfo.metaData, outError)) == null) {
|
||||
if ((outInfo.metaData = ParsingPackageUtils.parseMetaData(parsingPackage, res,
|
||||
parser, outInfo.metaData, outError)) == null) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -1,595 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.content.pm.parsing;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.ComponentInfo;
|
||||
import android.content.pm.ConfigurationInfo;
|
||||
import android.content.pm.FallbackCategoryProvider;
|
||||
import android.content.pm.FeatureGroupInfo;
|
||||
import android.content.pm.FeatureInfo;
|
||||
import android.content.pm.InstrumentationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageItemInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageParser;
|
||||
import android.content.pm.PackageUserState;
|
||||
import android.content.pm.PermissionGroupInfo;
|
||||
import android.content.pm.PermissionInfo;
|
||||
import android.content.pm.ProcessInfo;
|
||||
import android.content.pm.ProviderInfo;
|
||||
import android.content.pm.SELinuxUtil;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.content.pm.Signature;
|
||||
import android.content.pm.SigningInfo;
|
||||
import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
|
||||
import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
|
||||
import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
|
||||
import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/** @hide */
|
||||
public class PackageInfoUtils {
|
||||
|
||||
private static final String TAG = ApkParseUtils.TAG;
|
||||
|
||||
/**
|
||||
* Returns true if the package is installed and not hidden, or if the caller
|
||||
* explicitly wanted all uninstalled and hidden packages as well.
|
||||
*/
|
||||
private static boolean checkUseInstalledOrHidden(AndroidPackage pkg, PackageUserState state,
|
||||
@PackageManager.PackageInfoFlags int flags) {
|
||||
// Returns false if the package is hidden system app until installed.
|
||||
if ((flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) == 0
|
||||
&& !state.installed
|
||||
&& pkg.isHiddenUntilInstalled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If available for the target user, or trying to match uninstalled packages and it's
|
||||
// a system app.
|
||||
return state.isAvailable(flags)
|
||||
|| (pkg.isSystemApp()
|
||||
&& ((flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0
|
||||
|| (flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) != 0));
|
||||
}
|
||||
|
||||
public static PackageInfo generate(AndroidPackage pkg, int[] gids,
|
||||
@PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
|
||||
Set<String> grantedPermissions, PackageUserState state, int userId) {
|
||||
if (!checkUseInstalledOrHidden(pkg, state, flags) || !pkg.isMatch(flags)) {
|
||||
return null;
|
||||
}
|
||||
ApplicationInfo applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
|
||||
|
||||
PackageInfo pi = new PackageInfo();
|
||||
pi.packageName = pkg.getPackageName();
|
||||
pi.splitNames = pkg.getSplitNames();
|
||||
pi.versionCode = pkg.getVersionCode();
|
||||
pi.versionCodeMajor = pkg.getVersionCodeMajor();
|
||||
pi.baseRevisionCode = pkg.getBaseRevisionCode();
|
||||
pi.splitRevisionCodes = pkg.getSplitRevisionCodes();
|
||||
pi.versionName = pkg.getVersionName();
|
||||
pi.sharedUserId = pkg.getSharedUserId();
|
||||
pi.sharedUserLabel = pkg.getSharedUserLabel();
|
||||
pi.applicationInfo = applicationInfo;
|
||||
pi.installLocation = pkg.getInstallLocation();
|
||||
pi.isStub = pkg.isStub();
|
||||
pi.coreApp = pkg.isCoreApp();
|
||||
if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
|
||||
|| (pi.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
|
||||
pi.requiredForAllUsers = pkg.isRequiredForAllUsers();
|
||||
}
|
||||
pi.restrictedAccountType = pkg.getRestrictedAccountType();
|
||||
pi.requiredAccountType = pkg.getRequiredAccountType();
|
||||
pi.overlayTarget = pkg.getOverlayTarget();
|
||||
pi.targetOverlayableName = pkg.getOverlayTargetName();
|
||||
pi.overlayCategory = pkg.getOverlayCategory();
|
||||
pi.overlayPriority = pkg.getOverlayPriority();
|
||||
pi.mOverlayIsStatic = pkg.isOverlayIsStatic();
|
||||
pi.compileSdkVersion = pkg.getCompileSdkVersion();
|
||||
pi.compileSdkVersionCodename = pkg.getCompileSdkVersionCodeName();
|
||||
pi.firstInstallTime = firstInstallTime;
|
||||
pi.lastUpdateTime = lastUpdateTime;
|
||||
if ((flags & PackageManager.GET_GIDS) != 0) {
|
||||
pi.gids = gids;
|
||||
}
|
||||
if ((flags & PackageManager.GET_CONFIGURATIONS) != 0) {
|
||||
int size = pkg.getConfigPreferences() != null ? pkg.getConfigPreferences().size() : 0;
|
||||
if (size > 0) {
|
||||
pi.configPreferences = new ConfigurationInfo[size];
|
||||
pkg.getConfigPreferences().toArray(pi.configPreferences);
|
||||
}
|
||||
size = pkg.getReqFeatures() != null ? pkg.getReqFeatures().size() : 0;
|
||||
if (size > 0) {
|
||||
pi.reqFeatures = new FeatureInfo[size];
|
||||
pkg.getReqFeatures().toArray(pi.reqFeatures);
|
||||
}
|
||||
size = pkg.getFeatureGroups() != null ? pkg.getFeatureGroups().size() : 0;
|
||||
if (size > 0) {
|
||||
pi.featureGroups = new FeatureGroupInfo[size];
|
||||
pkg.getFeatureGroups().toArray(pi.featureGroups);
|
||||
}
|
||||
}
|
||||
if ((flags & PackageManager.GET_ACTIVITIES) != 0) {
|
||||
if (pkg.getActivities() != null) {
|
||||
final int N = pkg.getActivities().size();
|
||||
if (N > 0) {
|
||||
int num = 0;
|
||||
final ActivityInfo[] res = new ActivityInfo[N];
|
||||
for (int i = 0; i < N; i++) {
|
||||
final ParsedActivity a = pkg.getActivities().get(i);
|
||||
if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), a, flags)) {
|
||||
if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(
|
||||
a.className)) {
|
||||
continue;
|
||||
}
|
||||
res[num++] = generateActivityInfo(pkg, a, flags, state, applicationInfo,
|
||||
userId);
|
||||
}
|
||||
}
|
||||
pi.activities = ArrayUtils.trimToSize(res, num);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((flags & PackageManager.GET_RECEIVERS) != 0) {
|
||||
if (pkg.getReceivers() != null) {
|
||||
final int size = pkg.getReceivers().size();
|
||||
if (size > 0) {
|
||||
int num = 0;
|
||||
final ActivityInfo[] res = new ActivityInfo[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
final ParsedActivity a = pkg.getReceivers().get(i);
|
||||
if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), a, flags)) {
|
||||
res[num++] = generateActivityInfo(pkg, a, flags, state, applicationInfo,
|
||||
userId);
|
||||
}
|
||||
}
|
||||
pi.receivers = ArrayUtils.trimToSize(res, num);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((flags & PackageManager.GET_SERVICES) != 0) {
|
||||
if (pkg.getServices() != null) {
|
||||
final int size = pkg.getServices().size();
|
||||
if (size > 0) {
|
||||
int num = 0;
|
||||
final ServiceInfo[] res = new ServiceInfo[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
final ComponentParseUtils.ParsedService s = pkg.getServices().get(i);
|
||||
if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), s, flags)) {
|
||||
res[num++] = generateServiceInfo(pkg, s, flags, state, applicationInfo,
|
||||
userId);
|
||||
}
|
||||
}
|
||||
pi.services = ArrayUtils.trimToSize(res, num);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((flags & PackageManager.GET_PROVIDERS) != 0) {
|
||||
if (pkg.getProviders() != null) {
|
||||
final int size = pkg.getProviders().size();
|
||||
if (size > 0) {
|
||||
int num = 0;
|
||||
final ProviderInfo[] res = new ProviderInfo[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
final ComponentParseUtils.ParsedProvider pr = pkg.getProviders()
|
||||
.get(i);
|
||||
if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), pr, flags)) {
|
||||
res[num++] = generateProviderInfo(pkg, pr, flags, state,
|
||||
applicationInfo, userId);
|
||||
}
|
||||
}
|
||||
pi.providers = ArrayUtils.trimToSize(res, num);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((flags & PackageManager.GET_INSTRUMENTATION) != 0) {
|
||||
if (pkg.getInstrumentations() != null) {
|
||||
int N = pkg.getInstrumentations().size();
|
||||
if (N > 0) {
|
||||
pi.instrumentation = new InstrumentationInfo[N];
|
||||
for (int i = 0; i < N; i++) {
|
||||
pi.instrumentation[i] = generateInstrumentationInfo(
|
||||
pkg.getInstrumentations().get(i), pkg, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((flags & PackageManager.GET_PERMISSIONS) != 0) {
|
||||
if (pkg.getPermissions() != null) {
|
||||
int N = ArrayUtils.size(pkg.getPermissions());
|
||||
if (N > 0) {
|
||||
pi.permissions = new PermissionInfo[N];
|
||||
for (int i = 0; i < N; i++) {
|
||||
pi.permissions[i] = generatePermissionInfo(
|
||||
pkg.getPermissions().get(i),
|
||||
flags
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pkg.getRequestedPermissions() != null) {
|
||||
int N = pkg.getRequestedPermissions().size();
|
||||
if (N > 0) {
|
||||
pi.requestedPermissions = new String[N];
|
||||
pi.requestedPermissionsFlags = new int[N];
|
||||
for (int i = 0; i < N; i++) {
|
||||
final String perm = pkg.getRequestedPermissions().get(i);
|
||||
pi.requestedPermissions[i] = perm;
|
||||
// The notion of required permissions is deprecated but for compatibility.
|
||||
pi.requestedPermissionsFlags[i] |=
|
||||
PackageInfo.REQUESTED_PERMISSION_REQUIRED;
|
||||
if (grantedPermissions != null && grantedPermissions.contains(perm)) {
|
||||
pi.requestedPermissionsFlags[i] |=
|
||||
PackageInfo.REQUESTED_PERMISSION_GRANTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PackageParser.SigningDetails signingDetails = pkg.getSigningDetails();
|
||||
// deprecated method of getting signing certificates
|
||||
if ((flags & PackageManager.GET_SIGNATURES) != 0) {
|
||||
if (signingDetails.hasPastSigningCertificates()) {
|
||||
// Package has included signing certificate rotation information. Return the oldest
|
||||
// cert so that programmatic checks keep working even if unaware of key rotation.
|
||||
pi.signatures = new Signature[1];
|
||||
pi.signatures[0] = signingDetails.pastSigningCertificates[0];
|
||||
} else if (signingDetails.hasSignatures()) {
|
||||
// otherwise keep old behavior
|
||||
int numberOfSigs = signingDetails.signatures.length;
|
||||
pi.signatures = new Signature[numberOfSigs];
|
||||
System.arraycopy(signingDetails.signatures, 0, pi.signatures, 0,
|
||||
numberOfSigs);
|
||||
}
|
||||
}
|
||||
|
||||
// replacement for GET_SIGNATURES
|
||||
if ((flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0) {
|
||||
if (signingDetails != PackageParser.SigningDetails.UNKNOWN) {
|
||||
// only return a valid SigningInfo if there is signing information to report
|
||||
pi.signingInfo = new SigningInfo(signingDetails);
|
||||
} else {
|
||||
pi.signingInfo = null;
|
||||
}
|
||||
}
|
||||
|
||||
return pi;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ApplicationInfo generateApplicationInfo(AndroidPackage pkg,
|
||||
@PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId) {
|
||||
|
||||
if (pkg == null) return null;
|
||||
if (!checkUseInstalledOrHidden(pkg, state, flags) || !pkg.isMatch(flags)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Make shallow copy so we can store the metadata/libraries safely
|
||||
ApplicationInfo ai = pkg.toAppInfoWithoutState();
|
||||
ai.initForUser(userId);
|
||||
if ((flags & PackageManager.GET_META_DATA) == 0) {
|
||||
ai.metaData = null;
|
||||
}
|
||||
if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) == 0) {
|
||||
ai.sharedLibraryFiles = null;
|
||||
ai.sharedLibraryInfos = null;
|
||||
}
|
||||
if (state.stopped) {
|
||||
ai.flags |= ApplicationInfo.FLAG_STOPPED;
|
||||
} else {
|
||||
ai.flags &= ~ApplicationInfo.FLAG_STOPPED;
|
||||
}
|
||||
updateApplicationInfo(ai, flags, state);
|
||||
|
||||
return ai;
|
||||
}
|
||||
|
||||
private static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a,
|
||||
@PackageManager.ComponentInfoFlags int flags, PackageUserState state,
|
||||
@Nullable ApplicationInfo applicationInfo, int userId) {
|
||||
if (a == null) return null;
|
||||
if (!checkUseInstalledOrHidden(pkg, state, flags)) {
|
||||
return null;
|
||||
}
|
||||
if (applicationInfo == null) {
|
||||
applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
|
||||
}
|
||||
// Make shallow copies so we can store the metadata safely
|
||||
ActivityInfo ai = new ActivityInfo();
|
||||
assignSharedFieldsForComponentInfo(ai, a);
|
||||
ai.targetActivity = a.targetActivity;
|
||||
ai.processName = a.getProcessName();
|
||||
ai.exported = a.exported;
|
||||
ai.theme = a.theme;
|
||||
ai.uiOptions = a.uiOptions;
|
||||
ai.parentActivityName = a.parentActivityName;
|
||||
ai.permission = a.getPermission();
|
||||
ai.taskAffinity = a.taskAffinity;
|
||||
ai.flags = a.flags;
|
||||
ai.privateFlags = a.privateFlags;
|
||||
ai.launchMode = a.launchMode;
|
||||
ai.documentLaunchMode = a.documentLaunchMode;
|
||||
ai.maxRecents = a.maxRecents;
|
||||
ai.configChanges = a.configChanges;
|
||||
ai.softInputMode = a.softInputMode;
|
||||
ai.persistableMode = a.persistableMode;
|
||||
ai.lockTaskLaunchMode = a.lockTaskLaunchMode;
|
||||
ai.screenOrientation = a.screenOrientation;
|
||||
ai.resizeMode = a.resizeMode;
|
||||
ai.maxAspectRatio = a.maxAspectRatio;
|
||||
ai.minAspectRatio = a.minAspectRatio;
|
||||
ai.requestedVrComponent = a.requestedVrComponent;
|
||||
ai.rotationAnimation = a.rotationAnimation;
|
||||
ai.colorMode = a.colorMode;
|
||||
ai.preferMinimalPostProcessing = a.preferMinimalPostProcessing;
|
||||
ai.windowLayout = a.windowLayout;
|
||||
ai.metaData = a.metaData;
|
||||
ai.applicationInfo = applicationInfo;
|
||||
return ai;
|
||||
}
|
||||
|
||||
public static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a,
|
||||
@PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) {
|
||||
return generateActivityInfo(pkg, a, flags, state, null, userId);
|
||||
}
|
||||
|
||||
private static ServiceInfo generateServiceInfo(AndroidPackage pkg,
|
||||
ComponentParseUtils.ParsedService s, @PackageManager.ComponentInfoFlags int flags,
|
||||
PackageUserState state, @Nullable ApplicationInfo applicationInfo, int userId) {
|
||||
if (s == null) return null;
|
||||
if (!checkUseInstalledOrHidden(pkg, state, flags)) {
|
||||
return null;
|
||||
}
|
||||
if (applicationInfo == null) {
|
||||
applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
|
||||
}
|
||||
// Make shallow copies so we can store the metadata safely
|
||||
ServiceInfo si = new ServiceInfo();
|
||||
assignSharedFieldsForComponentInfo(si, s);
|
||||
si.exported = s.exported;
|
||||
si.flags = s.flags;
|
||||
si.metaData = s.metaData;
|
||||
si.permission = s.getPermission();
|
||||
si.processName = s.getProcessName();
|
||||
si.mForegroundServiceType = s.foregroundServiceType;
|
||||
si.metaData = s.metaData;
|
||||
si.applicationInfo = applicationInfo;
|
||||
return si;
|
||||
}
|
||||
|
||||
public static ServiceInfo generateServiceInfo(AndroidPackage pkg,
|
||||
ComponentParseUtils.ParsedService s, @PackageManager.ComponentInfoFlags int flags,
|
||||
PackageUserState state, int userId) {
|
||||
return generateServiceInfo(pkg, s, flags, state, null, userId);
|
||||
}
|
||||
|
||||
private static ProviderInfo generateProviderInfo(AndroidPackage pkg,
|
||||
ComponentParseUtils.ParsedProvider p, @PackageManager.ComponentInfoFlags int flags,
|
||||
PackageUserState state, @Nullable ApplicationInfo applicationInfo, int userId) {
|
||||
if (p == null) return null;
|
||||
if (!checkUseInstalledOrHidden(pkg, state, flags)) {
|
||||
return null;
|
||||
}
|
||||
if (applicationInfo == null) {
|
||||
applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
|
||||
}
|
||||
// Make shallow copies so we can store the metadata safely
|
||||
ProviderInfo pi = new ProviderInfo();
|
||||
assignSharedFieldsForComponentInfo(pi, p);
|
||||
pi.exported = p.exported;
|
||||
pi.flags = p.flags;
|
||||
pi.processName = p.getProcessName();
|
||||
pi.authority = p.getAuthority();
|
||||
pi.isSyncable = p.isSyncable;
|
||||
pi.readPermission = p.getReadPermission();
|
||||
pi.writePermission = p.getWritePermission();
|
||||
pi.grantUriPermissions = p.grantUriPermissions;
|
||||
pi.forceUriPermissions = p.forceUriPermissions;
|
||||
pi.multiprocess = p.multiProcess;
|
||||
pi.initOrder = p.initOrder;
|
||||
pi.uriPermissionPatterns = p.uriPermissionPatterns;
|
||||
pi.pathPermissions = p.pathPermissions;
|
||||
pi.metaData = p.metaData;
|
||||
if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) {
|
||||
pi.uriPermissionPatterns = null;
|
||||
}
|
||||
pi.applicationInfo = applicationInfo;
|
||||
return pi;
|
||||
}
|
||||
|
||||
public static ProviderInfo generateProviderInfo(AndroidPackage pkg,
|
||||
ComponentParseUtils.ParsedProvider p, @PackageManager.ComponentInfoFlags int flags,
|
||||
PackageUserState state, int userId) {
|
||||
return generateProviderInfo(pkg, p, flags, state, null, userId);
|
||||
}
|
||||
|
||||
public static InstrumentationInfo generateInstrumentationInfo(ParsedInstrumentation i,
|
||||
AndroidPackage pkg, @PackageManager.ComponentInfoFlags int flags) {
|
||||
if (i == null) return null;
|
||||
|
||||
InstrumentationInfo ii = new InstrumentationInfo();
|
||||
assignSharedFieldsForPackageItemInfo(ii, i);
|
||||
ii.targetPackage = i.getTargetPackage();
|
||||
ii.targetProcesses = i.getTargetProcesses();
|
||||
ii.handleProfiling = i.handleProfiling;
|
||||
ii.functionalTest = i.functionalTest;
|
||||
|
||||
ii.sourceDir = pkg.getBaseCodePath();
|
||||
ii.publicSourceDir = pkg.getBaseCodePath();
|
||||
ii.splitNames = pkg.getSplitNames();
|
||||
ii.splitSourceDirs = pkg.getSplitCodePaths();
|
||||
ii.splitPublicSourceDirs = pkg.getSplitCodePaths();
|
||||
ii.splitDependencies = pkg.getSplitDependencies();
|
||||
ii.dataDir = pkg.getDataDir();
|
||||
ii.deviceProtectedDataDir = pkg.getDeviceProtectedDataDir();
|
||||
ii.credentialProtectedDataDir = pkg.getCredentialProtectedDataDir();
|
||||
ii.primaryCpuAbi = pkg.getPrimaryCpuAbi();
|
||||
ii.secondaryCpuAbi = pkg.getSecondaryCpuAbi();
|
||||
ii.nativeLibraryDir = pkg.getNativeLibraryDir();
|
||||
ii.secondaryNativeLibraryDir = pkg.getSecondaryNativeLibraryDir();
|
||||
|
||||
if ((flags & PackageManager.GET_META_DATA) == 0) {
|
||||
return ii;
|
||||
}
|
||||
ii.metaData = i.metaData;
|
||||
return ii;
|
||||
}
|
||||
|
||||
public static ArrayMap<String, ProcessInfo> generateProcessInfo(
|
||||
ArrayMap<String, ComponentParseUtils.ParsedProcess> procs,
|
||||
@PackageManager.ComponentInfoFlags int flags) {
|
||||
if (procs == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final int numProcs = procs.size();
|
||||
ArrayMap<String, ProcessInfo> retProcs = new ArrayMap(numProcs);
|
||||
for (int i = 0; i < numProcs; i++) {
|
||||
ComponentParseUtils.ParsedProcess proc = procs.valueAt(i);
|
||||
retProcs.put(proc.name, new ProcessInfo(proc.name,
|
||||
proc.deniedPermissions != null
|
||||
? new ArraySet<>(proc.deniedPermissions) : null));
|
||||
}
|
||||
return retProcs;
|
||||
}
|
||||
|
||||
public static PermissionInfo generatePermissionInfo(ParsedPermission p,
|
||||
@PackageManager.ComponentInfoFlags int flags) {
|
||||
if (p == null) return null;
|
||||
|
||||
PermissionInfo pi = new PermissionInfo(p.backgroundPermission);
|
||||
assignSharedFieldsForPackageItemInfo(pi, p);
|
||||
pi.group = p.getGroup();
|
||||
pi.requestRes = p.requestRes;
|
||||
pi.protectionLevel = p.protectionLevel;
|
||||
pi.descriptionRes = p.descriptionRes;
|
||||
pi.flags = p.flags;
|
||||
|
||||
if ((flags & PackageManager.GET_META_DATA) == 0) {
|
||||
return pi;
|
||||
}
|
||||
pi.metaData = p.metaData;
|
||||
return pi;
|
||||
}
|
||||
|
||||
public static PermissionGroupInfo generatePermissionGroupInfo(ParsedPermissionGroup pg,
|
||||
@PackageManager.ComponentInfoFlags int flags) {
|
||||
if (pg == null) return null;
|
||||
|
||||
PermissionGroupInfo pgi = new PermissionGroupInfo(
|
||||
pg.requestDetailResourceId,
|
||||
pg.backgroundRequestResourceId,
|
||||
pg.backgroundRequestDetailResourceId
|
||||
);
|
||||
assignSharedFieldsForPackageItemInfo(pgi, pg);
|
||||
pgi.descriptionRes = pg.descriptionRes;
|
||||
pgi.priority = pg.priority;
|
||||
pgi.requestRes = pg.requestRes;
|
||||
pgi.flags = pg.flags;
|
||||
|
||||
if ((flags & PackageManager.GET_META_DATA) == 0) {
|
||||
return pgi;
|
||||
}
|
||||
pgi.metaData = pg.metaData;
|
||||
return pgi;
|
||||
}
|
||||
|
||||
private static void updateApplicationInfo(ApplicationInfo ai,
|
||||
@PackageManager.ApplicationInfoFlags int flags,
|
||||
PackageUserState state) {
|
||||
// CompatibilityMode is global state.
|
||||
if (!PackageParser.sCompatibilityModeEnabled) {
|
||||
ai.disableCompatibilityMode();
|
||||
}
|
||||
if (state.installed) {
|
||||
ai.flags |= ApplicationInfo.FLAG_INSTALLED;
|
||||
} else {
|
||||
ai.flags &= ~ApplicationInfo.FLAG_INSTALLED;
|
||||
}
|
||||
if (state.suspended) {
|
||||
ai.flags |= ApplicationInfo.FLAG_SUSPENDED;
|
||||
} else {
|
||||
ai.flags &= ~ApplicationInfo.FLAG_SUSPENDED;
|
||||
}
|
||||
if (state.instantApp) {
|
||||
ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_INSTANT;
|
||||
} else {
|
||||
ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_INSTANT;
|
||||
}
|
||||
if (state.virtualPreload) {
|
||||
ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD;
|
||||
} else {
|
||||
ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD;
|
||||
}
|
||||
if (state.hidden) {
|
||||
ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
|
||||
} else {
|
||||
ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN;
|
||||
}
|
||||
if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
|
||||
ai.enabled = true;
|
||||
} else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
|
||||
ai.enabled = (flags & PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0;
|
||||
} else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
|
||||
|| state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
|
||||
ai.enabled = false;
|
||||
}
|
||||
ai.enabledSetting = state.enabled;
|
||||
if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
|
||||
ai.category = state.categoryHint;
|
||||
}
|
||||
if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
|
||||
ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName);
|
||||
}
|
||||
ai.seInfoUser = SELinuxUtil.assignSeinfoUser(state);
|
||||
ai.resourceDirs = state.getAllOverlayPaths();
|
||||
ai.icon = (PackageParser.sUseRoundIcon && ai.roundIconRes != 0)
|
||||
? ai.roundIconRes : ai.iconRes;
|
||||
}
|
||||
|
||||
private static void assignSharedFieldsForPackageItemInfo(PackageItemInfo packageItemInfo,
|
||||
ComponentParseUtils.ParsedComponent parsedComponent) {
|
||||
packageItemInfo.banner = parsedComponent.banner;
|
||||
packageItemInfo.icon = parsedComponent.icon;
|
||||
packageItemInfo.labelRes = parsedComponent.labelRes;
|
||||
packageItemInfo.logo = parsedComponent.logo;
|
||||
packageItemInfo.name = parsedComponent.className;
|
||||
packageItemInfo.nonLocalizedLabel = parsedComponent.nonLocalizedLabel;
|
||||
packageItemInfo.packageName = parsedComponent.getPackageName();
|
||||
}
|
||||
|
||||
private static void assignSharedFieldsForComponentInfo(ComponentInfo componentInfo,
|
||||
ComponentParseUtils.ParsedComponent parsedComponent) {
|
||||
assignSharedFieldsForPackageItemInfo(componentInfo, parsedComponent);
|
||||
componentInfo.descriptionRes = parsedComponent.descriptionRes;
|
||||
componentInfo.directBootAware = parsedComponent.directBootAware;
|
||||
componentInfo.enabled = parsedComponent.enabled;
|
||||
componentInfo.splitName = parsedComponent.getSplitName();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,691 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.content.pm.parsing;
|
||||
|
||||
import android.annotation.CheckResult;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.apex.ApexInfo;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.ComponentInfo;
|
||||
import android.content.pm.ConfigurationInfo;
|
||||
import android.content.pm.FallbackCategoryProvider;
|
||||
import android.content.pm.FeatureGroupInfo;
|
||||
import android.content.pm.FeatureInfo;
|
||||
import android.content.pm.InstrumentationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageItemInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageParser;
|
||||
import android.content.pm.PackageUserState;
|
||||
import android.content.pm.PermissionGroupInfo;
|
||||
import android.content.pm.PermissionInfo;
|
||||
import android.content.pm.ProviderInfo;
|
||||
import android.content.pm.SELinuxUtil;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.content.pm.Signature;
|
||||
import android.content.pm.SigningInfo;
|
||||
import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
|
||||
import android.content.pm.parsing.ComponentParseUtils.ParsedComponent;
|
||||
import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
|
||||
import android.content.pm.parsing.ComponentParseUtils.ParsedMainComponent;
|
||||
import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
|
||||
import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
|
||||
import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
|
||||
import android.content.pm.parsing.ComponentParseUtils.ParsedService;
|
||||
import android.os.Environment;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
|
||||
import libcore.util.EmptyArray;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
/** @hide **/
|
||||
public class PackageInfoWithoutStateUtils {
|
||||
|
||||
@Nullable
|
||||
public static PackageInfo generate(ParsingPackageRead pkg, int[] gids,
|
||||
@PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
|
||||
Set<String> grantedPermissions, PackageUserState state, int userId) {
|
||||
return generateWithComponents(pkg, gids, flags, firstInstallTime, lastUpdateTime, grantedPermissions,
|
||||
state, userId, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PackageInfo generate(ParsingPackageRead pkg, ApexInfo apexInfo, int flags) {
|
||||
return generateWithComponents(pkg, EmptyArray.INT, flags, 0, 0, Collections.emptySet(),
|
||||
new PackageUserState(), UserHandle.getCallingUserId(), apexInfo);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PackageInfo generateWithComponents(ParsingPackageRead pkg, int[] gids,
|
||||
@PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
|
||||
Set<String> grantedPermissions, PackageUserState state, int userId,
|
||||
@Nullable ApexInfo apexInfo) {
|
||||
ApplicationInfo applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
|
||||
if (applicationInfo == null) {
|
||||
return null;
|
||||
}
|
||||
PackageInfo info = generateWithoutComponents(pkg, gids, flags, firstInstallTime,
|
||||
lastUpdateTime, grantedPermissions, state, userId, apexInfo, applicationInfo);
|
||||
|
||||
if (info == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ((flags & PackageManager.GET_ACTIVITIES) != 0) {
|
||||
final int N = pkg.getActivities().size();
|
||||
if (N > 0) {
|
||||
int num = 0;
|
||||
final ActivityInfo[] res = new ActivityInfo[N];
|
||||
for (int i = 0; i < N; i++) {
|
||||
final ParsedActivity a = pkg.getActivities().get(i);
|
||||
if (state.isMatch(false, pkg.isEnabled(), a, flags)) {
|
||||
if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(
|
||||
a.getName())) {
|
||||
continue;
|
||||
}
|
||||
res[num++] = generateActivityInfo(pkg, a, flags, state,
|
||||
applicationInfo, userId);
|
||||
}
|
||||
}
|
||||
info.activities = ArrayUtils.trimToSize(res, num);
|
||||
}
|
||||
}
|
||||
if ((flags & PackageManager.GET_RECEIVERS) != 0) {
|
||||
final int size = pkg.getReceivers().size();
|
||||
if (size > 0) {
|
||||
int num = 0;
|
||||
final ActivityInfo[] res = new ActivityInfo[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
final ParsedActivity a = pkg.getReceivers().get(i);
|
||||
if (state.isMatch(false, pkg.isEnabled(), a, flags)) {
|
||||
res[num++] = generateActivityInfo(pkg, a, flags, state,
|
||||
applicationInfo, userId);
|
||||
}
|
||||
}
|
||||
info.receivers = ArrayUtils.trimToSize(res, num);
|
||||
}
|
||||
}
|
||||
if ((flags & PackageManager.GET_SERVICES) != 0) {
|
||||
final int size = pkg.getServices().size();
|
||||
if (size > 0) {
|
||||
int num = 0;
|
||||
final ServiceInfo[] res = new ServiceInfo[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
final ParsedService s = pkg.getServices().get(i);
|
||||
if (state.isMatch(false, pkg.isEnabled(), s, flags)) {
|
||||
res[num++] = generateServiceInfo(pkg, s, flags, state,
|
||||
applicationInfo, userId);
|
||||
}
|
||||
}
|
||||
info.services = ArrayUtils.trimToSize(res, num);
|
||||
}
|
||||
}
|
||||
if ((flags & PackageManager.GET_PROVIDERS) != 0) {
|
||||
final int size = pkg.getProviders().size();
|
||||
if (size > 0) {
|
||||
int num = 0;
|
||||
final ProviderInfo[] res = new ProviderInfo[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
final ParsedProvider pr = pkg.getProviders()
|
||||
.get(i);
|
||||
if (state.isMatch(false, pkg.isEnabled(), pr, flags)) {
|
||||
res[num++] = generateProviderInfo(pkg, pr, flags, state,
|
||||
applicationInfo, userId);
|
||||
}
|
||||
}
|
||||
info.providers = ArrayUtils.trimToSize(res, num);
|
||||
}
|
||||
}
|
||||
if ((flags & PackageManager.GET_INSTRUMENTATION) != 0) {
|
||||
int N = pkg.getInstrumentations().size();
|
||||
if (N > 0) {
|
||||
info.instrumentation = new InstrumentationInfo[N];
|
||||
for (int i = 0; i < N; i++) {
|
||||
info.instrumentation[i] = generateInstrumentationInfo(
|
||||
pkg.getInstrumentations().get(i), pkg, flags, userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PackageInfo generateWithoutComponents(ParsingPackageRead pkg, int[] gids,
|
||||
@PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
|
||||
Set<String> grantedPermissions, PackageUserState state, int userId,
|
||||
@Nullable ApexInfo apexInfo, @NonNull ApplicationInfo applicationInfo) {
|
||||
if (!checkUseInstalled(pkg, state, flags)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PackageInfo pi = new PackageInfo();
|
||||
pi.packageName = pkg.getPackageName();
|
||||
pi.splitNames = pkg.getSplitNames();
|
||||
pi.versionCode = pkg.getVersionCode();
|
||||
pi.versionCodeMajor = pkg.getVersionCodeMajor();
|
||||
pi.baseRevisionCode = pkg.getBaseRevisionCode();
|
||||
pi.splitRevisionCodes = pkg.getSplitRevisionCodes();
|
||||
pi.versionName = pkg.getVersionName();
|
||||
pi.sharedUserId = pkg.getSharedUserId();
|
||||
pi.sharedUserLabel = pkg.getSharedUserLabel();
|
||||
pi.applicationInfo = applicationInfo;
|
||||
pi.installLocation = pkg.getInstallLocation();
|
||||
if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
|
||||
|| (pi.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
|
||||
pi.requiredForAllUsers = pkg.isRequiredForAllUsers();
|
||||
}
|
||||
pi.restrictedAccountType = pkg.getRestrictedAccountType();
|
||||
pi.requiredAccountType = pkg.getRequiredAccountType();
|
||||
pi.overlayTarget = pkg.getOverlayTarget();
|
||||
pi.targetOverlayableName = pkg.getOverlayTargetName();
|
||||
pi.overlayCategory = pkg.getOverlayCategory();
|
||||
pi.overlayPriority = pkg.getOverlayPriority();
|
||||
pi.mOverlayIsStatic = pkg.isOverlayIsStatic();
|
||||
pi.compileSdkVersion = pkg.getCompileSdkVersion();
|
||||
pi.compileSdkVersionCodename = pkg.getCompileSdkVersionCodeName();
|
||||
pi.firstInstallTime = firstInstallTime;
|
||||
pi.lastUpdateTime = lastUpdateTime;
|
||||
if ((flags & PackageManager.GET_GIDS) != 0) {
|
||||
pi.gids = gids;
|
||||
}
|
||||
if ((flags & PackageManager.GET_CONFIGURATIONS) != 0) {
|
||||
int size = pkg.getConfigPreferences().size();
|
||||
if (size > 0) {
|
||||
pi.configPreferences = new ConfigurationInfo[size];
|
||||
pkg.getConfigPreferences().toArray(pi.configPreferences);
|
||||
}
|
||||
size = pkg.getReqFeatures().size();
|
||||
if (size > 0) {
|
||||
pi.reqFeatures = new FeatureInfo[size];
|
||||
pkg.getReqFeatures().toArray(pi.reqFeatures);
|
||||
}
|
||||
size = pkg.getFeatureGroups().size();
|
||||
if (size > 0) {
|
||||
pi.featureGroups = new FeatureGroupInfo[size];
|
||||
pkg.getFeatureGroups().toArray(pi.featureGroups);
|
||||
}
|
||||
}
|
||||
if ((flags & PackageManager.GET_PERMISSIONS) != 0) {
|
||||
int size = ArrayUtils.size(pkg.getPermissions());
|
||||
if (size > 0) {
|
||||
pi.permissions = new PermissionInfo[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
pi.permissions[i] = generatePermissionInfo(pkg.getPermissions().get(i),
|
||||
flags);
|
||||
}
|
||||
}
|
||||
size = pkg.getRequestedPermissions().size();
|
||||
if (size > 0) {
|
||||
pi.requestedPermissions = new String[size];
|
||||
pi.requestedPermissionsFlags = new int[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
final String perm = pkg.getRequestedPermissions().get(i);
|
||||
pi.requestedPermissions[i] = perm;
|
||||
// The notion of required permissions is deprecated but for compatibility.
|
||||
pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_REQUIRED;
|
||||
if (grantedPermissions != null && grantedPermissions.contains(perm)) {
|
||||
pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_GRANTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (apexInfo != null) {
|
||||
File apexFile = new File(apexInfo.modulePath);
|
||||
|
||||
pi.applicationInfo.sourceDir = apexFile.getPath();
|
||||
pi.applicationInfo.publicSourceDir = apexFile.getPath();
|
||||
if (apexInfo.isFactory) {
|
||||
pi.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
|
||||
} else {
|
||||
pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;
|
||||
}
|
||||
if (apexInfo.isActive) {
|
||||
pi.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
|
||||
} else {
|
||||
pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
|
||||
}
|
||||
pi.isApex = true;
|
||||
}
|
||||
|
||||
PackageParser.SigningDetails signingDetails = pkg.getSigningDetails();
|
||||
// deprecated method of getting signing certificates
|
||||
if ((flags & PackageManager.GET_SIGNATURES) != 0) {
|
||||
if (signingDetails.hasPastSigningCertificates()) {
|
||||
// Package has included signing certificate rotation information. Return the oldest
|
||||
// cert so that programmatic checks keep working even if unaware of key rotation.
|
||||
pi.signatures = new Signature[1];
|
||||
pi.signatures[0] = signingDetails.pastSigningCertificates[0];
|
||||
} else if (signingDetails.hasSignatures()) {
|
||||
// otherwise keep old behavior
|
||||
int numberOfSigs = signingDetails.signatures.length;
|
||||
pi.signatures = new Signature[numberOfSigs];
|
||||
System.arraycopy(signingDetails.signatures, 0, pi.signatures, 0,
|
||||
numberOfSigs);
|
||||
}
|
||||
}
|
||||
|
||||
// replacement for GET_SIGNATURES
|
||||
if ((flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0) {
|
||||
if (signingDetails != PackageParser.SigningDetails.UNKNOWN) {
|
||||
// only return a valid SigningInfo if there is signing information to report
|
||||
pi.signingInfo = new SigningInfo(signingDetails);
|
||||
} else {
|
||||
pi.signingInfo = null;
|
||||
}
|
||||
}
|
||||
|
||||
return pi;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ApplicationInfo generateApplicationInfo(ParsingPackageRead pkg,
|
||||
@PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId) {
|
||||
if (pkg == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!checkUseInstalled(pkg, state, flags)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Make shallow copy so we can store the metadata/libraries safely
|
||||
ApplicationInfo ai = pkg.toAppInfoWithoutState();
|
||||
// Init handles data directories
|
||||
// TODO(b/135203078): Consolidate the data directory logic, remove initForUser
|
||||
ai.initForUser(userId);
|
||||
|
||||
ai.flags = appInfoFlags(pkg);
|
||||
ai.privateFlags = appInfoPrivateFlags(pkg);
|
||||
|
||||
if ((flags & PackageManager.GET_META_DATA) == 0) {
|
||||
ai.metaData = null;
|
||||
}
|
||||
if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) == 0) {
|
||||
ai.sharedLibraryFiles = null;
|
||||
ai.sharedLibraryInfos = null;
|
||||
}
|
||||
|
||||
// CompatibilityMode is global state.
|
||||
if (!PackageParser.sCompatibilityModeEnabled) {
|
||||
ai.disableCompatibilityMode();
|
||||
}
|
||||
|
||||
ai.flags |= flag(state.stopped, ApplicationInfo.FLAG_STOPPED)
|
||||
| flag(state.installed, ApplicationInfo.FLAG_INSTALLED)
|
||||
| flag(state.suspended, ApplicationInfo.FLAG_SUSPENDED);
|
||||
ai.privateFlags |= flag(state.instantApp, ApplicationInfo.PRIVATE_FLAG_INSTANT)
|
||||
| flag(state.virtualPreload, ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD)
|
||||
| flag(state.hidden, ApplicationInfo.PRIVATE_FLAG_HIDDEN);
|
||||
|
||||
if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
|
||||
ai.enabled = true;
|
||||
} else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
|
||||
ai.enabled = (flags & PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0;
|
||||
} else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
|
||||
|| state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
|
||||
ai.enabled = false;
|
||||
}
|
||||
ai.enabledSetting = state.enabled;
|
||||
if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
|
||||
ai.category = state.categoryHint;
|
||||
}
|
||||
if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
|
||||
ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName);
|
||||
}
|
||||
ai.seInfoUser = SELinuxUtil.assignSeinfoUser(state);
|
||||
ai.resourceDirs = state.getOverlayPaths();
|
||||
|
||||
return ai;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ActivityInfo generateActivityInfo(ParsingPackageRead pkg, ParsedActivity a,
|
||||
@PackageManager.ComponentInfoFlags int flags, PackageUserState state,
|
||||
@Nullable ApplicationInfo applicationInfo, int userId) {
|
||||
if (a == null) return null;
|
||||
if (!checkUseInstalled(pkg, state, flags)) {
|
||||
return null;
|
||||
}
|
||||
if (applicationInfo == null) {
|
||||
applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
|
||||
}
|
||||
// Make shallow copies so we can store the metadata safely
|
||||
ActivityInfo ai = new ActivityInfo();
|
||||
assignSharedFieldsForComponentInfo(ai, a);
|
||||
ai.targetActivity = a.targetActivity;
|
||||
ai.processName = a.getProcessName();
|
||||
ai.exported = a.exported;
|
||||
ai.theme = a.theme;
|
||||
ai.uiOptions = a.uiOptions;
|
||||
ai.parentActivityName = a.parentActivityName;
|
||||
ai.permission = a.getPermission();
|
||||
ai.taskAffinity = a.taskAffinity;
|
||||
ai.flags = a.flags;
|
||||
ai.privateFlags = a.privateFlags;
|
||||
ai.launchMode = a.launchMode;
|
||||
ai.documentLaunchMode = a.documentLaunchMode;
|
||||
ai.maxRecents = a.maxRecents;
|
||||
ai.configChanges = a.configChanges;
|
||||
ai.softInputMode = a.softInputMode;
|
||||
ai.persistableMode = a.persistableMode;
|
||||
ai.lockTaskLaunchMode = a.lockTaskLaunchMode;
|
||||
ai.screenOrientation = a.screenOrientation;
|
||||
ai.resizeMode = a.resizeMode;
|
||||
ai.maxAspectRatio = a.maxAspectRatio;
|
||||
ai.minAspectRatio = a.minAspectRatio;
|
||||
ai.requestedVrComponent = a.requestedVrComponent;
|
||||
ai.rotationAnimation = a.rotationAnimation;
|
||||
ai.colorMode = a.colorMode;
|
||||
ai.preferMinimalPostProcessing = a.preferMinimalPostProcessing;
|
||||
ai.windowLayout = a.windowLayout;
|
||||
ai.metaData = a.getMetaData();
|
||||
ai.applicationInfo = applicationInfo;
|
||||
return ai;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ActivityInfo generateActivityInfo(ParsingPackageRead pkg, ParsedActivity a,
|
||||
@PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) {
|
||||
return generateActivityInfo(pkg, a, flags, state, null, userId);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ServiceInfo generateServiceInfo(ParsingPackageRead pkg, ParsedService s,
|
||||
@PackageManager.ComponentInfoFlags int flags, PackageUserState state,
|
||||
@Nullable ApplicationInfo applicationInfo, int userId) {
|
||||
if (s == null) return null;
|
||||
if (!checkUseInstalled(pkg, state, flags)) {
|
||||
return null;
|
||||
}
|
||||
if (applicationInfo == null) {
|
||||
applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
|
||||
}
|
||||
// Make shallow copies so we can store the metadata safely
|
||||
ServiceInfo si = new ServiceInfo();
|
||||
assignSharedFieldsForComponentInfo(si, s);
|
||||
si.exported = s.exported;
|
||||
si.flags = s.flags;
|
||||
si.metaData = s.getMetaData();
|
||||
si.permission = s.getPermission();
|
||||
si.processName = s.getProcessName();
|
||||
si.mForegroundServiceType = s.foregroundServiceType;
|
||||
si.applicationInfo = applicationInfo;
|
||||
return si;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ServiceInfo generateServiceInfo(ParsingPackageRead pkg, ParsedService s,
|
||||
@PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) {
|
||||
return generateServiceInfo(pkg, s, flags, state, null, userId);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ProviderInfo generateProviderInfo(ParsingPackageRead pkg, ParsedProvider p,
|
||||
@PackageManager.ComponentInfoFlags int flags, PackageUserState state,
|
||||
@Nullable ApplicationInfo applicationInfo, int userId) {
|
||||
if (p == null) return null;
|
||||
if (!checkUseInstalled(pkg, state, flags)) {
|
||||
return null;
|
||||
}
|
||||
if (applicationInfo == null) {
|
||||
applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
|
||||
}
|
||||
// Make shallow copies so we can store the metadata safely
|
||||
ProviderInfo pi = new ProviderInfo();
|
||||
assignSharedFieldsForComponentInfo(pi, p);
|
||||
pi.exported = p.isExported();
|
||||
pi.flags = p.getFlags();
|
||||
pi.processName = p.getProcessName();
|
||||
pi.authority = p.getAuthority();
|
||||
pi.isSyncable = p.isSyncable();
|
||||
pi.readPermission = p.getReadPermission();
|
||||
pi.writePermission = p.getWritePermission();
|
||||
pi.grantUriPermissions = p.isGrantUriPermissions();
|
||||
pi.forceUriPermissions = p.isForceUriPermissions();
|
||||
pi.multiprocess = p.isMultiProcess();
|
||||
pi.initOrder = p.getInitOrder();
|
||||
pi.uriPermissionPatterns = p.getUriPermissionPatterns();
|
||||
pi.pathPermissions = p.getPathPermissions();
|
||||
pi.metaData = p.getMetaData();
|
||||
if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) {
|
||||
pi.uriPermissionPatterns = null;
|
||||
}
|
||||
pi.applicationInfo = applicationInfo;
|
||||
return pi;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ProviderInfo generateProviderInfo(ParsingPackageRead pkg, ParsedProvider p,
|
||||
@PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) {
|
||||
return generateProviderInfo(pkg, p, flags, state, null, userId);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static InstrumentationInfo generateInstrumentationInfo(ParsedInstrumentation i,
|
||||
ParsingPackageRead pkg, @PackageManager.ComponentInfoFlags int flags, int userId) {
|
||||
if (i == null) return null;
|
||||
|
||||
InstrumentationInfo ii = new InstrumentationInfo();
|
||||
assignSharedFieldsForPackageItemInfo(ii, i);
|
||||
ii.targetPackage = i.getTargetPackage();
|
||||
ii.targetProcesses = i.getTargetProcesses();
|
||||
ii.handleProfiling = i.handleProfiling;
|
||||
ii.functionalTest = i.functionalTest;
|
||||
|
||||
ii.sourceDir = pkg.getBaseCodePath();
|
||||
ii.publicSourceDir = pkg.getBaseCodePath();
|
||||
ii.splitNames = pkg.getSplitNames();
|
||||
ii.splitSourceDirs = pkg.getSplitCodePaths();
|
||||
ii.splitPublicSourceDirs = pkg.getSplitCodePaths();
|
||||
ii.splitDependencies = pkg.getSplitDependencies();
|
||||
ii.dataDir = getDataDir(pkg, UserHandle.myUserId()).getAbsolutePath();
|
||||
ii.deviceProtectedDataDir = getDeviceProtectedDataDir(pkg, userId)
|
||||
.getAbsolutePath();
|
||||
ii.credentialProtectedDataDir = getCredentialProtectedDataDir(pkg,
|
||||
userId).getAbsolutePath();
|
||||
|
||||
if ((flags & PackageManager.GET_META_DATA) == 0) {
|
||||
return ii;
|
||||
}
|
||||
ii.metaData = i.getMetaData();
|
||||
return ii;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PermissionInfo generatePermissionInfo(ParsedPermission p,
|
||||
@PackageManager.ComponentInfoFlags int flags) {
|
||||
if (p == null) return null;
|
||||
|
||||
PermissionInfo pi = new PermissionInfo(p.backgroundPermission);
|
||||
|
||||
assignSharedFieldsForPackageItemInfo(pi, p);
|
||||
|
||||
pi.group = p.getGroup();
|
||||
pi.requestRes = p.requestRes;
|
||||
pi.protectionLevel = p.protectionLevel;
|
||||
pi.descriptionRes = p.descriptionRes;
|
||||
pi.flags = p.flags;
|
||||
|
||||
if ((flags & PackageManager.GET_META_DATA) == 0) {
|
||||
return pi;
|
||||
}
|
||||
pi.metaData = p.getMetaData();
|
||||
return pi;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PermissionGroupInfo generatePermissionGroupInfo(ParsedPermissionGroup pg,
|
||||
@PackageManager.ComponentInfoFlags int flags) {
|
||||
if (pg == null) return null;
|
||||
|
||||
PermissionGroupInfo pgi = new PermissionGroupInfo(
|
||||
pg.requestDetailResourceId,
|
||||
pg.backgroundRequestResourceId,
|
||||
pg.backgroundRequestDetailResourceId
|
||||
);
|
||||
|
||||
assignSharedFieldsForPackageItemInfo(pgi, pg);
|
||||
pgi.descriptionRes = pg.descriptionRes;
|
||||
pgi.priority = pg.priority;
|
||||
pgi.requestRes = pg.requestRes;
|
||||
pgi.flags = pg.flags;
|
||||
|
||||
if ((flags & PackageManager.GET_META_DATA) == 0) {
|
||||
return pgi;
|
||||
}
|
||||
pgi.metaData = pg.getMetaData();
|
||||
return pgi;
|
||||
}
|
||||
|
||||
private static void assignSharedFieldsForComponentInfo(@NonNull ComponentInfo componentInfo,
|
||||
@NonNull ParsedMainComponent mainComponent) {
|
||||
assignSharedFieldsForPackageItemInfo(componentInfo, mainComponent);
|
||||
componentInfo.descriptionRes = mainComponent.descriptionRes;
|
||||
componentInfo.directBootAware = mainComponent.isDirectBootAware();
|
||||
componentInfo.enabled = mainComponent.isEnabled();
|
||||
componentInfo.splitName = mainComponent.getSplitName();
|
||||
}
|
||||
|
||||
private static void assignSharedFieldsForPackageItemInfo(
|
||||
@NonNull PackageItemInfo packageItemInfo, @NonNull ParsedComponent component) {
|
||||
packageItemInfo.nonLocalizedLabel = component.nonLocalizedLabel;
|
||||
packageItemInfo.icon = component.icon;
|
||||
|
||||
packageItemInfo.banner = component.banner;
|
||||
packageItemInfo.labelRes = component.labelRes;
|
||||
packageItemInfo.logo = component.logo;
|
||||
packageItemInfo.name = component.getName();
|
||||
packageItemInfo.packageName = component.getPackageName();
|
||||
}
|
||||
|
||||
@CheckResult
|
||||
private static int flag(boolean hasFlag, int flag) {
|
||||
if (hasFlag) {
|
||||
return flag;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** @see ApplicationInfo#flags */
|
||||
public static int appInfoFlags(ParsingPackageRead pkg) {
|
||||
// @formatter:off
|
||||
return flag(pkg.isExternalStorage(), ApplicationInfo.FLAG_EXTERNAL_STORAGE)
|
||||
| flag(pkg.isBaseHardwareAccelerated(), ApplicationInfo.FLAG_HARDWARE_ACCELERATED)
|
||||
| flag(pkg.isAllowBackup(), ApplicationInfo.FLAG_ALLOW_BACKUP)
|
||||
| flag(pkg.isKillAfterRestore(), ApplicationInfo.FLAG_KILL_AFTER_RESTORE)
|
||||
| flag(pkg.isRestoreAnyVersion(), ApplicationInfo.FLAG_RESTORE_ANY_VERSION)
|
||||
| flag(pkg.isFullBackupOnly(), ApplicationInfo.FLAG_FULL_BACKUP_ONLY)
|
||||
| flag(pkg.isPersistent(), ApplicationInfo.FLAG_PERSISTENT)
|
||||
| flag(pkg.isDebuggable(), ApplicationInfo.FLAG_DEBUGGABLE)
|
||||
| flag(pkg.isVmSafeMode(), ApplicationInfo.FLAG_VM_SAFE_MODE)
|
||||
| flag(pkg.isHasCode(), ApplicationInfo.FLAG_HAS_CODE)
|
||||
| flag(pkg.isAllowTaskReparenting(), ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING)
|
||||
| flag(pkg.isAllowClearUserData(), ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA)
|
||||
| flag(pkg.isLargeHeap(), ApplicationInfo.FLAG_LARGE_HEAP)
|
||||
| flag(pkg.isUsesCleartextTraffic(), ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC)
|
||||
| flag(pkg.isSupportsRtl(), ApplicationInfo.FLAG_SUPPORTS_RTL)
|
||||
| flag(pkg.isTestOnly(), ApplicationInfo.FLAG_TEST_ONLY)
|
||||
| flag(pkg.isMultiArch(), ApplicationInfo.FLAG_MULTIARCH)
|
||||
| flag(pkg.isExtractNativeLibs(), ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS)
|
||||
| flag(pkg.isGame(), ApplicationInfo.FLAG_IS_GAME)
|
||||
| flag(pkg.isSupportsSmallScreens(), ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS)
|
||||
| flag(pkg.isSupportsNormalScreens(), ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS)
|
||||
| flag(pkg.isSupportsLargeScreens(), ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS)
|
||||
| flag(pkg.isSupportsExtraLargeScreens(), ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS)
|
||||
| flag(pkg.isResizeable(), ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS)
|
||||
| flag(pkg.isAnyDensity(), ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
/** @see ApplicationInfo#privateFlags */
|
||||
public static int appInfoPrivateFlags(ParsingPackageRead pkg) {
|
||||
// @formatter:off
|
||||
int privateFlags = flag(pkg.isStaticSharedLibrary(), ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY)
|
||||
| flag(pkg.isOverlay(), ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY)
|
||||
| flag(pkg.isIsolatedSplitLoading(), ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING)
|
||||
| flag(pkg.isHasDomainUrls(), ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS)
|
||||
| flag(pkg.isProfileableByShell(), ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL)
|
||||
| flag(pkg.isBackupInForeground(), ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND)
|
||||
| flag(pkg.isUseEmbeddedDex(), ApplicationInfo.PRIVATE_FLAG_USE_EMBEDDED_DEX)
|
||||
| flag(pkg.isDefaultToDeviceProtectedStorage(), ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE)
|
||||
| flag(pkg.isDirectBootAware(), ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE)
|
||||
| flag(pkg.isPartiallyDirectBootAware(), ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE)
|
||||
| flag(pkg.isAllowClearUserDataOnFailedRestore(), ApplicationInfo.PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE)
|
||||
| flag(pkg.isAllowAudioPlaybackCapture(), ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE)
|
||||
| flag(pkg.isRequestLegacyExternalStorage(), ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE)
|
||||
| flag(pkg.isUsesNonSdkApi(), ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API)
|
||||
| flag(pkg.isHasFragileUserData(), ApplicationInfo.PRIVATE_FLAG_HAS_FRAGILE_USER_DATA)
|
||||
| flag(pkg.isCantSaveState(), ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
|
||||
| flag(pkg.isResizeableActivityViaSdkVersion(), ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION)
|
||||
| flag(pkg.isAllowNativeHeapPointerTagging(), ApplicationInfo.PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING);
|
||||
// @formatter:on
|
||||
|
||||
Boolean resizeableActivity = pkg.getResizeableActivity();
|
||||
if (resizeableActivity != null) {
|
||||
if (resizeableActivity) {
|
||||
privateFlags |= ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE;
|
||||
} else {
|
||||
privateFlags |= ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE;
|
||||
}
|
||||
}
|
||||
|
||||
return privateFlags;
|
||||
}
|
||||
|
||||
private static boolean checkUseInstalled(ParsingPackageRead pkg, PackageUserState state,
|
||||
@PackageManager.PackageInfoFlags int flags) {
|
||||
// If available for the target user
|
||||
return state.isAvailable(flags);
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
public static File getDataDir(ParsingPackageRead pkg, int userId) {
|
||||
if ("android".equals(pkg.getPackageName())) {
|
||||
return Environment.getDataSystemDirectory();
|
||||
}
|
||||
|
||||
if (pkg.isDefaultToDeviceProtectedStorage()
|
||||
&& PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) {
|
||||
return getDeviceProtectedDataDir(pkg, userId);
|
||||
} else {
|
||||
return getCredentialProtectedDataDir(pkg, userId);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static File getDeviceProtectedDataDir(ParsingPackageRead pkg, int userId) {
|
||||
return Environment.getDataUserDePackageDirectory(pkg.getVolumeUuid(), userId,
|
||||
pkg.getPackageName());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static File getCredentialProtectedDataDir(ParsingPackageRead pkg, int userId) {
|
||||
return Environment.getDataUserCePackageDirectory(pkg.getVolumeUuid(), userId,
|
||||
pkg.getPackageName());
|
||||
}
|
||||
}
|
||||
@@ -61,7 +61,7 @@ import com.android.internal.util.Parcelling.BuiltIn.ForBoolean;
|
||||
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
|
||||
import com.android.internal.util.Parcelling.BuiltIn.ForInternedStringArray;
|
||||
import com.android.internal.util.Parcelling.BuiltIn.ForInternedStringList;
|
||||
import com.android.internal.util.Parcelling.BuiltIn.ForInternedStringMap;
|
||||
import com.android.internal.util.Parcelling.BuiltIn.ForInternedStringValueMap;
|
||||
import com.android.internal.util.Parcelling.BuiltIn.ForInternedStringSet;
|
||||
|
||||
import java.security.PublicKey;
|
||||
@@ -159,7 +159,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
|
||||
private int overlayPriority;
|
||||
private boolean overlayIsStatic;
|
||||
@NonNull
|
||||
@DataClass.ParcelWith(ForInternedStringMap.class)
|
||||
@DataClass.ParcelWith(ForInternedStringValueMap.class)
|
||||
private Map<String, String> overlayables = emptyMap();
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -26,6 +26,7 @@ import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTEN
|
||||
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
|
||||
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
|
||||
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
|
||||
import static android.os.Build.VERSION_CODES.DONUT;
|
||||
import static android.os.Build.VERSION_CODES.O;
|
||||
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
|
||||
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
|
||||
@@ -99,10 +100,10 @@ import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/** @hide */
|
||||
public class ApkParseUtils {
|
||||
public class ParsingPackageUtils {
|
||||
|
||||
// TODO(b/135203078): Consolidate log tags
|
||||
static final String TAG = "PackageParsing";
|
||||
public static final String TAG = "PackageParsing";
|
||||
|
||||
/**
|
||||
* Parse the package at the given location. Automatically detects if the
|
||||
@@ -114,7 +115,7 @@ public class ApkParseUtils {
|
||||
* and unique split names.
|
||||
* <p>
|
||||
* Note that this <em>does not</em> perform signature verification; that
|
||||
* must be done separately in {@link #collectCertificates(ParsedPackage, boolean)}.
|
||||
* must be done separately in {@link #collectCertificates(ParsingPackageRead, boolean)}.
|
||||
*
|
||||
* If {@code useCaches} is true, the package parser might return a cached
|
||||
* result from a previous parse of the same {@code packageFile} with the same
|
||||
@@ -126,7 +127,7 @@ public class ApkParseUtils {
|
||||
public static ParsingPackage parsePackage(
|
||||
ParseInput parseInput,
|
||||
String[] separateProcesses,
|
||||
PackageParser.Callback callback,
|
||||
Callback callback,
|
||||
DisplayMetrics displayMetrics,
|
||||
boolean onlyCoreApps,
|
||||
File packageFile,
|
||||
@@ -148,12 +149,12 @@ public class ApkParseUtils {
|
||||
* split names.
|
||||
* <p>
|
||||
* Note that this <em>does not</em> perform signature verification; that
|
||||
* must be done separately in {@link #collectCertificates(ParsedPackage, boolean)}.
|
||||
* must be done separately in {@link #collectCertificates(ParsingPackageRead, boolean)}.
|
||||
*/
|
||||
private static ParsingPackage parseClusterPackage(
|
||||
ParseInput parseInput,
|
||||
String[] separateProcesses,
|
||||
PackageParser.Callback callback,
|
||||
Callback callback,
|
||||
DisplayMetrics displayMetrics,
|
||||
boolean onlyCoreApps,
|
||||
File packageDir,
|
||||
@@ -184,7 +185,7 @@ public class ApkParseUtils {
|
||||
final AssetManager assets = assetLoader.getBaseAssetManager();
|
||||
final File baseApk = new File(lite.baseCodePath);
|
||||
ParsingPackage parsingPackage = parseBaseApk(parseInput, separateProcesses, callback,
|
||||
displayMetrics, baseApk, assets, flags);
|
||||
displayMetrics, baseApk, lite.codePath, assets, flags);
|
||||
if (parsingPackage == null) {
|
||||
throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
|
||||
"Failed to parse base APK: " + baseApk);
|
||||
@@ -206,8 +207,7 @@ public class ApkParseUtils {
|
||||
}
|
||||
}
|
||||
|
||||
return parsingPackage.setCodePath(lite.codePath)
|
||||
.setUse32BitAbi(lite.use32bitAbi);
|
||||
return parsingPackage.setUse32BitAbi(lite.use32bitAbi);
|
||||
} finally {
|
||||
IoUtils.closeQuietly(assetLoader);
|
||||
}
|
||||
@@ -217,12 +217,12 @@ public class ApkParseUtils {
|
||||
* Parse the given APK file, treating it as as a single monolithic package.
|
||||
* <p>
|
||||
* Note that this <em>does not</em> perform signature verification; that
|
||||
* must be done separately in {@link #collectCertificates(AndroidPackage, boolean)}.
|
||||
* must be done separately in {@link #collectCertificates(ParsingPackageRead, boolean)}.
|
||||
*/
|
||||
public static ParsingPackage parseMonolithicPackage(
|
||||
ParseInput parseInput,
|
||||
String[] separateProcesses,
|
||||
PackageParser.Callback callback,
|
||||
Callback callback,
|
||||
DisplayMetrics displayMetrics,
|
||||
boolean onlyCoreApps,
|
||||
File apkFile,
|
||||
@@ -240,8 +240,8 @@ public class ApkParseUtils {
|
||||
final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags);
|
||||
try {
|
||||
return parseBaseApk(parseInput, separateProcesses, callback,
|
||||
displayMetrics, apkFile, assetLoader.getBaseAssetManager(), flags)
|
||||
.setCodePath(apkFile.getCanonicalPath())
|
||||
displayMetrics, apkFile, apkFile.getCanonicalPath(),
|
||||
assetLoader.getBaseAssetManager(), flags)
|
||||
.setUse32BitAbi(lite.use32bitAbi);
|
||||
} catch (IOException e) {
|
||||
throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
|
||||
@@ -251,14 +251,9 @@ public class ApkParseUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private static ParsingPackage parseBaseApk(
|
||||
ParseInput parseInput,
|
||||
String[] separateProcesses,
|
||||
PackageParser.Callback callback,
|
||||
DisplayMetrics displayMetrics,
|
||||
File apkFile,
|
||||
AssetManager assets,
|
||||
int flags
|
||||
private static ParsingPackage parseBaseApk(ParseInput parseInput, String[] separateProcesses,
|
||||
Callback callback, DisplayMetrics displayMetrics, File apkFile,
|
||||
String codePath, AssetManager assets, int flags
|
||||
) throws PackageParserException {
|
||||
final String apkPath = apkFile.getAbsolutePath();
|
||||
|
||||
@@ -280,8 +275,8 @@ public class ApkParseUtils {
|
||||
parser = assets.openXmlResourceParser(cookie, PackageParser.ANDROID_MANIFEST_FILENAME);
|
||||
final Resources res = new Resources(assets, displayMetrics, null);
|
||||
|
||||
ParseResult result = parseBaseApk(parseInput, separateProcesses, callback, apkPath, res,
|
||||
parser, flags);
|
||||
ParseResult result = parseBaseApk(parseInput, separateProcesses, callback, apkPath,
|
||||
codePath, res, parser, flags);
|
||||
if (!result.isSuccess()) {
|
||||
throw new PackageParserException(result.getParseError(),
|
||||
apkPath + " (at " + parser.getPositionDescription() + "): "
|
||||
@@ -305,7 +300,6 @@ public class ApkParseUtils {
|
||||
}
|
||||
|
||||
return pkg.setVolumeUuid(volumeUuid)
|
||||
.setApplicationVolumeUuid(volumeUuid)
|
||||
.setSigningDetails(SigningDetails.UNKNOWN);
|
||||
} catch (PackageParserException e) {
|
||||
throw e;
|
||||
@@ -372,14 +366,9 @@ public class ApkParseUtils {
|
||||
* @param flags Flags how to parse
|
||||
* @return Parsed package or null on error.
|
||||
*/
|
||||
private static ParseResult parseBaseApk(
|
||||
ParseInput parseInput,
|
||||
String[] separateProcesses,
|
||||
PackageParser.Callback callback,
|
||||
String apkPath,
|
||||
Resources res,
|
||||
XmlResourceParser parser,
|
||||
int flags
|
||||
private static ParseResult parseBaseApk(ParseInput parseInput, String[] separateProcesses,
|
||||
Callback callback, String apkPath, String codePath, Resources res,
|
||||
XmlResourceParser parser, int flags
|
||||
) throws XmlPullParserException, IOException {
|
||||
final String splitName;
|
||||
final String pkgName;
|
||||
@@ -407,12 +396,8 @@ public class ApkParseUtils {
|
||||
|
||||
boolean isCoreApp = parser.getAttributeBooleanValue(null, "coreApp", false);
|
||||
|
||||
ParsingPackage parsingPackage = PackageImpl.forParsing(
|
||||
pkgName,
|
||||
apkPath,
|
||||
manifestArray,
|
||||
isCoreApp
|
||||
);
|
||||
ParsingPackage parsingPackage = callback.startParsingPackage(pkgName, apkPath, codePath,
|
||||
manifestArray, isCoreApp);
|
||||
|
||||
ParseResult result = parseBaseApkTags(parseInput, separateProcesses, callback,
|
||||
parsingPackage, manifestArray, res, parser, flags);
|
||||
@@ -645,7 +630,7 @@ public class ApkParseUtils {
|
||||
// remain null in the primary copy (we like to avoid extra copies because
|
||||
// it can be large)
|
||||
Bundle appMetaData = parseMetaData(parsingPackage, res, parser,
|
||||
parsingPackage.getAppMetaData(),
|
||||
parsingPackage.getMetaData(),
|
||||
outError);
|
||||
if (appMetaData == null) {
|
||||
return parseInput.error(
|
||||
@@ -654,7 +639,7 @@ public class ApkParseUtils {
|
||||
);
|
||||
}
|
||||
|
||||
parsingPackage.setAppMetaData(appMetaData);
|
||||
parsingPackage.setMetaData(appMetaData);
|
||||
break;
|
||||
case "uses-static-library":
|
||||
ParseResult parseResult = parseUsesStaticLibrary(parseInput, parsingPackage,
|
||||
@@ -727,7 +712,7 @@ public class ApkParseUtils {
|
||||
private static ParseResult parseBaseApkTags(
|
||||
ParseInput parseInput,
|
||||
String[] separateProcesses,
|
||||
PackageParser.Callback callback,
|
||||
Callback callback,
|
||||
ParsingPackage parsingPackage,
|
||||
TypedArray manifestArray,
|
||||
Resources res,
|
||||
@@ -897,13 +882,23 @@ public class ApkParseUtils {
|
||||
// At this point we can check if an application is not supporting densities and hence
|
||||
// cannot be windowed / resized. Note that an SDK version of 0 is common for
|
||||
// pre-Doughnut applications.
|
||||
if (parsingPackage.usesCompatibilityMode()) {
|
||||
if (usesCompatibilityMode(parsingPackage)) {
|
||||
adjustPackageToBeUnresizeableAndUnpipable(parsingPackage);
|
||||
}
|
||||
|
||||
return parseInput.success(parsingPackage);
|
||||
}
|
||||
|
||||
public static boolean usesCompatibilityMode(ParsingPackage pkg) {
|
||||
return pkg.getTargetSdkVersion() < DONUT
|
||||
|| (!pkg.isSupportsSmallScreens()
|
||||
&& !pkg.isSupportsNormalScreens()
|
||||
&& !pkg.isSupportsLargeScreens()
|
||||
&& !pkg.isSupportsExtraLargeScreens()
|
||||
&& !pkg.isResizeable()
|
||||
&& !pkg.isAnyDensity());
|
||||
}
|
||||
|
||||
private static ParseResult parseUnknownTag(
|
||||
ParseInput parseInput,
|
||||
ParsingPackage parsingPackage,
|
||||
@@ -1234,20 +1229,11 @@ public class ApkParseUtils {
|
||||
);
|
||||
}
|
||||
|
||||
parsingPackage.setName(outInfoName);
|
||||
parsingPackage.setClassName(outInfoName);
|
||||
}
|
||||
|
||||
int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(roundIconRes, 0) : 0;
|
||||
if (roundIconVal != 0) {
|
||||
parsingPackage.setIcon(roundIconVal)
|
||||
.setNonLocalizedLabel(null);
|
||||
} else {
|
||||
int iconVal = sa.getResourceId(iconRes, 0);
|
||||
if (iconVal != 0) {
|
||||
parsingPackage.setIcon(iconVal)
|
||||
.setNonLocalizedLabel(null);
|
||||
}
|
||||
}
|
||||
parsingPackage.setRoundIconRes(sa.getResourceId(roundIconRes, 0))
|
||||
.setIconRes(sa.getResourceId(iconRes, 0));
|
||||
|
||||
int logoVal = sa.getResourceId(logoRes, 0);
|
||||
if (logoVal != 0) {
|
||||
@@ -1375,7 +1361,7 @@ public class ApkParseUtils {
|
||||
ParsingPackage parsingPackage,
|
||||
Resources res,
|
||||
XmlResourceParser parser,
|
||||
PackageParser.Callback callback
|
||||
Callback callback
|
||||
)
|
||||
throws XmlPullParserException, IOException {
|
||||
TypedArray sa = res.obtainAttributes(parser,
|
||||
@@ -1854,7 +1840,7 @@ public class ApkParseUtils {
|
||||
public static ParseResult parseBaseApplication(
|
||||
ParseInput parseInput,
|
||||
String[] separateProcesses,
|
||||
PackageParser.Callback callback,
|
||||
Callback callback,
|
||||
ParsingPackage parsingPackage,
|
||||
Resources res,
|
||||
XmlResourceParser parser,
|
||||
@@ -1893,11 +1879,6 @@ public class ApkParseUtils {
|
||||
return result;
|
||||
}
|
||||
|
||||
String name = parsingPackage.getName();
|
||||
if (name != null) {
|
||||
parsingPackage.setClassName(name);
|
||||
}
|
||||
|
||||
String manageSpaceActivity = sa.getNonConfigurationString(
|
||||
R.styleable.AndroidManifestApplication_manageSpaceActivity,
|
||||
Configuration.NATIVE_CONFIG_VERSION);
|
||||
@@ -2078,10 +2059,10 @@ public class ApkParseUtils {
|
||||
R.styleable.AndroidManifestApplication_directBootAware, false));
|
||||
|
||||
if (sa.hasValueOrEmpty(R.styleable.AndroidManifestApplication_resizeableActivity)) {
|
||||
parsingPackage.setActivitiesResizeModeResizeable(sa.getBoolean(
|
||||
parsingPackage.setResizeableActivity(sa.getBoolean(
|
||||
R.styleable.AndroidManifestApplication_resizeableActivity, true));
|
||||
} else {
|
||||
parsingPackage.setActivitiesResizeModeResizeableViaSdkVersion(
|
||||
parsingPackage.setResizeableActivityViaSdkVersion(
|
||||
parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.N);
|
||||
}
|
||||
|
||||
@@ -2195,7 +2176,7 @@ public class ApkParseUtils {
|
||||
parsingPackage.setCrossProfile(
|
||||
sa.getBoolean(R.styleable.AndroidManifestApplication_crossProfile, false));
|
||||
|
||||
parsingPackage.setIsGame(sa.getBoolean(
|
||||
parsingPackage.setGame(sa.getBoolean(
|
||||
R.styleable.AndroidManifestApplication_isGame, false));
|
||||
|
||||
boolean cantSaveState = sa.getBoolean(
|
||||
@@ -2334,7 +2315,7 @@ public class ApkParseUtils {
|
||||
// remain null in the primary copy (we like to avoid extra copies because
|
||||
// it can be large)
|
||||
Bundle appMetaData = parseMetaData(parsingPackage, res, parser,
|
||||
parsingPackage.getAppMetaData(),
|
||||
parsingPackage.getMetaData(),
|
||||
outError);
|
||||
if (appMetaData == null) {
|
||||
return parseInput.error(
|
||||
@@ -2343,7 +2324,7 @@ public class ApkParseUtils {
|
||||
);
|
||||
}
|
||||
|
||||
parsingPackage.setAppMetaData(appMetaData);
|
||||
parsingPackage.setMetaData(appMetaData);
|
||||
break;
|
||||
case "static-library":
|
||||
sa = res.obtainAttributes(parser,
|
||||
@@ -2728,7 +2709,7 @@ public class ApkParseUtils {
|
||||
// Use the application max aspect ration as default if set.
|
||||
maxAspectRatio = packageMaxAspectRatio;
|
||||
} else {
|
||||
Bundle appMetaData = parsingPackage.getAppMetaData();
|
||||
Bundle appMetaData = parsingPackage.getMetaData();
|
||||
if (appMetaData != null && appMetaData.containsKey(
|
||||
PackageParser.METADATA_MAX_ASPECT_RATIO)) {
|
||||
maxAspectRatio = appMetaData.getFloat(PackageParser.METADATA_MAX_ASPECT_RATIO,
|
||||
@@ -2764,7 +2745,7 @@ public class ApkParseUtils {
|
||||
*/
|
||||
private static void setMinAspectRatio(
|
||||
ParsingPackage parsingPackage,
|
||||
PackageParser.Callback callback
|
||||
Callback callback
|
||||
) {
|
||||
final float minAspectRatio;
|
||||
float packageMinAspectRatio = parsingPackage.getMinAspectRatio();
|
||||
@@ -2845,7 +2826,7 @@ public class ApkParseUtils {
|
||||
}
|
||||
|
||||
parsingPackage
|
||||
.setIsOverlay(true)
|
||||
.setOverlay(true)
|
||||
.setOverlayTarget(target)
|
||||
.setOverlayTargetName(targetName)
|
||||
.setOverlayCategory(category)
|
||||
@@ -2907,7 +2888,7 @@ public class ApkParseUtils {
|
||||
sa.getInteger(R.styleable.AndroidManifestSupportsScreens_normalScreens, 1))
|
||||
.setSupportsLargeScreens(
|
||||
sa.getInteger(R.styleable.AndroidManifestSupportsScreens_largeScreens, 1))
|
||||
.setSupportsXLargeScreens(
|
||||
.setSupportsExtraLargeScreens(
|
||||
sa.getInteger(R.styleable.AndroidManifestSupportsScreens_xlargeScreens, 1))
|
||||
.setResizeable(
|
||||
sa.getInteger(R.styleable.AndroidManifestSupportsScreens_resizeable, 1))
|
||||
@@ -2960,7 +2941,7 @@ public class ApkParseUtils {
|
||||
R.styleable.AndroidManifestOriginalPackage_name,
|
||||
0);
|
||||
if (!parsingPackage.getPackageName().equals(orig)) {
|
||||
if (parsingPackage.getOriginalPackages() == null) {
|
||||
if (parsingPackage.getOriginalPackages().isEmpty()) {
|
||||
parsingPackage.setRealPackage(parsingPackage.getPackageName());
|
||||
}
|
||||
parsingPackage.addOriginalPackage(orig);
|
||||
@@ -3186,36 +3167,36 @@ public class ApkParseUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect certificates from all the APKs described in the given package,
|
||||
* populating {@link AndroidPackageWrite#setSigningDetails(SigningDetails)}. Also asserts that
|
||||
* Collect certificates from all the APKs described in the given package. Also asserts that
|
||||
* all APK contents are signed correctly and consistently.
|
||||
*/
|
||||
public static void collectCertificates(AndroidPackage pkg, boolean skipVerify)
|
||||
public static SigningDetails collectCertificates(ParsingPackageRead pkg, boolean skipVerify)
|
||||
throws PackageParserException {
|
||||
pkg.mutate().setSigningDetails(SigningDetails.UNKNOWN);
|
||||
SigningDetails signingDetails = SigningDetails.UNKNOWN;
|
||||
|
||||
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
|
||||
try {
|
||||
pkg.mutate().setSigningDetails(collectCertificates(
|
||||
signingDetails = collectCertificates(
|
||||
pkg.getBaseCodePath(),
|
||||
skipVerify,
|
||||
pkg.isStaticSharedLibrary(),
|
||||
pkg.getSigningDetails(),
|
||||
signingDetails,
|
||||
pkg.getTargetSdkVersion()
|
||||
));
|
||||
);
|
||||
|
||||
String[] splitCodePaths = pkg.getSplitCodePaths();
|
||||
if (!ArrayUtils.isEmpty(splitCodePaths)) {
|
||||
for (int i = 0; i < splitCodePaths.length; i++) {
|
||||
pkg.mutate().setSigningDetails(collectCertificates(
|
||||
signingDetails = collectCertificates(
|
||||
splitCodePaths[i],
|
||||
skipVerify,
|
||||
pkg.isStaticSharedLibrary(),
|
||||
pkg.getSigningDetails(),
|
||||
signingDetails,
|
||||
pkg.getTargetSdkVersion()
|
||||
));
|
||||
);
|
||||
}
|
||||
}
|
||||
return signingDetails;
|
||||
} finally {
|
||||
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
|
||||
}
|
||||
@@ -3346,4 +3327,15 @@ public class ApkParseUtils {
|
||||
return errorMessage;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback interface for retrieving information that may be needed while parsing
|
||||
* a package.
|
||||
*/
|
||||
public interface Callback {
|
||||
boolean hasFeature(String feature);
|
||||
|
||||
ParsingPackage startParsingPackage(String packageName, String baseCodePath, String codePath,
|
||||
TypedArray manifestArray, boolean isCoreApp);
|
||||
}
|
||||
}
|
||||
45
core/java/android/content/pm/parsing/ParsingUtils.java
Normal file
45
core/java/android/content/pm/parsing/ParsingUtils.java
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.content.pm.parsing;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
|
||||
/** @hide **/
|
||||
public class ParsingUtils {
|
||||
|
||||
// TODO(b/135203078): Consolidate log tags
|
||||
public static final String TAG = "PackageParsing";
|
||||
|
||||
@Nullable
|
||||
public static String buildClassName(String pkg, CharSequence clsSeq) {
|
||||
if (clsSeq == null || clsSeq.length() <= 0) {
|
||||
return null;
|
||||
}
|
||||
String cls = clsSeq.toString();
|
||||
char c = cls.charAt(0);
|
||||
if (c == '.') {
|
||||
return pkg + cls;
|
||||
}
|
||||
if (cls.indexOf('.') < 0) {
|
||||
StringBuilder b = new StringBuilder(pkg);
|
||||
b.append('.');
|
||||
b.append(cls);
|
||||
return b.toString();
|
||||
}
|
||||
return cls;
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ package com.android.internal.content.om;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.pm.PackagePartitions;
|
||||
import android.content.pm.parsing.AndroidPackage;
|
||||
import android.content.pm.parsing.ParsingPackageRead;
|
||||
import android.os.Build;
|
||||
import android.os.Process;
|
||||
import android.os.Trace;
|
||||
@@ -36,7 +36,7 @@ import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
@@ -71,10 +71,10 @@ public class OverlayConfig {
|
||||
* Interface for providing information on scanned packages.
|
||||
* TODO(147840005): Remove this when android:isStatic and android:priority are fully deprecated
|
||||
*/
|
||||
public interface AndroidPackageProvider {
|
||||
public interface PackageProvider {
|
||||
|
||||
/** Performs the given action for each package. */
|
||||
void forEachPackage(Consumer<AndroidPackage> p);
|
||||
void forEachPackage(BiConsumer<ParsingPackageRead, Boolean> p);
|
||||
}
|
||||
|
||||
private static final Comparator<ParsedConfiguration> sStaticOverlayComparator = (c1, c2) -> {
|
||||
@@ -100,7 +100,7 @@ public class OverlayConfig {
|
||||
@VisibleForTesting
|
||||
public OverlayConfig(@Nullable File rootDirectory,
|
||||
@Nullable Supplier<OverlayScanner> scannerFactory,
|
||||
@Nullable AndroidPackageProvider packageProvider) {
|
||||
@Nullable PackageProvider packageProvider) {
|
||||
Preconditions.checkArgument((scannerFactory == null) != (packageProvider == null),
|
||||
"scannerFactory and packageProvider cannot be both null or both non-null");
|
||||
|
||||
@@ -208,7 +208,7 @@ public class OverlayConfig {
|
||||
* {@link #getSystemInstance()} will return the initialized instance.
|
||||
*/
|
||||
@NonNull
|
||||
public static OverlayConfig initializeSystemInstance(AndroidPackageProvider packageProvider) {
|
||||
public static OverlayConfig initializeSystemInstance(PackageProvider packageProvider) {
|
||||
if (Process.myUid() != Process.SYSTEM_UID) {
|
||||
throw new IllegalStateException("Can only be invoked in the system process");
|
||||
}
|
||||
@@ -221,7 +221,7 @@ public class OverlayConfig {
|
||||
|
||||
/**
|
||||
* Retrieves the singleton instance initialized by
|
||||
* {@link #initializeSystemInstance(AndroidPackageProvider)}.
|
||||
* {@link #initializeSystemInstance(PackageProvider)}.
|
||||
*/
|
||||
@NonNull
|
||||
public static OverlayConfig getSystemInstance() {
|
||||
@@ -291,10 +291,10 @@ public class OverlayConfig {
|
||||
|
||||
@NonNull
|
||||
private static ArrayList<ParsedOverlayInfo> getOverlayPackageInfos(
|
||||
@NonNull AndroidPackageProvider packageManager) {
|
||||
@NonNull PackageProvider packageManager) {
|
||||
final ArrayList<ParsedOverlayInfo> overlays = new ArrayList<>();
|
||||
packageManager.forEachPackage((AndroidPackage p) -> {
|
||||
if (p.getOverlayTarget() != null && p.isSystem()) {
|
||||
packageManager.forEachPackage((ParsingPackageRead p, Boolean isSystem) -> {
|
||||
if (p.getOverlayTarget() != null && isSystem) {
|
||||
overlays.add(new ParsedOverlayInfo(p.getPackageName(), p.getOverlayTarget(),
|
||||
p.getTargetSdkVersion(), p.isOverlayIsStatic(), p.getOverlayPriority(),
|
||||
new File(p.getBaseCodePath())));
|
||||
|
||||
@@ -15,10 +15,18 @@
|
||||
*/
|
||||
package com.android.internal.util;
|
||||
|
||||
import static java.util.Collections.emptySet;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.os.Parcel;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
@@ -90,6 +98,132 @@ public interface Parcelling<T> {
|
||||
*/
|
||||
interface BuiltIn {
|
||||
|
||||
class ForInternedString implements Parcelling<String> {
|
||||
@Override
|
||||
public void parcel(@Nullable String item, Parcel dest, int parcelFlags) {
|
||||
dest.writeString(item);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String unparcel(Parcel source) {
|
||||
return TextUtils.safeIntern(source.readString());
|
||||
}
|
||||
}
|
||||
|
||||
class ForInternedStringArray implements Parcelling<String[]> {
|
||||
@Override
|
||||
public void parcel(String[] item, Parcel dest, int parcelFlags) {
|
||||
dest.writeStringArray(item);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String[] unparcel(Parcel source) {
|
||||
String[] array = source.readStringArray();
|
||||
if (array != null) {
|
||||
int size = ArrayUtils.size(array);
|
||||
for (int index = 0; index < size; index++) {
|
||||
array[index] = TextUtils.safeIntern(array[index]);
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
class ForInternedStringList implements Parcelling<List<String>> {
|
||||
@Override
|
||||
public void parcel(List<String> item, Parcel dest, int parcelFlags) {
|
||||
dest.writeStringList(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> unparcel(Parcel source) {
|
||||
ArrayList<String> list = source.createStringArrayList();
|
||||
if (list != null) {
|
||||
int size = list.size();
|
||||
for (int index = 0; index < size; index++) {
|
||||
list.set(index, list.get(index).intern());
|
||||
}
|
||||
}
|
||||
return CollectionUtils.emptyIfNull(list);
|
||||
}
|
||||
}
|
||||
|
||||
class ForInternedStringValueMap implements Parcelling<Map<String, String>> {
|
||||
@Override
|
||||
public void parcel(Map<String, String> item, Parcel dest, int parcelFlags) {
|
||||
dest.writeMap(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> unparcel(Parcel source) {
|
||||
ArrayMap<String, String> map = new ArrayMap<>();
|
||||
source.readMap(map, String.class.getClassLoader());
|
||||
for (int index = 0; index < map.size(); index++) {
|
||||
map.setValueAt(index, TextUtils.safeIntern(map.valueAt(index)));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
class ForInternedStringSet implements Parcelling<Set<String>> {
|
||||
@Override
|
||||
public void parcel(Set<String> item, Parcel dest, int parcelFlags) {
|
||||
if (item == null) {
|
||||
dest.writeInt(-1);
|
||||
} else {
|
||||
dest.writeInt(item.size());
|
||||
for (String string : item) {
|
||||
dest.writeString(string);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> unparcel(Parcel source) {
|
||||
final int size = source.readInt();
|
||||
if (size < 0) {
|
||||
return emptySet();
|
||||
}
|
||||
Set<String> set = new ArraySet<>();
|
||||
for (int count = 0; count < size; count++) {
|
||||
set.add(TextUtils.safeIntern(source.readString()));
|
||||
}
|
||||
return set;
|
||||
}
|
||||
}
|
||||
|
||||
class ForBoolean implements Parcelling<Boolean> {
|
||||
@Override
|
||||
public void parcel(@Nullable Boolean item, Parcel dest, int parcelFlags) {
|
||||
if (item == null) {
|
||||
// This writes 1 for null to mirror TypedArray.getInteger(booleanResId, 1)
|
||||
dest.writeInt(1);
|
||||
} else if (!item) {
|
||||
dest.writeInt(0);
|
||||
} else {
|
||||
dest.writeInt(-1);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Boolean unparcel(Parcel source) {
|
||||
switch (source.readInt()) {
|
||||
default:
|
||||
throw new IllegalStateException("Malformed Parcel reading Boolean: "
|
||||
+ source);
|
||||
case 1:
|
||||
return null;
|
||||
case 0:
|
||||
return Boolean.FALSE;
|
||||
case -1:
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ForPattern implements Parcelling<Pattern> {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -21,11 +21,11 @@ import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.pm.parsing.AndroidPackage;
|
||||
import android.content.pm.parsing.ParsingPackageRead;
|
||||
import android.os.Build;
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import com.android.internal.content.om.OverlayConfig.AndroidPackageProvider;
|
||||
import com.android.internal.content.om.OverlayConfig.PackageProvider;
|
||||
import com.android.internal.content.om.OverlayScanner;
|
||||
import com.android.internal.content.om.OverlayScanner.ParsedOverlayInfo;
|
||||
|
||||
@@ -39,14 +39,14 @@ import org.mockito.invocation.InvocationOnMock;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* A {@link TestRule} that runs a test case twice. First, the test case runs with a non-null
|
||||
* {@link OverlayScanner} as if the zygote process is scanning the overlay packages
|
||||
* and parsing configuration files. The test case then runs with a non-null
|
||||
* {@link AndroidPackageProvider} as if the system server is parsing configuration files.
|
||||
* {@link PackageProvider} as if the system server is parsing configuration files.
|
||||
*
|
||||
* This simulates what will happen on device. If an exception would be thrown in the zygote, then
|
||||
* the exception should be thrown in the first run of the test case.
|
||||
@@ -60,7 +60,7 @@ public class OverlayConfigIterationRule implements TestRule {
|
||||
|
||||
private final ArrayMap<File, ParsedOverlayInfo> mOverlayStubResults = new ArrayMap<>();
|
||||
private Supplier<OverlayScanner> mOverlayScanner;
|
||||
private AndroidPackageProvider mAndroidPackageProvider;
|
||||
private PackageProvider mPkgProvider;
|
||||
private Iteration mIteration;
|
||||
|
||||
/**
|
||||
@@ -96,9 +96,9 @@ public class OverlayConfigIterationRule implements TestRule {
|
||||
return mOverlayScanner;
|
||||
}
|
||||
|
||||
/** Retrieves the {@link AndroidPackageProvider} for the current run of the test. */
|
||||
AndroidPackageProvider getPackageProvider() {
|
||||
return mAndroidPackageProvider;
|
||||
/** Retrieves the {@link PackageProvider} for the current run of the test. */
|
||||
PackageProvider getPackageProvider() {
|
||||
return mPkgProvider;
|
||||
}
|
||||
|
||||
/** Retrieves the current iteration of the test. */
|
||||
@@ -123,7 +123,7 @@ public class OverlayConfigIterationRule implements TestRule {
|
||||
}
|
||||
return scanner;
|
||||
};
|
||||
mAndroidPackageProvider = null;
|
||||
mPkgProvider = null;
|
||||
mIteration = Iteration.ZYGOTE;
|
||||
base.evaluate();
|
||||
|
||||
@@ -131,14 +131,15 @@ public class OverlayConfigIterationRule implements TestRule {
|
||||
// the system server is parsing the configuration files and using PackageManager to
|
||||
// retrieving information of overlays.
|
||||
mOverlayScanner = null;
|
||||
mAndroidPackageProvider = Mockito.mock(AndroidPackageProvider.class);
|
||||
mPkgProvider = Mockito.mock(PackageProvider.class);
|
||||
mIteration = Iteration.SYSTEM_SERVER;
|
||||
doAnswer((InvocationOnMock invocation) -> {
|
||||
final Object[] args = invocation.getArguments();
|
||||
final Consumer<AndroidPackage> f = (Consumer<AndroidPackage>) args[0];
|
||||
final BiConsumer<ParsingPackageRead, Boolean> f =
|
||||
(BiConsumer<ParsingPackageRead, Boolean>) args[0];
|
||||
for (Map.Entry<File, ParsedOverlayInfo> overlay :
|
||||
mOverlayStubResults.entrySet()) {
|
||||
final AndroidPackage a = Mockito.mock(AndroidPackage.class);
|
||||
final ParsingPackageRead a = Mockito.mock(ParsingPackageRead.class);
|
||||
final ParsedOverlayInfo info = overlay.getValue();
|
||||
when(a.getPackageName()).thenReturn(info.packageName);
|
||||
when(a.getOverlayTarget()).thenReturn(info.targetPackageName);
|
||||
@@ -146,12 +147,10 @@ public class OverlayConfigIterationRule implements TestRule {
|
||||
when(a.isOverlayIsStatic()).thenReturn(info.isStatic);
|
||||
when(a.getOverlayPriority()).thenReturn(info.priority);
|
||||
when(a.getBaseCodePath()).thenReturn(info.path.getPath());
|
||||
when(a.isSystem()).thenReturn(
|
||||
!info.path.getPath().contains("data/overlay"));
|
||||
f.accept(a);
|
||||
f.accept(a, !info.path.getPath().contains("data/overlay"));
|
||||
}
|
||||
return null;
|
||||
}).when(mAndroidPackageProvider).forEachPackage(any());
|
||||
}).when(mPkgProvider).forEachPackage(any());
|
||||
|
||||
base.evaluate();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -209,20 +209,16 @@ import android.content.pm.VersionedPackage;
|
||||
import android.content.pm.dex.ArtManager;
|
||||
import android.content.pm.dex.DexMetadataHelper;
|
||||
import android.content.pm.dex.IArtManager;
|
||||
import android.content.pm.parsing.AndroidPackage;
|
||||
import android.content.pm.parsing.ApkParseUtils;
|
||||
import android.content.pm.parsing.ComponentParseUtils;
|
||||
import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
|
||||
import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
|
||||
import android.content.pm.parsing.ComponentParseUtils.ParsedComponent;
|
||||
import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
|
||||
import android.content.pm.parsing.ComponentParseUtils.ParsedMainComponent;
|
||||
import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
|
||||
import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
|
||||
import android.content.pm.parsing.ComponentParseUtils.ParsedService;
|
||||
import android.content.pm.parsing.PackageImpl;
|
||||
import android.content.pm.parsing.PackageInfoUtils;
|
||||
import android.content.pm.parsing.ParsedPackage;
|
||||
import android.content.pm.parsing.library.PackageBackwardCompatibility;
|
||||
import android.content.pm.parsing.ParsingPackageRead;
|
||||
import android.content.pm.parsing.ParsingPackageUtils;
|
||||
import android.content.res.Resources;
|
||||
import android.content.rollback.IRollbackManager;
|
||||
import android.database.ContentObserver;
|
||||
@@ -341,6 +337,13 @@ import com.android.server.pm.dex.DexManager;
|
||||
import com.android.server.pm.dex.DexoptOptions;
|
||||
import com.android.server.pm.dex.PackageDexUsage;
|
||||
import com.android.server.pm.dex.ViewCompiler;
|
||||
import com.android.server.pm.parsing.PackageInfoUtils;
|
||||
import com.android.server.pm.parsing.PackageParser2;
|
||||
import com.android.server.pm.parsing.library.PackageBackwardCompatibility;
|
||||
import com.android.server.pm.parsing.pkg.AndroidPackage;
|
||||
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
|
||||
import com.android.server.pm.parsing.pkg.PackageImpl;
|
||||
import com.android.server.pm.parsing.pkg.ParsedPackage;
|
||||
import com.android.server.pm.permission.BasePermission;
|
||||
import com.android.server.pm.permission.PermissionManagerService;
|
||||
import com.android.server.pm.permission.PermissionManagerServiceInternal;
|
||||
@@ -1011,13 +1014,13 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
|
||||
private final AppsFilter mAppsFilter;
|
||||
|
||||
class PackageParserCallback implements PackageParser.Callback {
|
||||
class PackageParserCallback extends PackageParser2.Callback {
|
||||
@Override public final boolean hasFeature(String feature) {
|
||||
return PackageManagerService.this.hasSystemFeature(feature, 0);
|
||||
}
|
||||
}
|
||||
|
||||
final PackageParser.Callback mPackageParserCallback = new PackageParserCallback();
|
||||
final PackageParser2.Callback mPackageParserCallback = new PackageParserCallback();
|
||||
|
||||
// Currently known shared libraries.
|
||||
final ArrayMap<String, LongSparseArray<SharedLibraryInfo>> mSharedLibraries = new ArrayMap<>();
|
||||
@@ -2033,7 +2036,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
mInstantAppRegistry.onPackageInstalledLPw(res.pkg, res.newUsers);
|
||||
}
|
||||
|
||||
final String packageName = res.pkg.getAppInfoPackageName();
|
||||
final String packageName = res.pkg.getPackageName();
|
||||
|
||||
// Determine the set of users who are adding this package for
|
||||
// the first time vs. those who are seeing an update.
|
||||
@@ -2083,7 +2086,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
// Send added for users that see the package for the first time
|
||||
// sendPackageAddedForNewUsers also deals with system apps
|
||||
int appId = UserHandle.getAppId(res.uid);
|
||||
boolean isSystem = res.pkg.isSystemApp();
|
||||
boolean isSystem = res.pkg.isSystem();
|
||||
sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload,
|
||||
virtualPreload /*startReceiver*/, appId, firstUserIds, firstInstantUserIds);
|
||||
|
||||
@@ -2859,12 +2862,8 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
final int systemParseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR;
|
||||
final int systemScanFlags = scanFlags | SCAN_AS_SYSTEM;
|
||||
|
||||
PackageParser packageParser = new PackageParser();
|
||||
packageParser.setSeparateProcesses(mSeparateProcesses);
|
||||
packageParser.setOnlyCoreApps(mOnlyCore);
|
||||
packageParser.setDisplayMetrics(mMetrics);
|
||||
packageParser.setCacheDir(mCacheDir);
|
||||
packageParser.setCallback(mPackageParserCallback);
|
||||
PackageParser2 packageParser = new PackageParser2(mSeparateProcesses, mOnlyCore,
|
||||
mMetrics, mCacheDir, mPackageParserCallback);
|
||||
|
||||
ExecutorService executorService = ParallelPackageParser.makeExecutorService();
|
||||
// Collect vendor/product/system_ext overlay packages. (Do this before scanning
|
||||
@@ -2902,7 +2901,9 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
|
||||
// Parse overlay configuration files to set default enable state, mutability, and
|
||||
// priority of system overlays.
|
||||
mOverlayConfig = OverlayConfig.initializeSystemInstance(mPmInternal::forEachPackage);
|
||||
mOverlayConfig = OverlayConfig.initializeSystemInstance(
|
||||
consumer -> mPmInternal.forEachPackage(
|
||||
pkg -> consumer.accept(pkg, pkg.isSystem())));
|
||||
|
||||
// Prune any system packages that no longer exist.
|
||||
final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>();
|
||||
@@ -3044,7 +3045,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
// special privileges
|
||||
removePackageLI(pkg, true);
|
||||
try {
|
||||
final File codePath = new File(pkg.getAppInfoCodePath());
|
||||
final File codePath = new File(pkg.getCodePath());
|
||||
scanPackageTracedLI(codePath, 0, scanFlags, 0, null);
|
||||
} catch (PackageManagerException e) {
|
||||
Slog.e(TAG, "Failed to parse updated, ex-system package: "
|
||||
@@ -4208,7 +4209,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
throw new SecurityException("Package " + packageName + " is currently frozen!");
|
||||
}
|
||||
|
||||
if (!userKeyUnlocked && !ps.pkg.isEncryptionAware()) {
|
||||
if (!userKeyUnlocked && !AndroidPackageUtils.isEncryptionAware(ps.pkg)) {
|
||||
throw new SecurityException("Package " + packageName + " is not encryption aware!");
|
||||
}
|
||||
}
|
||||
@@ -4574,7 +4575,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
// reader
|
||||
synchronized (mLock) {
|
||||
final AndroidPackage p = mPackages.get(packageName);
|
||||
if (p != null && p.isMatch(flags)) {
|
||||
if (p != null && AndroidPackageUtils.isMatchForSystemOnly(p, flags)) {
|
||||
PackageSetting ps = getPackageSettingInternal(p.getPackageName(), callingUid);
|
||||
if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
|
||||
return -1;
|
||||
@@ -4604,7 +4605,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
// reader
|
||||
synchronized (mLock) {
|
||||
final AndroidPackage p = mPackages.get(packageName);
|
||||
if (p != null && p.isMatch(flags)) {
|
||||
if (p != null && AndroidPackageUtils.isMatchForSystemOnly(p, flags)) {
|
||||
PackageSetting ps = getPackageSetting(p.getPackageName());
|
||||
if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
|
||||
return null;
|
||||
@@ -8563,7 +8564,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
return null;
|
||||
}
|
||||
final ParsedInstrumentation i = mInstrumentation.get(component);
|
||||
return PackageInfoUtils.generateInstrumentationInfo(i, pkg, flags);
|
||||
return PackageInfoUtils.generateInstrumentationInfo(i, pkg, flags, callingUserId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8576,11 +8577,12 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
|
||||
return ParceledListSlice.emptyList();
|
||||
}
|
||||
return new ParceledListSlice<>(queryInstrumentationInternal(targetPackage, flags));
|
||||
return new ParceledListSlice<>(queryInstrumentationInternal(targetPackage, flags,
|
||||
callingUserId));
|
||||
}
|
||||
|
||||
private @NonNull List<InstrumentationInfo> queryInstrumentationInternal(String targetPackage,
|
||||
int flags) {
|
||||
int flags, int userId) {
|
||||
ArrayList<InstrumentationInfo> finalList = new ArrayList<>();
|
||||
|
||||
// reader
|
||||
@@ -8593,7 +8595,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
AndroidPackage pkg = mPackages.get(p.getPackageName());
|
||||
if (pkg != null) {
|
||||
InstrumentationInfo ii = PackageInfoUtils.generateInstrumentationInfo(p,
|
||||
pkg, flags);
|
||||
pkg, flags, userId);
|
||||
if (ii != null) {
|
||||
finalList.add(ii);
|
||||
}
|
||||
@@ -8606,7 +8608,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
}
|
||||
|
||||
private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags,
|
||||
long currentTime, PackageParser packageParser, ExecutorService executorService) {
|
||||
long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
|
||||
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
|
||||
try {
|
||||
scanDirLI(scanDir, parseFlags, scanFlags, currentTime, packageParser, executorService);
|
||||
@@ -8616,7 +8618,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
}
|
||||
|
||||
private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime,
|
||||
PackageParser packageParser, ExecutorService executorService) {
|
||||
PackageParser2 packageParser, ExecutorService executorService) {
|
||||
final File[] files = scanDir.listFiles();
|
||||
if (ArrayUtils.isEmpty(files)) {
|
||||
Log.d(TAG, "No files in app dir " + scanDir);
|
||||
@@ -8720,7 +8722,8 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
|
||||
try {
|
||||
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
|
||||
ApkParseUtils.collectCertificates(parsedPackage, skipVerify);
|
||||
parsedPackage.setSigningDetails(
|
||||
ParsingPackageUtils.collectCertificates(parsedPackage, skipVerify));
|
||||
} catch (PackageParserException e) {
|
||||
throw PackageManagerException.from(e);
|
||||
} finally {
|
||||
@@ -8774,16 +8777,13 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
private AndroidPackage scanPackageLI(File scanFile, int parseFlags, int scanFlags,
|
||||
long currentTime, UserHandle user) throws PackageManagerException {
|
||||
if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
|
||||
PackageParser pp = new PackageParser();
|
||||
pp.setSeparateProcesses(mSeparateProcesses);
|
||||
pp.setOnlyCoreApps(mOnlyCore);
|
||||
pp.setDisplayMetrics(mMetrics);
|
||||
pp.setCallback(mPackageParserCallback);
|
||||
PackageParser2 pp = new PackageParser2(mSeparateProcesses, mOnlyCore, mMetrics, null,
|
||||
mPackageParserCallback);
|
||||
|
||||
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
|
||||
final ParsedPackage parsedPackage;
|
||||
try {
|
||||
parsedPackage = pp.parseParsedPackage(scanFile, parseFlags, false);
|
||||
parsedPackage = pp.parsePackage(scanFile, parseFlags, false);
|
||||
} catch (PackageParserException e) {
|
||||
throw PackageManagerException.from(e);
|
||||
} finally {
|
||||
@@ -8869,18 +8869,6 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
final boolean pkgAlreadyExists;
|
||||
PackageSetting pkgSetting;
|
||||
|
||||
// NOTE: installPackageLI() has the same code to setup the package's
|
||||
// application info. This probably should be done lower in the call
|
||||
// stack [such as scanPackageOnly()]. However, we verify the application
|
||||
// info prior to that [in scanPackageNew()] and thus have to setup
|
||||
// the application info early.
|
||||
// TODO(b/135203078): Remove all of these application info calls
|
||||
parsedPackage.setApplicationVolumeUuid(parsedPackage.getVolumeUuid())
|
||||
.setApplicationInfoCodePath(parsedPackage.getCodePath())
|
||||
.setApplicationInfoResourcePath(parsedPackage.getCodePath())
|
||||
.setApplicationInfoBaseResourcePath(parsedPackage.getBaseCodePath())
|
||||
.setApplicationInfoSplitResourcePaths(parsedPackage.getSplitCodePaths());
|
||||
|
||||
synchronized (mLock) {
|
||||
renamedPkgName = mSettings.getRenamedPackageLPr(parsedPackage.getRealPackage());
|
||||
final String realPkgName = getRealPackageName(parsedPackage, renamedPkgName);
|
||||
@@ -9957,7 +9945,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
// Or:
|
||||
// - Package manager is in a state where package isn't scanned yet. This will
|
||||
// get called again after scanning to fix the dependencies.
|
||||
if (pkg.isLibrary()) {
|
||||
if (AndroidPackageUtils.isLibrary(pkg)) {
|
||||
if (pkg.getStaticSharedLibName() != null) {
|
||||
SharedLibraryInfo definedLibrary = getSharedLibraryInfoLPr(
|
||||
pkg.getStaticSharedLibName(), pkg.getStaticSharedLibVersion());
|
||||
@@ -9994,7 +9982,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
}
|
||||
}
|
||||
if (p != null) {
|
||||
usesLibraryFiles.addAll(p.getAllCodePaths());
|
||||
usesLibraryFiles.addAll(AndroidPackageUtils.getAllCodePaths(p));
|
||||
// If the package provides libraries, add the dependency to them.
|
||||
applyDefiningSharedLibraryUpdateLocked(pkg, libInfo, (definingLibrary, dependency) -> {
|
||||
definingLibrary.addDependency(dependency);
|
||||
@@ -10026,18 +10014,18 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
// that libraries are searched in the correct order) and must have no
|
||||
// duplicates.
|
||||
ArrayList<SharedLibraryInfo> usesLibraryInfos = null;
|
||||
if (pkg.getUsesLibraries() != null) {
|
||||
if (!pkg.getUsesLibraries().isEmpty()) {
|
||||
usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesLibraries(), null, null,
|
||||
pkg.getPackageName(), true, pkg.getTargetSdkVersion(), null,
|
||||
availablePackages, existingLibraries, newLibraries);
|
||||
}
|
||||
if (pkg.getUsesStaticLibraries() != null) {
|
||||
if (!pkg.getUsesStaticLibraries().isEmpty()) {
|
||||
usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesStaticLibraries(),
|
||||
pkg.getUsesStaticLibrariesVersions(), pkg.getUsesStaticLibrariesCertDigests(),
|
||||
pkg.getPackageName(), true, pkg.getTargetSdkVersion(), usesLibraryInfos,
|
||||
availablePackages, existingLibraries, newLibraries);
|
||||
}
|
||||
if (pkg.getUsesOptionalLibraries() != null) {
|
||||
if (!pkg.getUsesOptionalLibraries().isEmpty()) {
|
||||
usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesOptionalLibraries(),
|
||||
null, null, pkg.getPackageName(), false, pkg.getTargetSdkVersion(),
|
||||
usesLibraryInfos, availablePackages, existingLibraries, newLibraries);
|
||||
@@ -10607,7 +10595,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
}
|
||||
pkgSetting.signatures.mSigningDetails = reconciledPkg.signingDetails;
|
||||
|
||||
if (pkg.getAdoptPermissions() != null) {
|
||||
if (!pkg.getAdoptPermissions().isEmpty()) {
|
||||
// This package wants to adopt ownership of permissions from
|
||||
// another package.
|
||||
for (int i = pkg.getAdoptPermissions().size() - 1; i >= 0; i--) {
|
||||
@@ -10848,8 +10836,8 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
}
|
||||
|
||||
// Initialize package source and resource directories
|
||||
final File destCodeFile = new File(parsedPackage.getAppInfoCodePath());
|
||||
final File destResourceFile = new File(parsedPackage.getAppInfoResourcePath());
|
||||
final File destCodeFile = new File(parsedPackage.getCodePath());
|
||||
final File destResourceFile = new File(parsedPackage.getCodePath());
|
||||
|
||||
// We keep references to the derived CPU Abis from settings in oder to reuse
|
||||
// them in the case where we're not upgrading or booting for the first time.
|
||||
@@ -10878,7 +10866,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
}
|
||||
|
||||
String[] usesStaticLibraries = null;
|
||||
if (parsedPackage.getUsesStaticLibraries() != null) {
|
||||
if (!parsedPackage.getUsesStaticLibraries().isEmpty()) {
|
||||
usesStaticLibraries = new String[parsedPackage.getUsesStaticLibraries().size()];
|
||||
parsedPackage.getUsesStaticLibraries().toArray(usesStaticLibraries);
|
||||
}
|
||||
@@ -10898,8 +10886,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
} else {
|
||||
// make a deep copy to avoid modifying any existing system state.
|
||||
pkgSetting = new PackageSetting(pkgSetting);
|
||||
// TODO(b/135203078): Remove entirely. Set package directly.
|
||||
parsedPackage.setPackageSettingCallback(pkgSetting);
|
||||
pkgSetting.pkg = parsedPackage;
|
||||
|
||||
// REMOVE SharedUserSetting from method; update in a separate call.
|
||||
//
|
||||
@@ -10945,9 +10932,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
.setSeInfo(SELinuxMMAC.getSeInfo(parsedPackage, sharedUserSetting,
|
||||
injector.getCompatibility()))
|
||||
.setSeInfoUser(SELinuxUtil.assignSeinfoUser(pkgSetting.readUserState(
|
||||
userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId)))
|
||||
.setProcessName(fixProcessName(parsedPackage.getPackageName(),
|
||||
parsedPackage.getProcessName()));
|
||||
userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId)));
|
||||
|
||||
if (!isPlatformPackage) {
|
||||
// Get all of our default paths setup
|
||||
@@ -10964,7 +10949,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
|
||||
if (needToDeriveAbi) {
|
||||
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
|
||||
final boolean extractNativeLibs = !parsedPackage.isLibrary();
|
||||
final boolean extractNativeLibs = !AndroidPackageUtils.isLibrary(parsedPackage);
|
||||
final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths> derivedAbi =
|
||||
packageAbiHelper.derivePackageAbi(parsedPackage, cpuAbiOverride,
|
||||
extractNativeLibs);
|
||||
@@ -11104,13 +11089,13 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
}
|
||||
pkgSetting.setTimeStamp(scanFileTime);
|
||||
// TODO(b/135203078): Remove, move to constructor
|
||||
parsedPackage.setPackageSettingCallback(pkgSetting);
|
||||
pkgSetting.pkg = parsedPackage;
|
||||
pkgSetting.pkgFlags = parsedPackage.getFlags();
|
||||
if (parsedPackage.getLongVersionCode() != pkgSetting.versionCode) {
|
||||
pkgSetting.versionCode = parsedPackage.getLongVersionCode();
|
||||
}
|
||||
// Update volume if needed
|
||||
final String volumeUuid = parsedPackage.getApplicationInfoVolumeUuid();
|
||||
final String volumeUuid = parsedPackage.getVolumeUuid();
|
||||
if (!Objects.equals(volumeUuid, pkgSetting.volumeUuid)) {
|
||||
Slog.i(PackageManagerService.TAG,
|
||||
"Update" + (pkgSetting.isSystem() ? " system" : "")
|
||||
@@ -11122,14 +11107,15 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
|
||||
SharedLibraryInfo staticSharedLibraryInfo = null;
|
||||
if (!TextUtils.isEmpty(parsedPackage.getStaticSharedLibName())) {
|
||||
staticSharedLibraryInfo = SharedLibraryInfo.createForStatic(parsedPackage);
|
||||
staticSharedLibraryInfo =
|
||||
AndroidPackageUtils.createSharedLibraryForStatic(parsedPackage);
|
||||
}
|
||||
List<SharedLibraryInfo> dynamicSharedLibraryInfos = null;
|
||||
if (!ArrayUtils.isEmpty(parsedPackage.getLibraryNames())) {
|
||||
dynamicSharedLibraryInfos = new ArrayList<>(parsedPackage.getLibraryNames().size());
|
||||
for (String name : parsedPackage.getLibraryNames()) {
|
||||
dynamicSharedLibraryInfos.add(
|
||||
SharedLibraryInfo.createForDynamic(parsedPackage, name));
|
||||
AndroidPackageUtils.createSharedLibraryForDynamic(parsedPackage, name));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11202,7 +11188,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
parsedPackage.setAllComponentsDirectBootAware(true);
|
||||
}
|
||||
if (compressedFileExists(parsedPackage.getCodePath())) {
|
||||
parsedPackage.setIsStub(true);
|
||||
parsedPackage.setStub(true);
|
||||
}
|
||||
} else {
|
||||
parsedPackage
|
||||
@@ -11257,7 +11243,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
|
||||
private <T extends ComponentParseUtils.ParsedMainComponent>
|
||||
void assertPackageProcesses(AndroidPackage pkg, List<T> components,
|
||||
ArrayMap<String, ComponentParseUtils.ParsedProcess> procs, String compName)
|
||||
Map<String, ComponentParseUtils.ParsedProcess> procs, String compName)
|
||||
throws PackageManagerException {
|
||||
if (components == null) {
|
||||
return;
|
||||
@@ -11291,8 +11277,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
assertCodePolicy(pkg);
|
||||
}
|
||||
|
||||
if (pkg.getAppInfoCodePath() == null ||
|
||||
pkg.getAppInfoResourcePath() == null) {
|
||||
if (pkg.getCodePath() == null) {
|
||||
// Bail out. The resource and code paths haven't been set.
|
||||
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
|
||||
"Code and resource paths haven't been set correctly");
|
||||
@@ -11375,49 +11360,49 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
}
|
||||
|
||||
// Static shared libs cannot declare activities
|
||||
if (pkg.getActivities() != null && !pkg.getActivities().isEmpty()) {
|
||||
if (!pkg.getActivities().isEmpty()) {
|
||||
throw new PackageManagerException(
|
||||
"Static shared libs cannot declare activities");
|
||||
}
|
||||
|
||||
// Static shared libs cannot declare services
|
||||
if (pkg.getServices() != null && !pkg.getServices().isEmpty()) {
|
||||
if (!pkg.getServices().isEmpty()) {
|
||||
throw new PackageManagerException(
|
||||
"Static shared libs cannot declare services");
|
||||
}
|
||||
|
||||
// Static shared libs cannot declare providers
|
||||
if (pkg.getProviders() != null && !pkg.getProviders().isEmpty()) {
|
||||
if (!pkg.getProviders().isEmpty()) {
|
||||
throw new PackageManagerException(
|
||||
"Static shared libs cannot declare content providers");
|
||||
}
|
||||
|
||||
// Static shared libs cannot declare receivers
|
||||
if (pkg.getReceivers() != null && !pkg.getReceivers().isEmpty()) {
|
||||
if (!pkg.getReceivers().isEmpty()) {
|
||||
throw new PackageManagerException(
|
||||
"Static shared libs cannot declare broadcast receivers");
|
||||
}
|
||||
|
||||
// Static shared libs cannot declare permission groups
|
||||
if (pkg.getPermissionGroups() != null && !pkg.getPermissionGroups().isEmpty()) {
|
||||
if (!pkg.getPermissionGroups().isEmpty()) {
|
||||
throw new PackageManagerException(
|
||||
"Static shared libs cannot declare permission groups");
|
||||
}
|
||||
|
||||
// Static shared libs cannot declare features
|
||||
if (pkg.getFeatures() != null && !pkg.getFeatures().isEmpty()) {
|
||||
if (!pkg.getFeatures().isEmpty()) {
|
||||
throw new PackageManagerException(
|
||||
"Static shared libs cannot declare features");
|
||||
}
|
||||
|
||||
// Static shared libs cannot declare permissions
|
||||
if (pkg.getPermissions() != null && !pkg.getPermissions().isEmpty()) {
|
||||
if (!pkg.getPermissions().isEmpty()) {
|
||||
throw new PackageManagerException(
|
||||
"Static shared libs cannot declare permissions");
|
||||
}
|
||||
|
||||
// Static shared libs cannot declare protected broadcasts
|
||||
if (pkg.getProtectedBroadcasts() != null) {
|
||||
if (!pkg.getProtectedBroadcasts().isEmpty()) {
|
||||
throw new PackageManagerException(
|
||||
"Static shared libs cannot declare protected broadcasts");
|
||||
}
|
||||
@@ -11479,12 +11464,11 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
+ " and requiring known paths " + known.codePathString
|
||||
+ " & " + known.resourcePathString);
|
||||
}
|
||||
if (!pkg.getAppInfoCodePath().equals(known.codePathString)
|
||||
|| !pkg.getAppInfoResourcePath().equals(
|
||||
known.resourcePathString)) {
|
||||
if (!pkg.getCodePath().equals(known.codePathString)
|
||||
|| !pkg.getCodePath().equals(known.resourcePathString)) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED,
|
||||
"Application package " + pkg.getPackageName()
|
||||
+ " found at " + pkg.getAppInfoCodePath()
|
||||
+ " found at " + pkg.getCodePath()
|
||||
+ " but expected at " + known.codePathString
|
||||
+ "; ignoring.");
|
||||
}
|
||||
@@ -11506,8 +11490,8 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
|
||||
// If this package has defined explicit processes, then ensure that these are
|
||||
// the only processes used by its components.
|
||||
final ArrayMap<String, ComponentParseUtils.ParsedProcess> procs = pkg.getProcesses();
|
||||
if (procs != null) {
|
||||
final Map<String, ComponentParseUtils.ParsedProcess> procs = pkg.getProcesses();
|
||||
if (!procs.isEmpty()) {
|
||||
if (!procs.containsKey(pkg.getProcessName())) {
|
||||
throw new PackageManagerException(
|
||||
INSTALL_FAILED_PROCESS_NOT_DEFINED,
|
||||
@@ -11793,7 +11777,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
if (clientLibPkgs != null) {
|
||||
for (int i=0; i<clientLibPkgs.size(); i++) {
|
||||
AndroidPackage clientPkg = clientLibPkgs.get(i);
|
||||
killApplication(clientPkg.getAppInfoPackageName(),
|
||||
killApplication(clientPkg.getPackageName(),
|
||||
clientPkg.getUid(), "update lib");
|
||||
}
|
||||
}
|
||||
@@ -11807,7 +11791,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
// Add the new setting to mSettings
|
||||
mSettings.insertPackageSettingLPw(pkgSetting, pkg);
|
||||
// Add the new setting to mPackages
|
||||
mPackages.put(pkg.getAppInfoPackageName(), pkg);
|
||||
mPackages.put(pkg.getPackageName(), pkg);
|
||||
if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) {
|
||||
mApexManager.registerApkInApex(pkg);
|
||||
}
|
||||
@@ -11887,8 +11871,8 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
// Set up information for custom user intent resolution activity.
|
||||
mResolveActivity.applicationInfo = pkg.toAppInfoWithoutState();
|
||||
mResolveActivity.name = mCustomResolverComponentName.getClassName();
|
||||
mResolveActivity.packageName = pkg.getAppInfoPackageName();
|
||||
mResolveActivity.processName = pkg.getAppInfoProcessName();
|
||||
mResolveActivity.packageName = pkg.getPackageName();
|
||||
mResolveActivity.processName = pkg.getProcessName();
|
||||
mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
|
||||
mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS |
|
||||
ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
|
||||
@@ -13727,7 +13711,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
try {
|
||||
if (bm.isUserReadyForBackup(userId)) {
|
||||
bm.restoreAtInstallForUser(
|
||||
userId, res.pkg.getAppInfoPackageName(), token);
|
||||
userId, res.pkg.getPackageName(), token);
|
||||
} else {
|
||||
Slog.w(TAG, "User " + userId + " is not ready. Restore at install "
|
||||
+ "didn't take place.");
|
||||
@@ -13755,7 +13739,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
IRollbackManager rm = IRollbackManager.Stub.asInterface(
|
||||
ServiceManager.getService(Context.ROLLBACK_SERVICE));
|
||||
|
||||
final String packageName = res.pkg.getAppInfoPackageName();
|
||||
final String packageName = res.pkg.getPackageName();
|
||||
final String seInfo = res.pkg.getSeInfo();
|
||||
final int[] allUsers = mUserManager.getUserIds();
|
||||
final int[] installedUsers;
|
||||
@@ -13815,7 +13799,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
if (data.res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
|
||||
continue;
|
||||
}
|
||||
if (packageName.equals(data.res.pkg.getAppInfoPackageName())) {
|
||||
if (packageName.equals(data.res.pkg.getPackageName())) {
|
||||
// right package; but is it for the right user?
|
||||
for (int uIndex = 0; uIndex < data.res.newUsers.length; uIndex++) {
|
||||
if (userId == data.res.newUsers[uIndex]) {
|
||||
@@ -15000,14 +14984,6 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
parsedPackage.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,
|
||||
afterCodeFile, parsedPackage.getSplitCodePaths()));
|
||||
|
||||
// Reflect the rename in app info
|
||||
// TODO(b/135203078): Remove all of these application info calls
|
||||
parsedPackage.setApplicationVolumeUuid(parsedPackage.getVolumeUuid())
|
||||
.setApplicationInfoCodePath(parsedPackage.getCodePath())
|
||||
.setApplicationInfoResourcePath(parsedPackage.getCodePath())
|
||||
.setApplicationInfoBaseResourcePath(parsedPackage.getBaseCodePath())
|
||||
.setApplicationInfoSplitResourcePaths(parsedPackage.getSplitCodePaths());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -15117,14 +15093,6 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reflect the move in app info
|
||||
// TODO(b/135203078): Remove all of these application info calls
|
||||
parsedPackage.setApplicationVolumeUuid(parsedPackage.getVolumeUuid())
|
||||
.setApplicationInfoCodePath(parsedPackage.getCodePath())
|
||||
.setApplicationInfoResourcePath(parsedPackage.getCodePath())
|
||||
.setApplicationInfoBaseResourcePath(parsedPackage.getBaseCodePath())
|
||||
.setApplicationInfoSplitResourcePaths(parsedPackage.getSplitCodePaths());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -15922,8 +15890,8 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
// which means we are replacing another update that is already
|
||||
// installed. We need to make sure to delete the older one's .apk.
|
||||
res.removedInfo.args = createInstallArgsForExisting(
|
||||
oldPackage.getAppInfoCodePath(),
|
||||
oldPackage.getAppInfoResourcePath(),
|
||||
oldPackage.getCodePath(),
|
||||
oldPackage.getCodePath(),
|
||||
getAppDexInstructionSets(oldPackage.getPrimaryCpuAbi(),
|
||||
oldPackage.getSecondaryCpuAbi()));
|
||||
} else {
|
||||
@@ -15944,14 +15912,14 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
|
||||
// If deleted package lived in a container, give users a chance to
|
||||
// relinquish resources before killing.
|
||||
if (oldPackage.isForwardLocked() || isExternal(oldPackage)) {
|
||||
if (isExternal(oldPackage)) {
|
||||
if (DEBUG_INSTALL) {
|
||||
Slog.i(TAG, "upgrading pkg " + oldPackage
|
||||
+ " is ASEC-hosted -> UNAVAILABLE");
|
||||
}
|
||||
final int[] uidArray = new int[]{oldPackage.getUid()};
|
||||
final ArrayList<String> pkgList = new ArrayList<>(1);
|
||||
pkgList.add(oldPackage.getAppInfoPackageName());
|
||||
pkgList.add(oldPackage.getPackageName());
|
||||
sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null);
|
||||
}
|
||||
|
||||
@@ -16328,16 +16296,14 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
| PackageParser.PARSE_ENFORCE_CODE
|
||||
| (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);
|
||||
|
||||
PackageParser pp = new PackageParser();
|
||||
pp.setSeparateProcesses(mSeparateProcesses);
|
||||
pp.setDisplayMetrics(mMetrics);
|
||||
pp.setCallback(mPackageParserCallback);
|
||||
PackageParser2 pp = new PackageParser2(mSeparateProcesses, false, mMetrics, null,
|
||||
mPackageParserCallback);
|
||||
|
||||
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
|
||||
ParsedPackage parsedPackage;
|
||||
try {
|
||||
parsedPackage = pp.parseParsedPackage(tmpPackageFile, parseFlags, false);
|
||||
DexMetadataHelper.validatePackageDexMetadata(parsedPackage);
|
||||
parsedPackage = pp.parsePackage(tmpPackageFile, parseFlags, false);
|
||||
AndroidPackageUtils.validatePackageDexMetadata(parsedPackage);
|
||||
} catch (PackageParserException e) {
|
||||
throw new PrepareFailure("Failed parse during installPackageLI", e);
|
||||
} finally {
|
||||
@@ -16393,7 +16359,8 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
parsedPackage.setSigningDetails(args.signingDetails);
|
||||
} else {
|
||||
// TODO(b/136132412): skip for Incremental installation
|
||||
ApkParseUtils.collectCertificates(parsedPackage, false /* skipVerify */);
|
||||
parsedPackage.setSigningDetails(
|
||||
ParsingPackageUtils.collectCertificates(parsedPackage, false /* skipVerify */));
|
||||
}
|
||||
} catch (PackageParserException e) {
|
||||
throw new PrepareFailure("Failed collect during installPackageLI", e);
|
||||
@@ -16636,7 +16603,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
try {
|
||||
String abiOverride = (TextUtils.isEmpty(parsedPackage.getCpuAbiOverride())
|
||||
? args.abiOverride : parsedPackage.getCpuAbiOverride());
|
||||
final boolean extractNativeLibs = !parsedPackage.isLibrary();
|
||||
final boolean extractNativeLibs = !AndroidPackageUtils.isLibrary(parsedPackage);
|
||||
final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
|
||||
derivedAbi = mInjector.getAbiHelper().derivePackageAbi(
|
||||
parsedPackage, abiOverride, extractNativeLibs);
|
||||
@@ -19980,7 +19947,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
// We're dealing with a component level state change
|
||||
// First, verify that this is a valid class name.
|
||||
AndroidPackage pkg = pkgSetting.pkg;
|
||||
if (pkg == null || !pkg.hasComponentClassName(className)) {
|
||||
if (pkg == null || !AndroidPackageUtils.hasComponentClassName(pkg, className)) {
|
||||
if (pkg != null &&
|
||||
pkg.getTargetSdkVersion() >=
|
||||
Build.VERSION_CODES.JELLY_BEAN) {
|
||||
@@ -21336,7 +21303,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
final int[] packageUids = new int[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
final AndroidPackage pkg = packages.get(i);
|
||||
packageNames[i] = pkg.getAppInfoPackageName();
|
||||
packageNames[i] = pkg.getPackageName();
|
||||
packageUids[i] = pkg.getUid();
|
||||
}
|
||||
sendResourcesChangedBroadcast(mediaStatus, replacing, packageNames, packageUids,
|
||||
@@ -21801,7 +21768,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,
|
||||
appId, seInfo, pkg.getTargetSdkVersion());
|
||||
} catch (InstallerException e) {
|
||||
if (pkg.isSystemApp()) {
|
||||
if (pkg.isSystem()) {
|
||||
logCriticalInfo(Log.ERROR, "Failed to create app data for " + packageName
|
||||
+ ", but trying to recover: " + e);
|
||||
destroyAppDataLeafLIF(pkg, userId, flags);
|
||||
@@ -22054,7 +22021,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
|| shouldFilterApplicationLocked(ps, callingUid, user.getIdentifier())) {
|
||||
throw new PackageManagerException(MOVE_FAILED_DOESNT_EXIST, "Missing package");
|
||||
}
|
||||
if (pkg.isSystemApp()) {
|
||||
if (pkg.isSystem()) {
|
||||
throw new PackageManagerException(MOVE_FAILED_SYSTEM_PACKAGE,
|
||||
"Cannot move system application");
|
||||
}
|
||||
@@ -22080,7 +22047,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
|
||||
"Package already moved to " + volumeUuid);
|
||||
}
|
||||
if (pkg.isInternal() && isPackageDeviceAdminOnAnyUser(packageName)) {
|
||||
if (!pkg.isExternalStorage() && isPackageDeviceAdminOnAnyUser(packageName)) {
|
||||
throw new PackageManagerException(MOVE_FAILED_DEVICE_ADMIN,
|
||||
"Device admin cannot be moved");
|
||||
}
|
||||
@@ -23352,7 +23319,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledAndMatches(ParsedComponent component, int flags, int userId) {
|
||||
public boolean isEnabledAndMatches(ParsedMainComponent component, int flags, int userId) {
|
||||
synchronized (mLock) {
|
||||
AndroidPackage pkg = getPackage(component.getPackageName());
|
||||
return mSettings.isEnabledAndMatchLPr(pkg, component, flags, userId);
|
||||
@@ -24177,12 +24144,12 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
if (p == null) {
|
||||
return false;
|
||||
}
|
||||
return p.canHaveOatDir();
|
||||
return AndroidPackageUtils.canHaveOatDir(p, p.isUpdatedSystemApp());
|
||||
}
|
||||
}
|
||||
|
||||
private String getOatDir(AndroidPackage pkg) {
|
||||
if (!pkg.canHaveOatDir()) {
|
||||
if (!AndroidPackageUtils.canHaveOatDir(pkg, pkg.isUpdatedSystemApp())) {
|
||||
return null;
|
||||
}
|
||||
File codePath = new File(pkg.getCodePath());
|
||||
@@ -24202,7 +24169,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
}
|
||||
instructionSets = getAppDexInstructionSets(pkg.getPrimaryCpuAbi(),
|
||||
pkg.getSecondaryCpuAbi());
|
||||
codePaths = pkg.getAllCodePaths();
|
||||
codePaths = AndroidPackageUtils.getAllCodePaths(pkg);
|
||||
oatDir = getOatDir(pkg);
|
||||
|
||||
for (String codePath : codePaths) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -20,13 +20,12 @@ import android.annotation.Nullable;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.content.pm.parsing.AndroidPackage;
|
||||
import android.content.pm.parsing.ParsedPackage;
|
||||
import android.service.pm.PackageProto;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
|
||||
import com.android.server.pm.parsing.pkg.AndroidPackage;
|
||||
import com.android.server.pm.permission.PermissionsState;
|
||||
|
||||
import java.io.File;
|
||||
@@ -39,8 +38,7 @@ import java.util.Set;
|
||||
/**
|
||||
* Settings data for a particular package we know about.
|
||||
*/
|
||||
public final class PackageSetting extends PackageSettingBase implements
|
||||
ParsedPackage.PackageSettingCallback {
|
||||
public final class PackageSetting extends PackageSettingBase {
|
||||
int appId;
|
||||
|
||||
public AndroidPackage pkg;
|
||||
@@ -323,10 +321,4 @@ public final class PackageSetting extends PackageSettingBase implements
|
||||
Set<String> mimeGroupNames = other.mimeGroups != null ? other.mimeGroups.keySet() : null;
|
||||
updateMimeGroups(mimeGroupNames);
|
||||
}
|
||||
|
||||
// TODO(b/135203078): Move to constructor
|
||||
@Override
|
||||
public void setAndroidPackage(AndroidPackage pkg) {
|
||||
this.pkg = pkg;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3155,7 +3155,7 @@ public final class Settings {
|
||||
LocalServices.getService(PackageManagerInternal.class);
|
||||
for (PackageSetting ps : mPackages.values()) {
|
||||
if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0 && ps.pkg != null
|
||||
&& ps.pkg.getPreferredActivityFilters() != null) {
|
||||
&& !ps.pkg.getPreferredActivityFilters().isEmpty()) {
|
||||
List<ComponentParseUtils.ParsedActivityIntentInfo> intents
|
||||
= ps.pkg.getPreferredActivityFilters();
|
||||
for (int i=0; i<intents.size(); i++) {
|
||||
@@ -4608,10 +4608,10 @@ public final class Settings {
|
||||
pw.print(" (override=true)");
|
||||
}
|
||||
pw.println();
|
||||
if (ps.pkg.getQueriesPackages() != null) {
|
||||
if (ps.pkg.getQueriesPackages().isEmpty()) {
|
||||
pw.append(prefix).append(" queriesPackages=").println(ps.pkg.getQueriesPackages());
|
||||
}
|
||||
if (ps.pkg.getQueriesIntents() != null) {
|
||||
if (!ps.pkg.getQueriesIntents().isEmpty()) {
|
||||
pw.append(prefix).append(" queriesIntents=").println(ps.pkg.getQueriesIntents());
|
||||
}
|
||||
pw.print(prefix); pw.print(" dataDir="); pw.println(ps.pkg.getDataDir());
|
||||
@@ -4707,11 +4707,10 @@ public final class Settings {
|
||||
pw.print(prefix); pw.print(" "); pw.println(usesLibraryFiles[i]);
|
||||
}
|
||||
}
|
||||
final ArrayMap<String, ComponentParseUtils.ParsedProcess> procs = pkg.getProcesses();
|
||||
if (procs != null) {
|
||||
final Map<String, ComponentParseUtils.ParsedProcess> procs = pkg.getProcesses();
|
||||
if (!procs.isEmpty()) {
|
||||
pw.print(prefix); pw.println(" processes:");
|
||||
for (int i = 0; i < procs.size(); i++) {
|
||||
final ComponentParseUtils.ParsedProcess proc = procs.valueAt(i);
|
||||
for (ComponentParseUtils.ParsedProcess proc : procs.values()) {
|
||||
pw.print(prefix); pw.print(" "); pw.println(proc.name);
|
||||
if (proc.deniedPermissions != null) {
|
||||
for (int j = 0; j < proc.deniedPermissions.size(); j++) {
|
||||
@@ -4751,7 +4750,7 @@ public final class Settings {
|
||||
pw.print(prefix); pw.print(" overlayCategory="); pw.println(pkg.getOverlayCategory());
|
||||
}
|
||||
|
||||
if (pkg != null && pkg.getPermissions() != null && pkg.getPermissions().size() > 0) {
|
||||
if (pkg != null && !pkg.getPermissions().isEmpty()) {
|
||||
final List<ParsedPermission> perms = pkg.getPermissions();
|
||||
pw.print(prefix); pw.println(" declared permissions:");
|
||||
for (int i=0; i<perms.size(); i++) {
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.pm.parsing;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.pm.PackageParserCacheHelper;
|
||||
import android.os.Parcel;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.Os;
|
||||
import android.system.OsConstants;
|
||||
import android.system.StructStat;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.server.pm.parsing.pkg.PackageImpl;
|
||||
import com.android.server.pm.parsing.pkg.ParsedPackage;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class PackageCacher {
|
||||
|
||||
private static final String TAG = "PackageCacher";
|
||||
|
||||
/**
|
||||
* Total number of packages that were read from the cache. We use it only for logging.
|
||||
*/
|
||||
public static final AtomicInteger sCachedPackageReadCount = new AtomicInteger();
|
||||
|
||||
@NonNull
|
||||
private File mCacheDir;
|
||||
|
||||
public PackageCacher(@NonNull File cacheDir) {
|
||||
this.mCacheDir = cacheDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cache key for a specified {@code packageFile} and {@code flags}.
|
||||
*/
|
||||
private String getCacheKey(File packageFile, int flags) {
|
||||
StringBuilder sb = new StringBuilder(packageFile.getName());
|
||||
sb.append('-');
|
||||
sb.append(flags);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected ParsedPackage fromCacheEntry(byte[] bytes) {
|
||||
return fromCacheEntryStatic(bytes);
|
||||
}
|
||||
|
||||
/** static version of {@link #fromCacheEntry} for unit tests. */
|
||||
@VisibleForTesting
|
||||
public static ParsedPackage fromCacheEntryStatic(byte[] bytes) {
|
||||
final Parcel p = Parcel.obtain();
|
||||
p.unmarshall(bytes, 0, bytes.length);
|
||||
p.setDataPosition(0);
|
||||
|
||||
final PackageParserCacheHelper.ReadHelper helper = new PackageParserCacheHelper.ReadHelper(p);
|
||||
helper.startAndInstall();
|
||||
|
||||
// TODO(b/135203078): Hide PackageImpl constructor?
|
||||
ParsedPackage pkg = new PackageImpl(p);
|
||||
|
||||
p.recycle();
|
||||
|
||||
sCachedPackageReadCount.incrementAndGet();
|
||||
|
||||
return pkg;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected byte[] toCacheEntry(ParsedPackage pkg) {
|
||||
return toCacheEntryStatic(pkg);
|
||||
|
||||
}
|
||||
|
||||
/** static version of {@link #toCacheEntry} for unit tests. */
|
||||
@VisibleForTesting
|
||||
public static byte[] toCacheEntryStatic(ParsedPackage pkg) {
|
||||
final Parcel p = Parcel.obtain();
|
||||
final PackageParserCacheHelper.WriteHelper helper = new PackageParserCacheHelper.WriteHelper(p);
|
||||
|
||||
pkg.writeToParcel(p, 0 /* flags */);
|
||||
|
||||
helper.finishAndUninstall();
|
||||
|
||||
byte[] serialized = p.marshall();
|
||||
p.recycle();
|
||||
|
||||
return serialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a {@code packageFile} and a {@code cacheFile} returns whether the
|
||||
* cache file is up to date based on the mod-time of both files.
|
||||
*/
|
||||
private static boolean isCacheUpToDate(File packageFile, File cacheFile) {
|
||||
try {
|
||||
// NOTE: We don't use the File.lastModified API because it has the very
|
||||
// non-ideal failure mode of returning 0 with no excepions thrown.
|
||||
// The nio2 Files API is a little better but is considerably more expensive.
|
||||
final StructStat pkg = Os.stat(packageFile.getAbsolutePath());
|
||||
final StructStat cache = Os.stat(cacheFile.getAbsolutePath());
|
||||
return pkg.st_mtime < cache.st_mtime;
|
||||
} catch (ErrnoException ee) {
|
||||
// The most common reason why stat fails is that a given cache file doesn't
|
||||
// exist. We ignore that here. It's easy to reason that it's safe to say the
|
||||
// cache isn't up to date if we see any sort of exception here.
|
||||
//
|
||||
// (1) Exception while stating the package file : This should never happen,
|
||||
// and if it does, we do a full package parse (which is likely to throw the
|
||||
// same exception).
|
||||
// (2) Exception while stating the cache file : If the file doesn't exist, the
|
||||
// cache is obviously out of date. If the file *does* exist, we can't read it.
|
||||
// We will attempt to delete and recreate it after parsing the package.
|
||||
if (ee.errno != OsConstants.ENOENT) {
|
||||
Slog.w("Error while stating package cache : ", ee);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cached parse result for {@code packageFile} for parse flags {@code flags},
|
||||
* or {@code null} if no cached result exists.
|
||||
*/
|
||||
public ParsedPackage getCachedResult(File packageFile, int flags) {
|
||||
final String cacheKey = getCacheKey(packageFile, flags);
|
||||
final File cacheFile = new File(mCacheDir, cacheKey);
|
||||
|
||||
try {
|
||||
// If the cache is not up to date, return null.
|
||||
if (!isCacheUpToDate(packageFile, cacheFile)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final byte[] bytes = IoUtils.readFileAsByteArray(cacheFile.getAbsolutePath());
|
||||
return fromCacheEntry(bytes);
|
||||
} catch (Throwable e) {
|
||||
Slog.w(TAG, "Error reading package cache: ", e);
|
||||
|
||||
// If something went wrong while reading the cache entry, delete the cache file
|
||||
// so that we regenerate it the next time.
|
||||
cacheFile.delete();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches the parse result for {@code packageFile} with flags {@code flags}.
|
||||
*/
|
||||
public void cacheResult(File packageFile, int flags, ParsedPackage parsed) {
|
||||
try {
|
||||
final String cacheKey = getCacheKey(packageFile, flags);
|
||||
final File cacheFile = new File(mCacheDir, cacheKey);
|
||||
|
||||
if (cacheFile.exists()) {
|
||||
if (!cacheFile.delete()) {
|
||||
Slog.e(TAG, "Unable to delete cache file: " + cacheFile);
|
||||
}
|
||||
}
|
||||
|
||||
final byte[] cacheEntry = toCacheEntry(parsed);
|
||||
|
||||
if (cacheEntry == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try (FileOutputStream fos = new FileOutputStream(cacheFile)) {
|
||||
fos.write(cacheEntry);
|
||||
} catch (IOException ioe) {
|
||||
Slog.w(TAG, "Error writing cache entry.", ioe);
|
||||
cacheFile.delete();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
Slog.w(TAG, "Error saving package cache.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,419 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.pm.parsing;
|
||||
|
||||
import android.annotation.CheckResult;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.apex.ApexInfo;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.ComponentInfo;
|
||||
import android.content.pm.InstrumentationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageItemInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageUserState;
|
||||
import android.content.pm.PermissionGroupInfo;
|
||||
import android.content.pm.PermissionInfo;
|
||||
import android.content.pm.ProcessInfo;
|
||||
import android.content.pm.ProviderInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
|
||||
import android.content.pm.parsing.ComponentParseUtils.ParsedComponent;
|
||||
import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
|
||||
import android.content.pm.parsing.ComponentParseUtils.ParsedMainComponent;
|
||||
import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
|
||||
import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
|
||||
import android.content.pm.parsing.ComponentParseUtils.ParsedProcess;
|
||||
import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
|
||||
import android.content.pm.parsing.ComponentParseUtils.ParsedService;
|
||||
import android.content.pm.parsing.PackageInfoWithoutStateUtils;
|
||||
import android.os.UserHandle;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.server.pm.PackageSetting;
|
||||
import com.android.server.pm.parsing.pkg.AndroidPackage;
|
||||
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
|
||||
|
||||
import libcore.util.EmptyArray;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/** @hide **/
|
||||
public class PackageInfoUtils {
|
||||
|
||||
@Nullable
|
||||
public static PackageInfo generate(AndroidPackage pkg, int[] gids,
|
||||
@PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
|
||||
Set<String> grantedPermissions, PackageUserState state, int userId) {
|
||||
PackageSetting pkgSetting = null;
|
||||
return generateWithComponents(pkg, gids, flags, firstInstallTime, lastUpdateTime,
|
||||
grantedPermissions, state, userId, null, pkgSetting);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PackageInfo generate(AndroidPackage pkg, ApexInfo apexInfo, int flags,
|
||||
PackageSetting pkgSetting) {
|
||||
return generateWithComponents(pkg, EmptyArray.INT, flags, 0, 0, Collections.emptySet(),
|
||||
new PackageUserState(), UserHandle.getCallingUserId(), apexInfo, pkgSetting);
|
||||
}
|
||||
|
||||
private static PackageInfo generateWithComponents(AndroidPackage pkg, int[] gids,
|
||||
@PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
|
||||
Set<String> grantedPermissions, PackageUserState state, int userId,
|
||||
@Nullable ApexInfo apexInfo, @Nullable PackageSetting pkgSetting) {
|
||||
ApplicationInfo applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
|
||||
if (applicationInfo == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PackageInfo info = PackageInfoWithoutStateUtils.generateWithoutComponents(pkg, gids, flags,
|
||||
firstInstallTime, lastUpdateTime, grantedPermissions, state, userId, apexInfo,
|
||||
applicationInfo);
|
||||
if (info == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
info.isStub = pkg.isStub();
|
||||
info.coreApp = pkg.isCoreApp();
|
||||
|
||||
if ((flags & PackageManager.GET_ACTIVITIES) != 0) {
|
||||
final int N = pkg.getActivities().size();
|
||||
if (N > 0) {
|
||||
int num = 0;
|
||||
final ActivityInfo[] res = new ActivityInfo[N];
|
||||
for (int i = 0; i < N; i++) {
|
||||
final ParsedActivity a = pkg.getActivities().get(i);
|
||||
if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), a, flags)) {
|
||||
if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(
|
||||
a.getName())) {
|
||||
continue;
|
||||
}
|
||||
res[num++] = generateActivityInfo(pkg, a, flags, state,
|
||||
applicationInfo, userId, pkgSetting);
|
||||
}
|
||||
}
|
||||
info.activities = ArrayUtils.trimToSize(res, num);
|
||||
}
|
||||
}
|
||||
if ((flags & PackageManager.GET_RECEIVERS) != 0) {
|
||||
final int size = pkg.getReceivers().size();
|
||||
if (size > 0) {
|
||||
int num = 0;
|
||||
final ActivityInfo[] res = new ActivityInfo[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
final ParsedActivity a = pkg.getReceivers().get(i);
|
||||
if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), a, flags)) {
|
||||
res[num++] = generateActivityInfo(pkg, a, flags, state, applicationInfo,
|
||||
userId, pkgSetting);
|
||||
}
|
||||
}
|
||||
info.receivers = ArrayUtils.trimToSize(res, num);
|
||||
}
|
||||
}
|
||||
if ((flags & PackageManager.GET_SERVICES) != 0) {
|
||||
final int size = pkg.getServices().size();
|
||||
if (size > 0) {
|
||||
int num = 0;
|
||||
final ServiceInfo[] res = new ServiceInfo[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
final ParsedService s = pkg.getServices().get(i);
|
||||
if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), s, flags)) {
|
||||
res[num++] = generateServiceInfo(pkg, s, flags, state, applicationInfo,
|
||||
userId, pkgSetting);
|
||||
}
|
||||
}
|
||||
info.services = ArrayUtils.trimToSize(res, num);
|
||||
}
|
||||
}
|
||||
if ((flags & PackageManager.GET_PROVIDERS) != 0) {
|
||||
final int size = pkg.getProviders().size();
|
||||
if (size > 0) {
|
||||
int num = 0;
|
||||
final ProviderInfo[] res = new ProviderInfo[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
final ParsedProvider pr = pkg.getProviders()
|
||||
.get(i);
|
||||
if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), pr, flags)) {
|
||||
res[num++] = generateProviderInfo(pkg, pr, flags, state, applicationInfo,
|
||||
userId, pkgSetting);
|
||||
}
|
||||
}
|
||||
info.providers = ArrayUtils.trimToSize(res, num);
|
||||
}
|
||||
}
|
||||
if ((flags & PackageManager.GET_INSTRUMENTATION) != 0) {
|
||||
int N = pkg.getInstrumentations().size();
|
||||
if (N > 0) {
|
||||
info.instrumentation = new InstrumentationInfo[N];
|
||||
for (int i = 0; i < N; i++) {
|
||||
info.instrumentation[i] = generateInstrumentationInfo(
|
||||
pkg.getInstrumentations().get(i), pkg, flags, userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ApplicationInfo generateApplicationInfo(AndroidPackage pkg,
|
||||
@PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId) {
|
||||
PackageSetting pkgSetting = null;
|
||||
// TODO(b/135203078): Consider cases where we don't have a PkgSetting
|
||||
if (pkg == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)
|
||||
|| !AndroidPackageUtils.isMatchForSystemOnly(pkg, flags)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ApplicationInfo info = PackageInfoWithoutStateUtils.generateApplicationInfo(pkg, flags,
|
||||
state, userId);
|
||||
if (info == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
info.flags |= appInfoFlags(pkg, pkgSetting);
|
||||
info.privateFlags |= appInfoPrivateFlags(pkg, pkgSetting);
|
||||
return info;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a,
|
||||
@PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) {
|
||||
PackageSetting pkgSetting = null;
|
||||
return generateActivityInfo(pkg, a, flags, state, null, userId, pkgSetting);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a,
|
||||
@PackageManager.ComponentInfoFlags int flags, PackageUserState state,
|
||||
@Nullable ApplicationInfo applicationInfo, int userId,
|
||||
@Nullable PackageSetting pkgSetting) {
|
||||
if (a == null) return null;
|
||||
if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)) {
|
||||
return null;
|
||||
}
|
||||
if (applicationInfo == null) {
|
||||
applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
|
||||
}
|
||||
ActivityInfo info = PackageInfoWithoutStateUtils.generateActivityInfo(pkg, a, flags, state,
|
||||
applicationInfo, userId);
|
||||
if (info == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
assignSharedFieldsForComponentInfo(info, a, pkgSetting);
|
||||
return info;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ServiceInfo generateServiceInfo(AndroidPackage pkg, ParsedService s,
|
||||
@PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) {
|
||||
PackageSetting pkgSetting = null;
|
||||
return generateServiceInfo(pkg, s, flags, state, null, userId, pkgSetting);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ServiceInfo generateServiceInfo(AndroidPackage pkg, ParsedService s,
|
||||
@PackageManager.ComponentInfoFlags int flags, PackageUserState state,
|
||||
@Nullable ApplicationInfo applicationInfo, int userId,
|
||||
@Nullable PackageSetting pkgSetting) {
|
||||
if (s == null) return null;
|
||||
if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)) {
|
||||
return null;
|
||||
}
|
||||
if (applicationInfo == null) {
|
||||
applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
|
||||
}
|
||||
ServiceInfo info = PackageInfoWithoutStateUtils.generateServiceInfo(pkg, s, flags, state,
|
||||
applicationInfo, userId);
|
||||
if (info == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
assignSharedFieldsForComponentInfo(info, s, pkgSetting);
|
||||
return info;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ProviderInfo generateProviderInfo(AndroidPackage pkg, ParsedProvider p,
|
||||
@PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) {
|
||||
PackageSetting pkgSetting = null;
|
||||
return generateProviderInfo(pkg, p, flags, state, null, userId, pkgSetting);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ProviderInfo generateProviderInfo(AndroidPackage pkg, ParsedProvider p,
|
||||
@PackageManager.ComponentInfoFlags int flags, PackageUserState state,
|
||||
@Nullable ApplicationInfo applicationInfo, int userId,
|
||||
@Nullable PackageSetting pkgSetting) {
|
||||
if (p == null) return null;
|
||||
if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)) {
|
||||
return null;
|
||||
}
|
||||
if (applicationInfo == null) {
|
||||
applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
|
||||
}
|
||||
ProviderInfo info = PackageInfoWithoutStateUtils.generateProviderInfo(pkg, p, flags, state,
|
||||
applicationInfo, userId);
|
||||
if (info == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
assignSharedFieldsForComponentInfo(info, p, pkgSetting);
|
||||
return info;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static InstrumentationInfo generateInstrumentationInfo(ParsedInstrumentation i,
|
||||
AndroidPackage pkg, @PackageManager.ComponentInfoFlags int flags, int userId) {
|
||||
PackageSetting pkgSetting = null;
|
||||
if (i == null) return null;
|
||||
|
||||
InstrumentationInfo info =
|
||||
PackageInfoWithoutStateUtils.generateInstrumentationInfo(i, pkg, flags, userId);
|
||||
if (info == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO(b/135203078): Add setting related state
|
||||
info.primaryCpuAbi = pkg.getPrimaryCpuAbi();
|
||||
info.secondaryCpuAbi = pkg.getSecondaryCpuAbi();
|
||||
info.nativeLibraryDir = pkg.getNativeLibraryDir();
|
||||
info.secondaryNativeLibraryDir = pkg.getSecondaryNativeLibraryDir();
|
||||
|
||||
assignStateFieldsForPackageItemInfo(info, i, pkgSetting);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
// TODO(b/135203078): Determine if permission methods need to pass in a non-null PackageSetting
|
||||
// os that checkUseInstalledOrHidden filter can apply
|
||||
@Nullable
|
||||
public static PermissionInfo generatePermissionInfo(ParsedPermission p,
|
||||
@PackageManager.ComponentInfoFlags int flags) {
|
||||
// TODO(b/135203078): Remove null checks and make all usages @NonNull
|
||||
if (p == null) return null;
|
||||
|
||||
// For now, permissions don't have state-adjustable fields; return directly
|
||||
return PackageInfoWithoutStateUtils.generatePermissionInfo(p, flags);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PermissionGroupInfo generatePermissionGroupInfo(ParsedPermissionGroup pg,
|
||||
@PackageManager.ComponentInfoFlags int flags) {
|
||||
if (pg == null) return null;
|
||||
|
||||
// For now, permissions don't have state-adjustable fields; return directly
|
||||
return PackageInfoWithoutStateUtils.generatePermissionGroupInfo(pg, flags);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ArrayMap<String, ProcessInfo> generateProcessInfo(
|
||||
Map<String, ParsedProcess> procs, @PackageManager.ComponentInfoFlags int flags) {
|
||||
if (procs == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final int numProcs = procs.size();
|
||||
ArrayMap<String, ProcessInfo> retProcs = new ArrayMap<>(numProcs);
|
||||
for (String key : procs.keySet()) {
|
||||
ParsedProcess proc = procs.get(key);
|
||||
retProcs.put(proc.name, new ProcessInfo(proc.name,
|
||||
proc.deniedPermissions != null
|
||||
? new ArraySet<>(proc.deniedPermissions) : null));
|
||||
}
|
||||
return retProcs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the package is installed and not hidden, or if the caller
|
||||
* explicitly wanted all uninstalled and hidden packages as well.
|
||||
*/
|
||||
private static boolean checkUseInstalledOrHidden(AndroidPackage pkg,
|
||||
PackageSetting pkgSetting, PackageUserState state,
|
||||
@PackageManager.PackageInfoFlags int flags) {
|
||||
// Returns false if the package is hidden system app until installed.
|
||||
if ((flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) == 0
|
||||
&& !state.installed
|
||||
&& pkg.isHiddenUntilInstalled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If available for the target user, or trying to match uninstalled packages and it's
|
||||
// a system app.
|
||||
return state.isAvailable(flags)
|
||||
|| (pkg.isSystem()
|
||||
&& ((flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0
|
||||
|| (flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) != 0));
|
||||
}
|
||||
|
||||
private static void assignSharedFieldsForComponentInfo(@NonNull ComponentInfo componentInfo,
|
||||
@NonNull ParsedMainComponent mainComponent, @Nullable PackageSetting pkgSetting) {
|
||||
assignStateFieldsForPackageItemInfo(componentInfo, mainComponent, pkgSetting);
|
||||
componentInfo.descriptionRes = mainComponent.descriptionRes;
|
||||
componentInfo.directBootAware = mainComponent.isDirectBootAware();
|
||||
componentInfo.enabled = mainComponent.isEnabled();
|
||||
componentInfo.splitName = mainComponent.getSplitName();
|
||||
}
|
||||
|
||||
private static void assignStateFieldsForPackageItemInfo(
|
||||
@NonNull PackageItemInfo packageItemInfo, @NonNull ParsedComponent component,
|
||||
@Nullable PackageSetting pkgSetting) {
|
||||
// TODO(b/135203078): Add setting related state
|
||||
}
|
||||
|
||||
@CheckResult
|
||||
private static int flag(boolean hasFlag, int flag) {
|
||||
return hasFlag ? flag : 0;
|
||||
}
|
||||
|
||||
/** @see ApplicationInfo#flags */
|
||||
public static int appInfoFlags(AndroidPackage pkg, @Nullable PackageSetting pkgSetting) {
|
||||
// TODO(b/135203078): Add setting related state
|
||||
// @formatter:off
|
||||
return PackageInfoWithoutStateUtils.appInfoFlags(pkg)
|
||||
| flag(pkg.isSystem(), ApplicationInfo.FLAG_SYSTEM)
|
||||
| flag(pkg.isFactoryTest(), ApplicationInfo.FLAG_FACTORY_TEST)
|
||||
| flag(pkg.isUpdatedSystemApp(), ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
/** @see ApplicationInfo#privateFlags */
|
||||
public static int appInfoPrivateFlags(AndroidPackage pkg, @Nullable PackageSetting pkgSetting) {
|
||||
// TODO(b/135203078): Add setting related state
|
||||
// @formatter:off
|
||||
return PackageInfoWithoutStateUtils.appInfoPrivateFlags(pkg)
|
||||
| flag(pkg.isSystemExt(), ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT)
|
||||
| flag(pkg.isPrivileged(), ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
|
||||
| flag(pkg.isOem(), ApplicationInfo.PRIVATE_FLAG_OEM)
|
||||
| flag(pkg.isVendor(), ApplicationInfo.PRIVATE_FLAG_VENDOR)
|
||||
| flag(pkg.isProduct(), ApplicationInfo.PRIVATE_FLAG_PRODUCT)
|
||||
| flag(pkg.isOdm(), ApplicationInfo.PRIVATE_FLAG_ODM)
|
||||
| flag(pkg.isSignedWithPlatformKey(), ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY);
|
||||
// @formatter:on
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.pm.parsing;
|
||||
|
||||
import android.annotation.AnyThread;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.pm.PackageParser;
|
||||
import android.content.pm.parsing.ParsingPackage;
|
||||
import android.content.pm.parsing.ParsingPackageUtils;
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.Build;
|
||||
import android.os.SystemClock;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.server.pm.parsing.pkg.PackageImpl;
|
||||
import com.android.server.pm.parsing.pkg.ParsedPackage;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* The v2 of {@link PackageParser} for use when parsing is initiated in the server and must
|
||||
* contain state contained by the server.
|
||||
*/
|
||||
public class PackageParser2 {
|
||||
|
||||
private static final String TAG = "PackageParser2";
|
||||
|
||||
private static final boolean LOG_PARSE_TIMINGS = Build.IS_DEBUGGABLE;
|
||||
private static final int LOG_PARSE_TIMINGS_THRESHOLD_MS = 100;
|
||||
|
||||
private ThreadLocal<ParsingPackageUtils.ParseResult> mSharedResult = ThreadLocal.withInitial(
|
||||
ParsingPackageUtils.ParseResult::new);
|
||||
|
||||
private final String[] mSeparateProcesses;
|
||||
private final boolean mOnlyCoreApps;
|
||||
private final DisplayMetrics mDisplayMetrics;
|
||||
private final Callback mCallback;
|
||||
|
||||
@Nullable
|
||||
protected PackageCacher mCacher;
|
||||
|
||||
/**
|
||||
* @param onlyCoreApps Flag indicating this parser should only consider apps with
|
||||
* {@code coreApp} manifest attribute to be valid apps. This is useful when
|
||||
* creating a minimalist boot environment.
|
||||
*/
|
||||
public PackageParser2(String[] separateProcesses, boolean onlyCoreApps,
|
||||
DisplayMetrics displayMetrics, @Nullable File cacheDir, Callback callback) {
|
||||
mSeparateProcesses = separateProcesses;
|
||||
mOnlyCoreApps = onlyCoreApps;
|
||||
|
||||
if (displayMetrics == null) {
|
||||
mDisplayMetrics = new DisplayMetrics();
|
||||
mDisplayMetrics.setToDefaults();
|
||||
} else {
|
||||
mDisplayMetrics = displayMetrics;
|
||||
}
|
||||
|
||||
mCacher = cacheDir == null ? null : new PackageCacher(cacheDir);
|
||||
// TODO(b/135203078): Remove nullability of callback
|
||||
mCallback = callback != null ? callback : new Callback() {
|
||||
@Override
|
||||
public boolean hasFeature(String feature) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO(b/135203078): Document new package parsing
|
||||
*/
|
||||
@AnyThread
|
||||
public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches)
|
||||
throws PackageParser.PackageParserException {
|
||||
if (useCaches && mCacher != null) {
|
||||
ParsedPackage parsed = mCacher.getCachedResult(packageFile, flags);
|
||||
if (parsed != null) {
|
||||
return parsed;
|
||||
}
|
||||
}
|
||||
|
||||
long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
|
||||
ParsingPackageUtils.ParseInput parseInput = mSharedResult.get().reset();
|
||||
ParsedPackage parsed = (ParsedPackage) ParsingPackageUtils.parsePackage(parseInput,
|
||||
mSeparateProcesses, mCallback, mDisplayMetrics, mOnlyCoreApps, packageFile, flags)
|
||||
.hideAsParsed();
|
||||
|
||||
long cacheTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
|
||||
if (mCacher != null) {
|
||||
mCacher.cacheResult(packageFile, flags, parsed);
|
||||
}
|
||||
if (LOG_PARSE_TIMINGS) {
|
||||
parseTime = cacheTime - parseTime;
|
||||
cacheTime = SystemClock.uptimeMillis() - cacheTime;
|
||||
if (parseTime + cacheTime > LOG_PARSE_TIMINGS_THRESHOLD_MS) {
|
||||
Slog.i(TAG, "Parse times for '" + packageFile + "': parse=" + parseTime
|
||||
+ "ms, update_cache=" + cacheTime + " ms");
|
||||
}
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
public static abstract class Callback implements ParsingPackageUtils.Callback {
|
||||
|
||||
@Override
|
||||
public final ParsingPackage startParsingPackage(String packageName, String baseCodePath,
|
||||
String codePath, TypedArray manifestArray, boolean isCoreApp) {
|
||||
return PackageImpl.forParsing(packageName, baseCodePath, codePath, manifestArray,
|
||||
isCoreApp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -187,7 +187,7 @@ public interface AndroidPackage extends PkgAppInfo, PkgPackageInfo, ParsingPacka
|
||||
@NonNull
|
||||
List<ParsedPermissionGroup> getPermissionGroups();
|
||||
|
||||
@Nullable
|
||||
@NonNull
|
||||
List<ParsedFeature> getFeatures();
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user