Merge changes from topic "apks_in_apex"
* changes: PackageAbiHepler no longer modifies Package Adds scan unit tests
This commit is contained in:
@@ -22,11 +22,11 @@ import android.os.SystemProperties;
|
|||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
|
|
||||||
|
import dalvik.system.VMRuntime;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import dalvik.system.VMRuntime;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides various methods for obtaining and converting of instruction sets.
|
* Provides various methods for obtaining and converting of instruction sets.
|
||||||
*
|
*
|
||||||
@@ -113,12 +113,15 @@ public class InstructionSets {
|
|||||||
return allInstructionSets;
|
return allInstructionSets;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getPrimaryInstructionSet(ApplicationInfo info) {
|
/**
|
||||||
if (info.primaryCpuAbi == null) {
|
* Calculates the primary instruction set based on the computed Abis of a given package.
|
||||||
|
*/
|
||||||
|
public static String getPrimaryInstructionSet(PackageAbiHelper.Abis abis) {
|
||||||
|
if (abis.primary == null) {
|
||||||
return getPreferredInstructionSet();
|
return getPreferredInstructionSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
return VMRuntime.getInstructionSet(info.primaryCpuAbi);
|
return VMRuntime.getInstructionSet(abis.primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
135
services/core/java/com/android/server/pm/PackageAbiHelper.java
Normal file
135
services/core/java/com/android/server/pm/PackageAbiHelper.java
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
* 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 com.android.server.pm;
|
||||||
|
|
||||||
|
import android.annotation.Nullable;
|
||||||
|
import android.content.pm.PackageParser;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
interface PackageAbiHelper {
|
||||||
|
/**
|
||||||
|
* Derive and get the location of native libraries for the given package,
|
||||||
|
* which varies depending on where and how the package was installed.
|
||||||
|
*/
|
||||||
|
NativeLibraryPaths getNativeLibraryPaths(
|
||||||
|
PackageParser.Package pkg, File appLib32InstallDir);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the abis for a bundled app. These can uniquely be determined from the contents of
|
||||||
|
* the system partition, i.e whether it contains 64 or 32 bit shared libraries etc. We do not
|
||||||
|
* validate any of this information, and instead assume that the system was built sensibly.
|
||||||
|
*/
|
||||||
|
Abis getBundledAppAbis(PackageParser.Package pkg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derive the ABI of a non-system package located at {@code pkg}. This information
|
||||||
|
* is derived purely on the basis of the contents of {@code pkg} and {@code cpuAbiOverride}.
|
||||||
|
*
|
||||||
|
* If {@code extractLibs} is true, native libraries are extracted from the app if required.
|
||||||
|
*/
|
||||||
|
Pair<Abis, NativeLibraryPaths> derivePackageAbi(
|
||||||
|
PackageParser.Package pkg, String cpuAbiOverride, boolean extractLibs)
|
||||||
|
throws PackageManagerException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates adjusted ABIs for a set of packages belonging to a shared user so that they all
|
||||||
|
* match. i.e, so that all packages can be run inside a single process if required.
|
||||||
|
*
|
||||||
|
* Optionally, callers can pass in a parsed package via {@code scannedPackage} in which case
|
||||||
|
* this function will either try and make the ABI for all packages in
|
||||||
|
* {@code packagesForUser} match {@code scannedPackage} or will update the ABI of
|
||||||
|
* {@code scannedPackage} to match the ABI selected for {@code packagesForUser}. This
|
||||||
|
* variant is used when installing or updating a package that belongs to a shared user.
|
||||||
|
*
|
||||||
|
* NOTE: We currently only match for the primary CPU abi string. Matching the secondary
|
||||||
|
* adds unnecessary complexity.
|
||||||
|
*
|
||||||
|
* @return the calculated primary abi that should be set for all non-specified packages
|
||||||
|
* belonging to the shared user.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
String getAdjustedAbiForSharedUser(
|
||||||
|
Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The native library paths and related properties that should be set on a
|
||||||
|
* {@link android.content.pm.PackageParser.Package}.
|
||||||
|
*/
|
||||||
|
final class NativeLibraryPaths {
|
||||||
|
public final String nativeLibraryRootDir;
|
||||||
|
public final boolean nativeLibraryRootRequiresIsa;
|
||||||
|
public final String nativeLibraryDir;
|
||||||
|
public final String secondaryNativeLibraryDir;
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
NativeLibraryPaths(String nativeLibraryRootDir,
|
||||||
|
boolean nativeLibraryRootRequiresIsa, String nativeLibraryDir,
|
||||||
|
String secondaryNativeLibraryDir) {
|
||||||
|
this.nativeLibraryRootDir = nativeLibraryRootDir;
|
||||||
|
this.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa;
|
||||||
|
this.nativeLibraryDir = nativeLibraryDir;
|
||||||
|
this.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void applyTo(PackageParser.Package pkg) {
|
||||||
|
pkg.applicationInfo.nativeLibraryRootDir = nativeLibraryRootDir;
|
||||||
|
pkg.applicationInfo.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa;
|
||||||
|
pkg.applicationInfo.nativeLibraryDir = nativeLibraryDir;
|
||||||
|
pkg.applicationInfo.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The primary and secondary ABIs that should be set on a package and its package setting.
|
||||||
|
*/
|
||||||
|
final class Abis {
|
||||||
|
public final String primary;
|
||||||
|
public final String secondary;
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
Abis(String primary, String secondary) {
|
||||||
|
this.primary = primary;
|
||||||
|
this.secondary = secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
Abis(PackageParser.Package pkg) {
|
||||||
|
this(pkg.applicationInfo.primaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void applyTo(PackageParser.Package pkg) {
|
||||||
|
pkg.applicationInfo.primaryCpuAbi = primary;
|
||||||
|
pkg.applicationInfo.secondaryCpuAbi = secondary;
|
||||||
|
}
|
||||||
|
public void applyTo(PackageSetting pkgSetting) {
|
||||||
|
// pkgSetting might be null during rescan following uninstall of updates
|
||||||
|
// to a bundled app, so accommodate that possibility. The settings in
|
||||||
|
// that case will be established later from the parsed package.
|
||||||
|
//
|
||||||
|
// If the settings aren't null, sync them up with what we've derived.
|
||||||
|
if (pkgSetting != null) {
|
||||||
|
pkgSetting.primaryCpuAbiString = primary;
|
||||||
|
pkgSetting.secondaryCpuAbiString = secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,528 @@
|
|||||||
|
/*
|
||||||
|
* 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 com.android.server.pm;
|
||||||
|
|
||||||
|
import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
|
||||||
|
import static android.content.pm.PackageParser.isApkFile;
|
||||||
|
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
|
||||||
|
|
||||||
|
import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME;
|
||||||
|
import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
|
||||||
|
import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
|
||||||
|
import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
|
||||||
|
|
||||||
|
import android.annotation.Nullable;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.pm.PackageParser;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.os.FileUtils;
|
||||||
|
import android.os.Trace;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.Pair;
|
||||||
|
import android.util.Slog;
|
||||||
|
|
||||||
|
import com.android.internal.content.NativeLibraryHelper;
|
||||||
|
import com.android.internal.util.ArrayUtils;
|
||||||
|
|
||||||
|
import dalvik.system.VMRuntime;
|
||||||
|
|
||||||
|
import libcore.io.IoUtils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
final class PackageAbiHelperImpl implements PackageAbiHelper {
|
||||||
|
|
||||||
|
private static String calculateBundledApkRoot(final String codePathString) {
|
||||||
|
final File codePath = new File(codePathString);
|
||||||
|
final File codeRoot;
|
||||||
|
if (FileUtils.contains(Environment.getRootDirectory(), codePath)) {
|
||||||
|
codeRoot = Environment.getRootDirectory();
|
||||||
|
} else if (FileUtils.contains(Environment.getOemDirectory(), codePath)) {
|
||||||
|
codeRoot = Environment.getOemDirectory();
|
||||||
|
} else if (FileUtils.contains(Environment.getVendorDirectory(), codePath)) {
|
||||||
|
codeRoot = Environment.getVendorDirectory();
|
||||||
|
} else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
|
||||||
|
codeRoot = Environment.getOdmDirectory();
|
||||||
|
} else if (FileUtils.contains(Environment.getProductDirectory(), codePath)) {
|
||||||
|
codeRoot = Environment.getProductDirectory();
|
||||||
|
} else if (FileUtils.contains(Environment.getSystemExtDirectory(), codePath)) {
|
||||||
|
codeRoot = Environment.getSystemExtDirectory();
|
||||||
|
} else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
|
||||||
|
codeRoot = Environment.getOdmDirectory();
|
||||||
|
} else {
|
||||||
|
// Unrecognized code path; take its top real segment as the apk root:
|
||||||
|
// e.g. /something/app/blah.apk => /something
|
||||||
|
try {
|
||||||
|
File f = codePath.getCanonicalFile();
|
||||||
|
File parent = f.getParentFile(); // non-null because codePath is a file
|
||||||
|
File tmp;
|
||||||
|
while ((tmp = parent.getParentFile()) != null) {
|
||||||
|
f = parent;
|
||||||
|
parent = tmp;
|
||||||
|
}
|
||||||
|
codeRoot = f;
|
||||||
|
Slog.w(PackageManagerService.TAG, "Unrecognized code path "
|
||||||
|
+ codePath + " - using " + codeRoot);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// Can't canonicalize the code path -- shenanigans?
|
||||||
|
Slog.w(PackageManagerService.TAG, "Can't canonicalize code path " + codePath);
|
||||||
|
return Environment.getRootDirectory().getPath();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return codeRoot.getPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utility method that returns the relative package path with respect
|
||||||
|
// to the installation directory. Like say for /data/data/com.test-1.apk
|
||||||
|
// string com.test-1 is returned.
|
||||||
|
private static String deriveCodePathName(String codePath) {
|
||||||
|
if (codePath == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final File codeFile = new File(codePath);
|
||||||
|
final String name = codeFile.getName();
|
||||||
|
if (codeFile.isDirectory()) {
|
||||||
|
return name;
|
||||||
|
} else if (name.endsWith(".apk") || name.endsWith(".tmp")) {
|
||||||
|
final int lastDot = name.lastIndexOf('.');
|
||||||
|
return name.substring(0, lastDot);
|
||||||
|
} else {
|
||||||
|
Slog.w(PackageManagerService.TAG, "Odd, " + codePath + " doesn't look like an APK");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void maybeThrowExceptionForMultiArchCopy(String message, int copyRet) throws
|
||||||
|
PackageManagerException {
|
||||||
|
if (copyRet < 0) {
|
||||||
|
if (copyRet != PackageManager.NO_NATIVE_LIBRARIES
|
||||||
|
&& copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
|
||||||
|
throw new PackageManagerException(copyRet, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NativeLibraryPaths getNativeLibraryPaths(
|
||||||
|
PackageParser.Package pkg, File appLib32InstallDir) {
|
||||||
|
return getNativeLibraryPaths(new Abis(pkg), appLib32InstallDir, pkg.codePath,
|
||||||
|
pkg.applicationInfo.sourceDir, pkg.applicationInfo.isSystemApp(),
|
||||||
|
pkg.applicationInfo.isUpdatedSystemApp());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static NativeLibraryPaths getNativeLibraryPaths(final Abis abis,
|
||||||
|
final File appLib32InstallDir, final String codePath, final String sourceDir,
|
||||||
|
final boolean isSystemApp, final boolean isUpdatedSystemApp) {
|
||||||
|
final File codeFile = new File(codePath);
|
||||||
|
final boolean bundledApp = isSystemApp && !isUpdatedSystemApp;
|
||||||
|
|
||||||
|
final String nativeLibraryRootDir;
|
||||||
|
final boolean nativeLibraryRootRequiresIsa;
|
||||||
|
final String nativeLibraryDir;
|
||||||
|
final String secondaryNativeLibraryDir;
|
||||||
|
|
||||||
|
if (isApkFile(codeFile)) {
|
||||||
|
// Monolithic install
|
||||||
|
if (bundledApp) {
|
||||||
|
// If "/system/lib64/apkname" exists, assume that is the per-package
|
||||||
|
// native library directory to use; otherwise use "/system/lib/apkname".
|
||||||
|
final String apkRoot = calculateBundledApkRoot(sourceDir);
|
||||||
|
final boolean is64Bit = VMRuntime.is64BitInstructionSet(
|
||||||
|
getPrimaryInstructionSet(abis));
|
||||||
|
|
||||||
|
// This is a bundled system app so choose the path based on the ABI.
|
||||||
|
// if it's a 64 bit abi, use lib64 otherwise use lib32. Note that this
|
||||||
|
// is just the default path.
|
||||||
|
final String apkName = deriveCodePathName(codePath);
|
||||||
|
final String libDir = is64Bit ? LIB64_DIR_NAME : LIB_DIR_NAME;
|
||||||
|
nativeLibraryRootDir = Environment.buildPath(new File(apkRoot), libDir,
|
||||||
|
apkName).getAbsolutePath();
|
||||||
|
|
||||||
|
if (abis.secondary != null) {
|
||||||
|
final String secondaryLibDir = is64Bit ? LIB_DIR_NAME : LIB64_DIR_NAME;
|
||||||
|
secondaryNativeLibraryDir = Environment.buildPath(new File(apkRoot),
|
||||||
|
secondaryLibDir, apkName).getAbsolutePath();
|
||||||
|
} else {
|
||||||
|
secondaryNativeLibraryDir = null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
final String apkName = deriveCodePathName(codePath);
|
||||||
|
nativeLibraryRootDir = new File(appLib32InstallDir, apkName)
|
||||||
|
.getAbsolutePath();
|
||||||
|
secondaryNativeLibraryDir = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
nativeLibraryRootRequiresIsa = false;
|
||||||
|
nativeLibraryDir = nativeLibraryRootDir;
|
||||||
|
} else {
|
||||||
|
// Cluster install
|
||||||
|
nativeLibraryRootDir = new File(codeFile, LIB_DIR_NAME).getAbsolutePath();
|
||||||
|
nativeLibraryRootRequiresIsa = true;
|
||||||
|
|
||||||
|
nativeLibraryDir = new File(nativeLibraryRootDir,
|
||||||
|
getPrimaryInstructionSet(abis)).getAbsolutePath();
|
||||||
|
|
||||||
|
if (abis.secondary != null) {
|
||||||
|
secondaryNativeLibraryDir = new File(nativeLibraryRootDir,
|
||||||
|
VMRuntime.getInstructionSet(abis.secondary)).getAbsolutePath();
|
||||||
|
} else {
|
||||||
|
secondaryNativeLibraryDir = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new NativeLibraryPaths(nativeLibraryRootDir, nativeLibraryRootRequiresIsa,
|
||||||
|
nativeLibraryDir, secondaryNativeLibraryDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Abis getBundledAppAbis(PackageParser.Package pkg) {
|
||||||
|
final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath());
|
||||||
|
|
||||||
|
// If "/system/lib64/apkname" exists, assume that is the per-package
|
||||||
|
// native library directory to use; otherwise use "/system/lib/apkname".
|
||||||
|
final String apkRoot = calculateBundledApkRoot(pkg.applicationInfo.sourceDir);
|
||||||
|
final Abis abis = getBundledAppAbi(pkg, apkRoot, apkName);
|
||||||
|
return abis;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deduces the ABI of a bundled app and sets the relevant fields on the
|
||||||
|
* parsed pkg object.
|
||||||
|
*
|
||||||
|
* @param apkRoot the root of the installed apk, something like {@code /system} or
|
||||||
|
* {@code /oem} under which system libraries are installed.
|
||||||
|
* @param apkName the name of the installed package.
|
||||||
|
*/
|
||||||
|
private Abis getBundledAppAbi(PackageParser.Package pkg, String apkRoot, String apkName) {
|
||||||
|
final File codeFile = new File(pkg.codePath);
|
||||||
|
|
||||||
|
final boolean has64BitLibs;
|
||||||
|
final boolean has32BitLibs;
|
||||||
|
|
||||||
|
final String primaryCpuAbi;
|
||||||
|
final String secondaryCpuAbi;
|
||||||
|
if (isApkFile(codeFile)) {
|
||||||
|
// Monolithic install
|
||||||
|
has64BitLibs =
|
||||||
|
(new File(apkRoot, new File(LIB64_DIR_NAME, apkName).getPath())).exists();
|
||||||
|
has32BitLibs = (new File(apkRoot, new File(LIB_DIR_NAME, apkName).getPath())).exists();
|
||||||
|
} else {
|
||||||
|
// Cluster install
|
||||||
|
final File rootDir = new File(codeFile, LIB_DIR_NAME);
|
||||||
|
if (!ArrayUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS)
|
||||||
|
&& !TextUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS[0])) {
|
||||||
|
final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_64_BIT_ABIS[0]);
|
||||||
|
has64BitLibs = (new File(rootDir, isa)).exists();
|
||||||
|
} else {
|
||||||
|
has64BitLibs = false;
|
||||||
|
}
|
||||||
|
if (!ArrayUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS)
|
||||||
|
&& !TextUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS[0])) {
|
||||||
|
final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_32_BIT_ABIS[0]);
|
||||||
|
has32BitLibs = (new File(rootDir, isa)).exists();
|
||||||
|
} else {
|
||||||
|
has32BitLibs = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has64BitLibs && !has32BitLibs) {
|
||||||
|
// The package has 64 bit libs, but not 32 bit libs. Its primary
|
||||||
|
// ABI should be 64 bit. We can safely assume here that the bundled
|
||||||
|
// native libraries correspond to the most preferred ABI in the list.
|
||||||
|
|
||||||
|
primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
|
||||||
|
secondaryCpuAbi = null;
|
||||||
|
} else if (has32BitLibs && !has64BitLibs) {
|
||||||
|
// The package has 32 bit libs but not 64 bit libs. Its primary
|
||||||
|
// ABI should be 32 bit.
|
||||||
|
|
||||||
|
primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
|
||||||
|
secondaryCpuAbi = null;
|
||||||
|
} else if (has32BitLibs && has64BitLibs) {
|
||||||
|
// The application has both 64 and 32 bit bundled libraries. We check
|
||||||
|
// here that the app declares multiArch support, and warn if it doesn't.
|
||||||
|
//
|
||||||
|
// We will be lenient here and record both ABIs. The primary will be the
|
||||||
|
// ABI that's higher on the list, i.e, a device that's configured to prefer
|
||||||
|
// 64 bit apps will see a 64 bit primary ABI,
|
||||||
|
|
||||||
|
if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) == 0) {
|
||||||
|
Slog.e(PackageManagerService.TAG,
|
||||||
|
"Package " + pkg + " has multiple bundled libs, but is not multiarch.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VMRuntime.is64BitInstructionSet(getPreferredInstructionSet())) {
|
||||||
|
primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
|
||||||
|
secondaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
|
||||||
|
} else {
|
||||||
|
primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
|
||||||
|
secondaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
primaryCpuAbi = null;
|
||||||
|
secondaryCpuAbi = null;
|
||||||
|
}
|
||||||
|
return new Abis(primaryCpuAbi, secondaryCpuAbi);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Pair<Abis, NativeLibraryPaths> derivePackageAbi(
|
||||||
|
PackageParser.Package pkg, String cpuAbiOverride, boolean extractLibs)
|
||||||
|
throws PackageManagerException {
|
||||||
|
// Give ourselves some initial paths; we'll come back for another
|
||||||
|
// pass once we've determined ABI below.
|
||||||
|
final NativeLibraryPaths initialLibraryPaths = getNativeLibraryPaths(new Abis(pkg),
|
||||||
|
PackageManagerService.sAppLib32InstallDir, pkg.codePath,
|
||||||
|
pkg.applicationInfo.sourceDir, pkg.applicationInfo.isSystemApp(),
|
||||||
|
pkg.applicationInfo.isUpdatedSystemApp());
|
||||||
|
|
||||||
|
// We shouldn't attempt to extract libs from system app when it was not updated.
|
||||||
|
if (PackageManagerService.isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) {
|
||||||
|
extractLibs = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String nativeLibraryRootStr = initialLibraryPaths.nativeLibraryRootDir;
|
||||||
|
final boolean useIsaSpecificSubdirs = initialLibraryPaths.nativeLibraryRootRequiresIsa;
|
||||||
|
|
||||||
|
String primaryCpuAbi = null;
|
||||||
|
String secondaryCpuAbi = null;
|
||||||
|
|
||||||
|
NativeLibraryHelper.Handle handle = null;
|
||||||
|
try {
|
||||||
|
handle = NativeLibraryHelper.Handle.create(pkg);
|
||||||
|
// TODO(multiArch): This can be null for apps that didn't go through the
|
||||||
|
// usual installation process. We can calculate it again, like we
|
||||||
|
// do during install time.
|
||||||
|
//
|
||||||
|
// TODO(multiArch): Why do we need to rescan ASEC apps again ? It seems totally
|
||||||
|
// unnecessary.
|
||||||
|
final File nativeLibraryRoot = new File(nativeLibraryRootStr);
|
||||||
|
|
||||||
|
// Null out the abis so that they can be recalculated.
|
||||||
|
primaryCpuAbi = null;
|
||||||
|
secondaryCpuAbi = null;
|
||||||
|
if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0) {
|
||||||
|
// Warn if we've set an abiOverride for multi-lib packages..
|
||||||
|
// By definition, we need to copy both 32 and 64 bit libraries for
|
||||||
|
// such packages.
|
||||||
|
if (pkg.cpuAbiOverride != null
|
||||||
|
&& !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(pkg.cpuAbiOverride)) {
|
||||||
|
Slog.w(PackageManagerService.TAG,
|
||||||
|
"Ignoring abiOverride for multi arch application.");
|
||||||
|
}
|
||||||
|
|
||||||
|
int abi32 = PackageManager.NO_NATIVE_LIBRARIES;
|
||||||
|
int abi64 = PackageManager.NO_NATIVE_LIBRARIES;
|
||||||
|
if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
|
||||||
|
if (extractLibs) {
|
||||||
|
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
|
||||||
|
abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
|
||||||
|
nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS,
|
||||||
|
useIsaSpecificSubdirs);
|
||||||
|
} else {
|
||||||
|
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
|
||||||
|
abi32 = NativeLibraryHelper.findSupportedAbi(
|
||||||
|
handle, Build.SUPPORTED_32_BIT_ABIS);
|
||||||
|
}
|
||||||
|
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shared library native code should be in the APK zip aligned
|
||||||
|
if (abi32 >= 0 && pkg.isLibrary() && extractLibs) {
|
||||||
|
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
|
||||||
|
"Shared library native lib extraction not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
maybeThrowExceptionForMultiArchCopy(
|
||||||
|
"Error unpackaging 32 bit native libs for multiarch app.", abi32);
|
||||||
|
|
||||||
|
if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
|
||||||
|
if (extractLibs) {
|
||||||
|
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
|
||||||
|
abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
|
||||||
|
nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS,
|
||||||
|
useIsaSpecificSubdirs);
|
||||||
|
} else {
|
||||||
|
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
|
||||||
|
abi64 = NativeLibraryHelper.findSupportedAbi(
|
||||||
|
handle, Build.SUPPORTED_64_BIT_ABIS);
|
||||||
|
}
|
||||||
|
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
|
||||||
|
}
|
||||||
|
|
||||||
|
maybeThrowExceptionForMultiArchCopy(
|
||||||
|
"Error unpackaging 64 bit native libs for multiarch app.", abi64);
|
||||||
|
|
||||||
|
if (abi64 >= 0) {
|
||||||
|
// Shared library native libs should be in the APK zip aligned
|
||||||
|
if (extractLibs && pkg.isLibrary()) {
|
||||||
|
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
|
||||||
|
"Shared library native lib extraction not supported");
|
||||||
|
}
|
||||||
|
primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[abi64];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (abi32 >= 0) {
|
||||||
|
final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32];
|
||||||
|
if (abi64 >= 0) {
|
||||||
|
if (pkg.use32bitAbi) {
|
||||||
|
secondaryCpuAbi = primaryCpuAbi;
|
||||||
|
primaryCpuAbi = abi;
|
||||||
|
} else {
|
||||||
|
secondaryCpuAbi = abi;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
primaryCpuAbi = abi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String[] abiList = (cpuAbiOverride != null)
|
||||||
|
? new String[]{cpuAbiOverride} : Build.SUPPORTED_ABIS;
|
||||||
|
|
||||||
|
// Enable gross and lame hacks for apps that are built with old
|
||||||
|
// SDK tools. We must scan their APKs for renderscript bitcode and
|
||||||
|
// not launch them if it's present. Don't bother checking on devices
|
||||||
|
// that don't have 64 bit support.
|
||||||
|
boolean needsRenderScriptOverride = false;
|
||||||
|
if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null
|
||||||
|
&& NativeLibraryHelper.hasRenderscriptBitcode(handle)) {
|
||||||
|
abiList = Build.SUPPORTED_32_BIT_ABIS;
|
||||||
|
needsRenderScriptOverride = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int copyRet;
|
||||||
|
if (extractLibs) {
|
||||||
|
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
|
||||||
|
copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
|
||||||
|
nativeLibraryRoot, abiList, useIsaSpecificSubdirs);
|
||||||
|
} else {
|
||||||
|
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
|
||||||
|
copyRet = NativeLibraryHelper.findSupportedAbi(handle, abiList);
|
||||||
|
}
|
||||||
|
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
|
||||||
|
|
||||||
|
if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
|
||||||
|
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
|
||||||
|
"Error unpackaging native libs for app, errorCode=" + copyRet);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (copyRet >= 0) {
|
||||||
|
// Shared libraries that have native libs must be multi-architecture
|
||||||
|
if (pkg.isLibrary()) {
|
||||||
|
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
|
||||||
|
"Shared library with native libs must be multiarch");
|
||||||
|
}
|
||||||
|
primaryCpuAbi = abiList[copyRet];
|
||||||
|
} else if (copyRet == PackageManager.NO_NATIVE_LIBRARIES
|
||||||
|
&& cpuAbiOverride != null) {
|
||||||
|
primaryCpuAbi = cpuAbiOverride;
|
||||||
|
} else if (needsRenderScriptOverride) {
|
||||||
|
primaryCpuAbi = abiList[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
Slog.e(PackageManagerService.TAG, "Unable to get canonical file " + ioe.toString());
|
||||||
|
} finally {
|
||||||
|
IoUtils.closeQuietly(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that we've calculated the ABIs and determined if it's an internal app,
|
||||||
|
// we will go ahead and populate the nativeLibraryPath.
|
||||||
|
|
||||||
|
final Abis abis = new Abis(primaryCpuAbi, secondaryCpuAbi);
|
||||||
|
return new Pair<>(abis,
|
||||||
|
getNativeLibraryPaths(abis, PackageManagerService.sAppLib32InstallDir,
|
||||||
|
pkg.codePath, pkg.applicationInfo.sourceDir,
|
||||||
|
pkg.applicationInfo.isSystemApp(),
|
||||||
|
pkg.applicationInfo.isUpdatedSystemApp()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjusts ABIs for a set of packages belonging to a shared user so that they all match.
|
||||||
|
* i.e, so that all packages can be run inside a single process if required.
|
||||||
|
*
|
||||||
|
* Optionally, callers can pass in a parsed package via {@code newPackage} in which case
|
||||||
|
* this function will either try and make the ABI for all packages in
|
||||||
|
* {@code packagesForUser} match {@code scannedPackage} or will update the ABI of
|
||||||
|
* {@code scannedPackage} to match the ABI selected for {@code packagesForUser}. This
|
||||||
|
* variant is used when installing or updating a package that belongs to a shared user.
|
||||||
|
*
|
||||||
|
* NOTE: We currently only match for the primary CPU abi string. Matching the secondary
|
||||||
|
* adds unnecessary complexity.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public String getAdjustedAbiForSharedUser(
|
||||||
|
Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage) {
|
||||||
|
String requiredInstructionSet = null;
|
||||||
|
if (scannedPackage != null && scannedPackage.applicationInfo.primaryCpuAbi != null) {
|
||||||
|
requiredInstructionSet = VMRuntime.getInstructionSet(
|
||||||
|
scannedPackage.applicationInfo.primaryCpuAbi);
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageSetting requirer = null;
|
||||||
|
for (PackageSetting ps : packagesForUser) {
|
||||||
|
// If packagesForUser contains scannedPackage, we skip it. This will happen
|
||||||
|
// when scannedPackage is an update of an existing package. Without this check,
|
||||||
|
// we will never be able to change the ABI of any package belonging to a shared
|
||||||
|
// user, even if it's compatible with other packages.
|
||||||
|
if (scannedPackage != null && scannedPackage.packageName.equals(ps.name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ps.primaryCpuAbiString == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String instructionSet =
|
||||||
|
VMRuntime.getInstructionSet(ps.primaryCpuAbiString);
|
||||||
|
if (requiredInstructionSet != null && !requiredInstructionSet.equals(instructionSet)) {
|
||||||
|
// We have a mismatch between instruction sets (say arm vs arm64) warn about
|
||||||
|
// this but there's not much we can do.
|
||||||
|
String errorMessage = "Instruction set mismatch, "
|
||||||
|
+ ((requirer == null) ? "[caller]" : requirer)
|
||||||
|
+ " requires " + requiredInstructionSet + " whereas " + ps
|
||||||
|
+ " requires " + instructionSet;
|
||||||
|
Slog.w(PackageManagerService.TAG, errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requiredInstructionSet == null) {
|
||||||
|
requiredInstructionSet = instructionSet;
|
||||||
|
requirer = ps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requiredInstructionSet == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final String adjustedAbi;
|
||||||
|
if (requirer != null) {
|
||||||
|
// requirer != null implies that either scannedPackage was null or that
|
||||||
|
// scannedPackage did not require an ABI, in which case we have to adjust
|
||||||
|
// scannedPackage to match the ABI of the set (which is the same as
|
||||||
|
// requirer's ABI)
|
||||||
|
adjustedAbi = requirer.primaryCpuAbiString;
|
||||||
|
} else {
|
||||||
|
// requirer == null implies that we're updating all ABIs in the set to
|
||||||
|
// match scannedPackage.
|
||||||
|
adjustedAbi = scannedPackage.applicationInfo.primaryCpuAbi;
|
||||||
|
}
|
||||||
|
return adjustedAbi;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -93,14 +93,12 @@ import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL;
|
|||||||
|
|
||||||
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
|
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
|
||||||
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT;
|
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT;
|
||||||
import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME;
|
|
||||||
import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
|
import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
|
||||||
import static com.android.server.pm.ComponentResolver.RESOLVE_PRIORITY_SORTER;
|
import static com.android.server.pm.ComponentResolver.RESOLVE_PRIORITY_SORTER;
|
||||||
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
|
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
|
||||||
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
|
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
|
||||||
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
|
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
|
||||||
import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
|
import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
|
||||||
import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
|
|
||||||
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter;
|
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter;
|
||||||
import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
|
import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
|
||||||
import static com.android.server.pm.PackageManagerServiceUtils.compressedFileExists;
|
import static com.android.server.pm.PackageManagerServiceUtils.compressedFileExists;
|
||||||
@@ -278,6 +276,7 @@ import android.view.Display;
|
|||||||
|
|
||||||
import com.android.internal.R;
|
import com.android.internal.R;
|
||||||
import com.android.internal.annotations.GuardedBy;
|
import com.android.internal.annotations.GuardedBy;
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.app.ResolverActivity;
|
import com.android.internal.app.ResolverActivity;
|
||||||
import com.android.internal.content.NativeLibraryHelper;
|
import com.android.internal.content.NativeLibraryHelper;
|
||||||
import com.android.internal.content.PackageHelper;
|
import com.android.internal.content.PackageHelper;
|
||||||
@@ -433,7 +432,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
// user, but by default initialize to this.
|
// user, but by default initialize to this.
|
||||||
public static final boolean DEBUG_DEXOPT = false;
|
public static final boolean DEBUG_DEXOPT = false;
|
||||||
|
|
||||||
private static final boolean DEBUG_ABI_SELECTION = false;
|
static final boolean DEBUG_ABI_SELECTION = false;
|
||||||
private static final boolean DEBUG_INSTANT = Build.IS_DEBUGGABLE;
|
private static final boolean DEBUG_INSTANT = Build.IS_DEBUGGABLE;
|
||||||
private static final boolean DEBUG_APP_DATA = false;
|
private static final boolean DEBUG_APP_DATA = false;
|
||||||
|
|
||||||
@@ -663,7 +662,8 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
private static final File sAppInstallDir =
|
private static final File sAppInstallDir =
|
||||||
new File(Environment.getDataDirectory(), "app");
|
new File(Environment.getDataDirectory(), "app");
|
||||||
/** Directory where installed application's 32-bit native libraries are copied. */
|
/** Directory where installed application's 32-bit native libraries are copied. */
|
||||||
private static final File sAppLib32InstallDir =
|
@VisibleForTesting
|
||||||
|
static final File sAppLib32InstallDir =
|
||||||
new File(Environment.getDataDirectory(), "app-lib");
|
new File(Environment.getDataDirectory(), "app-lib");
|
||||||
|
|
||||||
// ----------------------------------------------------------------
|
// ----------------------------------------------------------------
|
||||||
@@ -754,6 +754,30 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
|
|
||||||
private final ApexManager mApexManager;
|
private final ApexManager mApexManager;
|
||||||
|
|
||||||
|
private final Injector mInjector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests will instantiate and / or extend to mock dependencies / behaviors.
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
static class Injector {
|
||||||
|
private final UserManagerInternal mUserManager;
|
||||||
|
private final PackageAbiHelper mAbiHelper;
|
||||||
|
|
||||||
|
Injector(UserManagerInternal userManager, PackageAbiHelper abiHelper) {
|
||||||
|
mUserManager = userManager;
|
||||||
|
mAbiHelper = abiHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserManagerInternal getUserManager() {
|
||||||
|
return mUserManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackageAbiHelper getAbiHelper() {
|
||||||
|
return mAbiHelper;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class PackageParserCallback implements PackageParser.Callback {
|
class PackageParserCallback implements PackageParser.Callback {
|
||||||
@Override public final boolean hasFeature(String feature) {
|
@Override public final boolean hasFeature(String feature) {
|
||||||
return PackageManagerService.this.hasSystemFeature(feature, 0);
|
return PackageManagerService.this.hasSystemFeature(feature, 0);
|
||||||
@@ -2093,8 +2117,8 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
// survive long enough to benefit of background optimizations.
|
// survive long enough to benefit of background optimizations.
|
||||||
for (int userId : firstUserIds) {
|
for (int userId : firstUserIds) {
|
||||||
PackageInfo info = getPackageInfo(packageName, /*flags*/ 0, userId);
|
PackageInfo info = getPackageInfo(packageName, /*flags*/ 0, userId);
|
||||||
// There's a race currently where some install events may interleave with an uninstall.
|
// There's a race currently where some install events may interleave with an
|
||||||
// This can lead to package info being null (b/36642664).
|
// uninstall. This can lead to package info being null (b/36642664).
|
||||||
if (info != null) {
|
if (info != null) {
|
||||||
mDexManager.notifyPackageInstalled(info, userId);
|
mDexManager.notifyPackageInstalled(info, userId);
|
||||||
}
|
}
|
||||||
@@ -2164,6 +2188,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
* external/removable/unprotected storage.
|
* external/removable/unprotected storage.
|
||||||
* @return {@link StorageEnum#TYPE_UNKNOWN} if the package is not stored externally or the
|
* @return {@link StorageEnum#TYPE_UNKNOWN} if the package is not stored externally or the
|
||||||
* corresponding {@link StorageEnum} storage type value if it is.
|
* corresponding {@link StorageEnum} storage type value if it is.
|
||||||
|
* corresponding {@link StorageEnum} storage type value if it is.
|
||||||
*/
|
*/
|
||||||
private static int getPackageExternalStorageType(VolumeInfo packageVolume,
|
private static int getPackageExternalStorageType(VolumeInfo packageVolume,
|
||||||
boolean packageIsExternal) {
|
boolean packageIsExternal) {
|
||||||
@@ -2421,6 +2446,11 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
mPermissionManager.getPermissionSettings(), mPackages);
|
mPermissionManager.getPermissionSettings(), mPackages);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(b/137961986): We should pass this via constructor, but would first need to create
|
||||||
|
// a packages lock that could also be passed in.
|
||||||
|
mInjector = new Injector(getUserManagerInternal(), new PackageAbiHelperImpl());
|
||||||
|
|
||||||
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
|
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
|
||||||
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
|
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
|
||||||
mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
|
mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
|
||||||
@@ -3128,7 +3158,9 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
// the rest of the commands above) because there's precious little we
|
// the rest of the commands above) because there's precious little we
|
||||||
// can do about it. A settings error is reported, though.
|
// can do about it. A settings error is reported, though.
|
||||||
final List<String> changedAbiCodePath =
|
final List<String> changedAbiCodePath =
|
||||||
adjustCpuAbisForSharedUserLPw(setting.packages, null /*scannedPackage*/);
|
applyAdjustedAbiToSharedUser(setting, null /*scannedPackage*/,
|
||||||
|
mInjector.getAbiHelper().getAdjustedAbiForSharedUser(
|
||||||
|
setting.packages, null /*scannedPackage*/));
|
||||||
if (changedAbiCodePath != null && changedAbiCodePath.size() > 0) {
|
if (changedAbiCodePath != null && changedAbiCodePath.size() > 0) {
|
||||||
for (int i = changedAbiCodePath.size() - 1; i >= 0; --i) {
|
for (int i = changedAbiCodePath.size() - 1; i >= 0; --i) {
|
||||||
final String codePathString = changedAbiCodePath.get(i);
|
final String codePathString = changedAbiCodePath.get(i);
|
||||||
@@ -9397,7 +9429,8 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
null /* originalPkgSetting */, null, parseFlags, scanFlags,
|
null /* originalPkgSetting */, null, parseFlags, scanFlags,
|
||||||
(pkg == mPlatformPackage), user);
|
(pkg == mPlatformPackage), user);
|
||||||
applyPolicy(pkg, parseFlags, scanFlags, mPlatformPackage);
|
applyPolicy(pkg, parseFlags, scanFlags, mPlatformPackage);
|
||||||
final ScanResult scanResult = scanPackageOnlyLI(request, mFactoryTest, -1L);
|
final ScanResult scanResult =
|
||||||
|
scanPackageOnlyLI(request, mInjector, mFactoryTest, -1L);
|
||||||
if (scanResult.existingSettingCopied && scanResult.request.pkgSetting != null) {
|
if (scanResult.existingSettingCopied && scanResult.request.pkgSetting != null) {
|
||||||
scanResult.request.pkgSetting.updateFrom(scanResult.pkgSetting);
|
scanResult.request.pkgSetting.updateFrom(scanResult.pkgSetting);
|
||||||
}
|
}
|
||||||
@@ -10759,7 +10792,8 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** The result of a package scan. */
|
/** The result of a package scan. */
|
||||||
private static class ScanResult {
|
@VisibleForTesting
|
||||||
|
static class ScanResult {
|
||||||
/** The request that initiated the scan that produced this result. */
|
/** The request that initiated the scan that produced this result. */
|
||||||
public final ScanRequest request;
|
public final ScanRequest request;
|
||||||
/** Whether or not the package scan was successful */
|
/** Whether or not the package scan was successful */
|
||||||
@@ -10798,7 +10832,8 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** A package to be scanned */
|
/** A package to be scanned */
|
||||||
private static class ScanRequest {
|
@VisibleForTesting
|
||||||
|
static class ScanRequest {
|
||||||
/** The parsed package */
|
/** The parsed package */
|
||||||
@NonNull public final PackageParser.Package pkg;
|
@NonNull public final PackageParser.Package pkg;
|
||||||
/** The package this package replaces */
|
/** The package this package replaces */
|
||||||
@@ -10991,7 +11026,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
pkgSetting == null ? null : pkgSetting.pkg, pkgSetting, disabledPkgSetting,
|
pkgSetting == null ? null : pkgSetting.pkg, pkgSetting, disabledPkgSetting,
|
||||||
originalPkgSetting, realPkgName, parseFlags, scanFlags,
|
originalPkgSetting, realPkgName, parseFlags, scanFlags,
|
||||||
(pkg == mPlatformPackage), user);
|
(pkg == mPlatformPackage), user);
|
||||||
return scanPackageOnlyLI(request, mFactoryTest, currentTime);
|
return scanPackageOnlyLI(request, mInjector, mFactoryTest, currentTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -11215,21 +11250,71 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
pkg.setPackageName(renamedPackageName);
|
pkg.setPackageName(renamedPackageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the adjusted ABI calculated by
|
||||||
|
* {@link PackageAbiHelper#getAdjustedAbiForSharedUser(Set, PackageParser.Package)} to all
|
||||||
|
* relevant packages and settings.
|
||||||
|
* @param sharedUserSetting The {@code SharedUserSetting} to adjust
|
||||||
|
* @param scannedPackage the package being scanned or null
|
||||||
|
* @param adjustedAbi the adjusted ABI calculated by {@link PackageAbiHelper}
|
||||||
|
* @return the list of code paths that belong to packages that had their ABIs adjusted.
|
||||||
|
*/
|
||||||
|
private static List<String> applyAdjustedAbiToSharedUser(SharedUserSetting sharedUserSetting,
|
||||||
|
PackageParser.Package scannedPackage, String adjustedAbi) {
|
||||||
|
if (scannedPackage != null) {
|
||||||
|
scannedPackage.applicationInfo.primaryCpuAbi = adjustedAbi;
|
||||||
|
}
|
||||||
|
List<String> changedAbiCodePath = null;
|
||||||
|
for (PackageSetting ps : sharedUserSetting.packages) {
|
||||||
|
if (scannedPackage == null || !scannedPackage.packageName.equals(ps.name)) {
|
||||||
|
if (ps.primaryCpuAbiString != null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ps.primaryCpuAbiString = adjustedAbi;
|
||||||
|
if (ps.pkg != null && ps.pkg.applicationInfo != null
|
||||||
|
&& !TextUtils.equals(
|
||||||
|
adjustedAbi, ps.pkg.applicationInfo.primaryCpuAbi)) {
|
||||||
|
ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
|
||||||
|
if (DEBUG_ABI_SELECTION) {
|
||||||
|
Slog.i(TAG,
|
||||||
|
"Adjusting ABI for " + ps.name + " to " + adjustedAbi
|
||||||
|
+ " (scannedPackage="
|
||||||
|
+ (scannedPackage != null ? scannedPackage : "null")
|
||||||
|
+ ")");
|
||||||
|
}
|
||||||
|
if (changedAbiCodePath == null) {
|
||||||
|
changedAbiCodePath = new ArrayList<>();
|
||||||
|
}
|
||||||
|
changedAbiCodePath.add(ps.codePathString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return changedAbiCodePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Just scans the package without any side effects.
|
* Just scans the package without any side effects.
|
||||||
* <p>Not entirely true at the moment. There is still one side effect -- this
|
* <p>Not entirely true at the moment. There is still one side effect -- this
|
||||||
* method potentially modifies a live {@link PackageSetting} object representing
|
* method potentially modifies a live {@link PackageSetting} object representing
|
||||||
* the package being scanned. This will be resolved in the future.
|
* the package being scanned. This will be resolved in the future.
|
||||||
*
|
*
|
||||||
|
* @param injector injector for acquiring dependencies
|
||||||
* @param request Information about the package to be scanned
|
* @param request Information about the package to be scanned
|
||||||
* @param isUnderFactoryTest Whether or not the device is under factory test
|
* @param isUnderFactoryTest Whether or not the device is under factory test
|
||||||
* @param currentTime The current time, in millis
|
* @param currentTime The current time, in millis
|
||||||
* @return The results of the scan
|
* @return The results of the scan
|
||||||
*/
|
*/
|
||||||
@GuardedBy("mInstallLock")
|
@GuardedBy("mInstallLock")
|
||||||
private static @NonNull ScanResult scanPackageOnlyLI(@NonNull ScanRequest request,
|
@VisibleForTesting
|
||||||
|
@NonNull
|
||||||
|
static ScanResult scanPackageOnlyLI(@NonNull ScanRequest request,
|
||||||
|
Injector injector,
|
||||||
boolean isUnderFactoryTest, long currentTime)
|
boolean isUnderFactoryTest, long currentTime)
|
||||||
throws PackageManagerException {
|
throws PackageManagerException {
|
||||||
|
final PackageAbiHelper packageAbiHelper = injector.getAbiHelper();
|
||||||
|
final UserManagerInternal userManager = injector.getUserManager();
|
||||||
final PackageParser.Package pkg = request.pkg;
|
final PackageParser.Package pkg = request.pkg;
|
||||||
PackageSetting pkgSetting = request.pkgSetting;
|
PackageSetting pkgSetting = request.pkgSetting;
|
||||||
final PackageSetting disabledPkgSetting = request.disabledPkgSetting;
|
final PackageSetting disabledPkgSetting = request.disabledPkgSetting;
|
||||||
@@ -11335,7 +11420,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
if (!createNewPackage) {
|
if (!createNewPackage) {
|
||||||
final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
|
final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
|
||||||
final boolean fullApp = (scanFlags & SCAN_AS_FULL_APP) != 0;
|
final boolean fullApp = (scanFlags & SCAN_AS_FULL_APP) != 0;
|
||||||
setInstantAppForUser(pkgSetting, userId, instantApp, fullApp);
|
setInstantAppForUser(userManager, pkgSetting, userId, instantApp, fullApp);
|
||||||
}
|
}
|
||||||
// TODO(patb): see if we can do away with disabled check here.
|
// TODO(patb): see if we can do away with disabled check here.
|
||||||
if (disabledPkgSetting != null
|
if (disabledPkgSetting != null
|
||||||
@@ -11381,7 +11466,10 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
if (needToDeriveAbi) {
|
if (needToDeriveAbi) {
|
||||||
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
|
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
|
||||||
final boolean extractNativeLibs = !pkg.isLibrary();
|
final boolean extractNativeLibs = !pkg.isLibrary();
|
||||||
derivePackageAbi(pkg, cpuAbiOverride, extractNativeLibs);
|
final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths> derivedAbi =
|
||||||
|
packageAbiHelper.derivePackageAbi(pkg, cpuAbiOverride, extractNativeLibs);
|
||||||
|
derivedAbi.first.applyTo(pkg);
|
||||||
|
derivedAbi.second.applyTo(pkg);
|
||||||
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
|
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
|
||||||
|
|
||||||
// Some system apps still use directory structure for native libraries
|
// Some system apps still use directory structure for native libraries
|
||||||
@@ -11389,8 +11477,13 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
// structure. Try to detect abi based on directory structure.
|
// structure. Try to detect abi based on directory structure.
|
||||||
if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp() &&
|
if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp() &&
|
||||||
pkg.applicationInfo.primaryCpuAbi == null) {
|
pkg.applicationInfo.primaryCpuAbi == null) {
|
||||||
setBundledAppAbisAndRoots(pkg, pkgSetting);
|
final PackageAbiHelper.Abis abis = packageAbiHelper.getBundledAppAbis(
|
||||||
setNativeLibraryPaths(pkg, sAppLib32InstallDir);
|
pkg);
|
||||||
|
abis.applyTo(pkg);
|
||||||
|
abis.applyTo(pkgSetting);
|
||||||
|
final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
|
||||||
|
packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir);
|
||||||
|
nativeLibraryPaths.applyTo(pkg);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// This is not a first boot or an upgrade, don't bother deriving the
|
// This is not a first boot or an upgrade, don't bother deriving the
|
||||||
@@ -11399,7 +11492,9 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
pkg.applicationInfo.primaryCpuAbi = primaryCpuAbiFromSettings;
|
pkg.applicationInfo.primaryCpuAbi = primaryCpuAbiFromSettings;
|
||||||
pkg.applicationInfo.secondaryCpuAbi = secondaryCpuAbiFromSettings;
|
pkg.applicationInfo.secondaryCpuAbi = secondaryCpuAbiFromSettings;
|
||||||
|
|
||||||
setNativeLibraryPaths(pkg, sAppLib32InstallDir);
|
final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
|
||||||
|
packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir);
|
||||||
|
nativeLibraryPaths.applyTo(pkg);
|
||||||
|
|
||||||
if (DEBUG_ABI_SELECTION) {
|
if (DEBUG_ABI_SELECTION) {
|
||||||
Slog.i(TAG, "Using ABIS and native lib paths from settings : " +
|
Slog.i(TAG, "Using ABIS and native lib paths from settings : " +
|
||||||
@@ -11420,7 +11515,9 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
// ABIs we've determined above. For non-moves, the path will be updated based on the
|
// ABIs we've determined above. For non-moves, the path will be updated based on the
|
||||||
// ABIs we determined during compilation, but the path will depend on the final
|
// ABIs we determined during compilation, but the path will depend on the final
|
||||||
// package path (after the rename away from the stage path).
|
// package path (after the rename away from the stage path).
|
||||||
setNativeLibraryPaths(pkg, sAppLib32InstallDir);
|
final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
|
||||||
|
packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir);
|
||||||
|
nativeLibraryPaths.applyTo(pkg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a special case for the "system" package, where the ABI is
|
// This is a special case for the "system" package, where the ABI is
|
||||||
@@ -11474,8 +11571,9 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
// We also do this *before* we perform dexopt on this package, so that
|
// We also do this *before* we perform dexopt on this package, so that
|
||||||
// we can avoid redundant dexopts, and also to make sure we've got the
|
// we can avoid redundant dexopts, and also to make sure we've got the
|
||||||
// code and package path correct.
|
// code and package path correct.
|
||||||
changedAbiCodePath =
|
changedAbiCodePath = applyAdjustedAbiToSharedUser(pkgSetting.sharedUser, pkg,
|
||||||
adjustCpuAbisForSharedUserLPw(pkgSetting.sharedUser.packages, pkg);
|
packageAbiHelper.getAdjustedAbiForSharedUser(
|
||||||
|
pkgSetting.sharedUser.packages, pkg));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isUnderFactoryTest && pkg.requestedPermissions.contains(
|
if (isUnderFactoryTest && pkg.requestedPermissions.contains(
|
||||||
@@ -12325,264 +12423,6 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
|
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Derive the ABI of a non-system package located at {@code scanFile}. This information
|
|
||||||
* is derived purely on the basis of the contents of {@code scanFile} and
|
|
||||||
* {@code cpuAbiOverride}.
|
|
||||||
*
|
|
||||||
* If {@code extractLibs} is true, native libraries are extracted from the app if required.
|
|
||||||
*/
|
|
||||||
private static void derivePackageAbi(PackageParser.Package pkg, String cpuAbiOverride,
|
|
||||||
boolean extractLibs)
|
|
||||||
throws PackageManagerException {
|
|
||||||
// Give ourselves some initial paths; we'll come back for another
|
|
||||||
// pass once we've determined ABI below.
|
|
||||||
setNativeLibraryPaths(pkg, sAppLib32InstallDir);
|
|
||||||
|
|
||||||
// We shouldn't attempt to extract libs from system app when it was not updated.
|
|
||||||
if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) {
|
|
||||||
extractLibs = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String nativeLibraryRootStr = pkg.applicationInfo.nativeLibraryRootDir;
|
|
||||||
final boolean useIsaSpecificSubdirs = pkg.applicationInfo.nativeLibraryRootRequiresIsa;
|
|
||||||
|
|
||||||
NativeLibraryHelper.Handle handle = null;
|
|
||||||
try {
|
|
||||||
handle = NativeLibraryHelper.Handle.create(pkg);
|
|
||||||
// TODO(multiArch): This can be null for apps that didn't go through the
|
|
||||||
// usual installation process. We can calculate it again, like we
|
|
||||||
// do during install time.
|
|
||||||
//
|
|
||||||
// TODO(multiArch): Why do we need to rescan ASEC apps again ? It seems totally
|
|
||||||
// unnecessary.
|
|
||||||
final File nativeLibraryRoot = new File(nativeLibraryRootStr);
|
|
||||||
|
|
||||||
// Null out the abis so that they can be recalculated.
|
|
||||||
pkg.applicationInfo.primaryCpuAbi = null;
|
|
||||||
pkg.applicationInfo.secondaryCpuAbi = null;
|
|
||||||
if (isMultiArch(pkg.applicationInfo)) {
|
|
||||||
// Warn if we've set an abiOverride for multi-lib packages..
|
|
||||||
// By definition, we need to copy both 32 and 64 bit libraries for
|
|
||||||
// such packages.
|
|
||||||
if (pkg.cpuAbiOverride != null
|
|
||||||
&& !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(pkg.cpuAbiOverride)) {
|
|
||||||
Slog.w(TAG, "Ignoring abiOverride for multi arch application.");
|
|
||||||
}
|
|
||||||
|
|
||||||
int abi32 = PackageManager.NO_NATIVE_LIBRARIES;
|
|
||||||
int abi64 = PackageManager.NO_NATIVE_LIBRARIES;
|
|
||||||
if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
|
|
||||||
if (extractLibs) {
|
|
||||||
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
|
|
||||||
abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
|
|
||||||
nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS,
|
|
||||||
useIsaSpecificSubdirs);
|
|
||||||
} else {
|
|
||||||
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
|
|
||||||
abi32 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_32_BIT_ABIS);
|
|
||||||
}
|
|
||||||
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shared library native code should be in the APK zip aligned
|
|
||||||
if (abi32 >= 0 && pkg.isLibrary() && extractLibs) {
|
|
||||||
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
|
|
||||||
"Shared library native lib extraction not supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
maybeThrowExceptionForMultiArchCopy(
|
|
||||||
"Error unpackaging 32 bit native libs for multiarch app.", abi32);
|
|
||||||
|
|
||||||
if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
|
|
||||||
if (extractLibs) {
|
|
||||||
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
|
|
||||||
abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
|
|
||||||
nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS,
|
|
||||||
useIsaSpecificSubdirs);
|
|
||||||
} else {
|
|
||||||
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
|
|
||||||
abi64 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_64_BIT_ABIS);
|
|
||||||
}
|
|
||||||
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
|
|
||||||
}
|
|
||||||
|
|
||||||
maybeThrowExceptionForMultiArchCopy(
|
|
||||||
"Error unpackaging 64 bit native libs for multiarch app.", abi64);
|
|
||||||
|
|
||||||
if (abi64 >= 0) {
|
|
||||||
// Shared library native libs should be in the APK zip aligned
|
|
||||||
if (extractLibs && pkg.isLibrary()) {
|
|
||||||
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
|
|
||||||
"Shared library native lib extraction not supported");
|
|
||||||
}
|
|
||||||
pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[abi64];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (abi32 >= 0) {
|
|
||||||
final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32];
|
|
||||||
if (abi64 >= 0) {
|
|
||||||
if (pkg.use32bitAbi) {
|
|
||||||
pkg.applicationInfo.secondaryCpuAbi = pkg.applicationInfo.primaryCpuAbi;
|
|
||||||
pkg.applicationInfo.primaryCpuAbi = abi;
|
|
||||||
} else {
|
|
||||||
pkg.applicationInfo.secondaryCpuAbi = abi;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pkg.applicationInfo.primaryCpuAbi = abi;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
String[] abiList = (cpuAbiOverride != null) ?
|
|
||||||
new String[] { cpuAbiOverride } : Build.SUPPORTED_ABIS;
|
|
||||||
|
|
||||||
// Enable gross and lame hacks for apps that are built with old
|
|
||||||
// SDK tools. We must scan their APKs for renderscript bitcode and
|
|
||||||
// not launch them if it's present. Don't bother checking on devices
|
|
||||||
// that don't have 64 bit support.
|
|
||||||
boolean needsRenderScriptOverride = false;
|
|
||||||
if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null &&
|
|
||||||
NativeLibraryHelper.hasRenderscriptBitcode(handle)) {
|
|
||||||
abiList = Build.SUPPORTED_32_BIT_ABIS;
|
|
||||||
needsRenderScriptOverride = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int copyRet;
|
|
||||||
if (extractLibs) {
|
|
||||||
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
|
|
||||||
copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
|
|
||||||
nativeLibraryRoot, abiList, useIsaSpecificSubdirs);
|
|
||||||
} else {
|
|
||||||
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
|
|
||||||
copyRet = NativeLibraryHelper.findSupportedAbi(handle, abiList);
|
|
||||||
}
|
|
||||||
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
|
|
||||||
|
|
||||||
if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
|
|
||||||
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
|
|
||||||
"Error unpackaging native libs for app, errorCode=" + copyRet);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (copyRet >= 0) {
|
|
||||||
// Shared libraries that have native libs must be multi-architecture
|
|
||||||
if (pkg.isLibrary()) {
|
|
||||||
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
|
|
||||||
"Shared library with native libs must be multiarch");
|
|
||||||
}
|
|
||||||
pkg.applicationInfo.primaryCpuAbi = abiList[copyRet];
|
|
||||||
} else if (copyRet == PackageManager.NO_NATIVE_LIBRARIES && cpuAbiOverride != null) {
|
|
||||||
pkg.applicationInfo.primaryCpuAbi = cpuAbiOverride;
|
|
||||||
} else if (needsRenderScriptOverride) {
|
|
||||||
pkg.applicationInfo.primaryCpuAbi = abiList[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
Slog.e(TAG, "Unable to get canonical file " + ioe.toString());
|
|
||||||
} finally {
|
|
||||||
IoUtils.closeQuietly(handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now that we've calculated the ABIs and determined if it's an internal app,
|
|
||||||
// we will go ahead and populate the nativeLibraryPath.
|
|
||||||
setNativeLibraryPaths(pkg, sAppLib32InstallDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adjusts ABIs for a set of packages belonging to a shared user so that they all match.
|
|
||||||
* i.e, so that all packages can be run inside a single process if required.
|
|
||||||
*
|
|
||||||
* Optionally, callers can pass in a parsed package via {@code newPackage} in which case
|
|
||||||
* this function will either try and make the ABI for all packages in {@code packagesForUser}
|
|
||||||
* match {@code scannedPackage} or will update the ABI of {@code scannedPackage} to match
|
|
||||||
* the ABI selected for {@code packagesForUser}. This variant is used when installing or
|
|
||||||
* updating a package that belongs to a shared user.
|
|
||||||
*
|
|
||||||
* NOTE: We currently only match for the primary CPU abi string. Matching the secondary
|
|
||||||
* adds unnecessary complexity.
|
|
||||||
*/
|
|
||||||
private static @Nullable List<String> adjustCpuAbisForSharedUserLPw(
|
|
||||||
Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage) {
|
|
||||||
List<String> changedAbiCodePath = null;
|
|
||||||
String requiredInstructionSet = null;
|
|
||||||
if (scannedPackage != null && scannedPackage.applicationInfo.primaryCpuAbi != null) {
|
|
||||||
requiredInstructionSet = VMRuntime.getInstructionSet(
|
|
||||||
scannedPackage.applicationInfo.primaryCpuAbi);
|
|
||||||
}
|
|
||||||
|
|
||||||
PackageSetting requirer = null;
|
|
||||||
for (PackageSetting ps : packagesForUser) {
|
|
||||||
// If packagesForUser contains scannedPackage, we skip it. This will happen
|
|
||||||
// when scannedPackage is an update of an existing package. Without this check,
|
|
||||||
// we will never be able to change the ABI of any package belonging to a shared
|
|
||||||
// user, even if it's compatible with other packages.
|
|
||||||
if (scannedPackage == null || !scannedPackage.packageName.equals(ps.name)) {
|
|
||||||
if (ps.primaryCpuAbiString == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String instructionSet = VMRuntime.getInstructionSet(ps.primaryCpuAbiString);
|
|
||||||
if (requiredInstructionSet != null && !instructionSet.equals(requiredInstructionSet)) {
|
|
||||||
// We have a mismatch between instruction sets (say arm vs arm64) warn about
|
|
||||||
// this but there's not much we can do.
|
|
||||||
String errorMessage = "Instruction set mismatch, "
|
|
||||||
+ ((requirer == null) ? "[caller]" : requirer)
|
|
||||||
+ " requires " + requiredInstructionSet + " whereas " + ps
|
|
||||||
+ " requires " + instructionSet;
|
|
||||||
Slog.w(TAG, errorMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (requiredInstructionSet == null) {
|
|
||||||
requiredInstructionSet = instructionSet;
|
|
||||||
requirer = ps;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (requiredInstructionSet != null) {
|
|
||||||
String adjustedAbi;
|
|
||||||
if (requirer != null) {
|
|
||||||
// requirer != null implies that either scannedPackage was null or that scannedPackage
|
|
||||||
// did not require an ABI, in which case we have to adjust scannedPackage to match
|
|
||||||
// the ABI of the set (which is the same as requirer's ABI)
|
|
||||||
adjustedAbi = requirer.primaryCpuAbiString;
|
|
||||||
if (scannedPackage != null) {
|
|
||||||
scannedPackage.applicationInfo.primaryCpuAbi = adjustedAbi;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// requirer == null implies that we're updating all ABIs in the set to
|
|
||||||
// match scannedPackage.
|
|
||||||
adjustedAbi = scannedPackage.applicationInfo.primaryCpuAbi;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (PackageSetting ps : packagesForUser) {
|
|
||||||
if (scannedPackage == null || !scannedPackage.packageName.equals(ps.name)) {
|
|
||||||
if (ps.primaryCpuAbiString != null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ps.primaryCpuAbiString = adjustedAbi;
|
|
||||||
if (ps.pkg != null && ps.pkg.applicationInfo != null &&
|
|
||||||
!TextUtils.equals(adjustedAbi, ps.pkg.applicationInfo.primaryCpuAbi)) {
|
|
||||||
ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
|
|
||||||
if (DEBUG_ABI_SELECTION) {
|
|
||||||
Slog.i(TAG, "Adjusting ABI for " + ps.name + " to " + adjustedAbi
|
|
||||||
+ " (requirer="
|
|
||||||
+ (requirer != null ? requirer.pkg : "null")
|
|
||||||
+ ", scannedPackage="
|
|
||||||
+ (scannedPackage != null ? scannedPackage : "null")
|
|
||||||
+ ")");
|
|
||||||
}
|
|
||||||
if (changedAbiCodePath == null) {
|
|
||||||
changedAbiCodePath = new ArrayList<>();
|
|
||||||
}
|
|
||||||
changedAbiCodePath.add(ps.codePathString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return changedAbiCodePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setUpCustomResolverActivity(PackageParser.Package pkg) {
|
private void setUpCustomResolverActivity(PackageParser.Package pkg) {
|
||||||
synchronized (mPackages) {
|
synchronized (mPackages) {
|
||||||
mResolverReplaced = true;
|
mResolverReplaced = true;
|
||||||
@@ -12634,207 +12474,6 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
| IntentFilter.MATCH_ADJUSTMENT_NORMAL;
|
| IntentFilter.MATCH_ADJUSTMENT_NORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String calculateBundledApkRoot(final String codePathString) {
|
|
||||||
final File codePath = new File(codePathString);
|
|
||||||
final File codeRoot;
|
|
||||||
if (FileUtils.contains(Environment.getRootDirectory(), codePath)) {
|
|
||||||
codeRoot = Environment.getRootDirectory();
|
|
||||||
} else if (FileUtils.contains(Environment.getOemDirectory(), codePath)) {
|
|
||||||
codeRoot = Environment.getOemDirectory();
|
|
||||||
} else if (FileUtils.contains(Environment.getVendorDirectory(), codePath)) {
|
|
||||||
codeRoot = Environment.getVendorDirectory();
|
|
||||||
} else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
|
|
||||||
codeRoot = Environment.getOdmDirectory();
|
|
||||||
} else if (FileUtils.contains(Environment.getProductDirectory(), codePath)) {
|
|
||||||
codeRoot = Environment.getProductDirectory();
|
|
||||||
} else if (FileUtils.contains(Environment.getSystemExtDirectory(), codePath)) {
|
|
||||||
codeRoot = Environment.getSystemExtDirectory();
|
|
||||||
} else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
|
|
||||||
codeRoot = Environment.getOdmDirectory();
|
|
||||||
} else {
|
|
||||||
// Unrecognized code path; take its top real segment as the apk root:
|
|
||||||
// e.g. /something/app/blah.apk => /something
|
|
||||||
try {
|
|
||||||
File f = codePath.getCanonicalFile();
|
|
||||||
File parent = f.getParentFile(); // non-null because codePath is a file
|
|
||||||
File tmp;
|
|
||||||
while ((tmp = parent.getParentFile()) != null) {
|
|
||||||
f = parent;
|
|
||||||
parent = tmp;
|
|
||||||
}
|
|
||||||
codeRoot = f;
|
|
||||||
Slog.w(TAG, "Unrecognized code path "
|
|
||||||
+ codePath + " - using " + codeRoot);
|
|
||||||
} catch (IOException e) {
|
|
||||||
// Can't canonicalize the code path -- shenanigans?
|
|
||||||
Slog.w(TAG, "Can't canonicalize code path " + codePath);
|
|
||||||
return Environment.getRootDirectory().getPath();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return codeRoot.getPath();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Derive and set the location of native libraries for the given package,
|
|
||||||
* which varies depending on where and how the package was installed.
|
|
||||||
*/
|
|
||||||
private static void setNativeLibraryPaths(PackageParser.Package pkg, File appLib32InstallDir) {
|
|
||||||
final ApplicationInfo info = pkg.applicationInfo;
|
|
||||||
final String codePath = pkg.codePath;
|
|
||||||
final File codeFile = new File(codePath);
|
|
||||||
final boolean bundledApp = info.isSystemApp() && !info.isUpdatedSystemApp();
|
|
||||||
|
|
||||||
info.nativeLibraryRootDir = null;
|
|
||||||
info.nativeLibraryRootRequiresIsa = false;
|
|
||||||
info.nativeLibraryDir = null;
|
|
||||||
info.secondaryNativeLibraryDir = null;
|
|
||||||
|
|
||||||
if (isApkFile(codeFile)) {
|
|
||||||
// Monolithic install
|
|
||||||
if (bundledApp) {
|
|
||||||
// If "/system/lib64/apkname" exists, assume that is the per-package
|
|
||||||
// native library directory to use; otherwise use "/system/lib/apkname".
|
|
||||||
final String apkRoot = calculateBundledApkRoot(info.sourceDir);
|
|
||||||
final boolean is64Bit = VMRuntime.is64BitInstructionSet(
|
|
||||||
getPrimaryInstructionSet(info));
|
|
||||||
|
|
||||||
// This is a bundled system app so choose the path based on the ABI.
|
|
||||||
// if it's a 64 bit abi, use lib64 otherwise use lib32. Note that this
|
|
||||||
// is just the default path.
|
|
||||||
final String apkName = deriveCodePathName(codePath);
|
|
||||||
final String libDir = is64Bit ? LIB64_DIR_NAME : LIB_DIR_NAME;
|
|
||||||
info.nativeLibraryRootDir = Environment.buildPath(new File(apkRoot), libDir,
|
|
||||||
apkName).getAbsolutePath();
|
|
||||||
|
|
||||||
if (info.secondaryCpuAbi != null) {
|
|
||||||
final String secondaryLibDir = is64Bit ? LIB_DIR_NAME : LIB64_DIR_NAME;
|
|
||||||
info.secondaryNativeLibraryDir = Environment.buildPath(new File(apkRoot),
|
|
||||||
secondaryLibDir, apkName).getAbsolutePath();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
final String apkName = deriveCodePathName(codePath);
|
|
||||||
info.nativeLibraryRootDir = new File(appLib32InstallDir, apkName)
|
|
||||||
.getAbsolutePath();
|
|
||||||
}
|
|
||||||
|
|
||||||
info.nativeLibraryRootRequiresIsa = false;
|
|
||||||
info.nativeLibraryDir = info.nativeLibraryRootDir;
|
|
||||||
} else {
|
|
||||||
// Cluster install
|
|
||||||
info.nativeLibraryRootDir = new File(codeFile, LIB_DIR_NAME).getAbsolutePath();
|
|
||||||
info.nativeLibraryRootRequiresIsa = true;
|
|
||||||
|
|
||||||
info.nativeLibraryDir = new File(info.nativeLibraryRootDir,
|
|
||||||
getPrimaryInstructionSet(info)).getAbsolutePath();
|
|
||||||
|
|
||||||
if (info.secondaryCpuAbi != null) {
|
|
||||||
info.secondaryNativeLibraryDir = new File(info.nativeLibraryRootDir,
|
|
||||||
VMRuntime.getInstructionSet(info.secondaryCpuAbi)).getAbsolutePath();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate the abis and roots for a bundled app. These can uniquely
|
|
||||||
* be determined from the contents of the system partition, i.e whether
|
|
||||||
* it contains 64 or 32 bit shared libraries etc. We do not validate any
|
|
||||||
* of this information, and instead assume that the system was built
|
|
||||||
* sensibly.
|
|
||||||
*/
|
|
||||||
private static void setBundledAppAbisAndRoots(PackageParser.Package pkg,
|
|
||||||
PackageSetting pkgSetting) {
|
|
||||||
final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath());
|
|
||||||
|
|
||||||
// If "/system/lib64/apkname" exists, assume that is the per-package
|
|
||||||
// native library directory to use; otherwise use "/system/lib/apkname".
|
|
||||||
final String apkRoot = calculateBundledApkRoot(pkg.applicationInfo.sourceDir);
|
|
||||||
setBundledAppAbi(pkg, apkRoot, apkName);
|
|
||||||
// pkgSetting might be null during rescan following uninstall of updates
|
|
||||||
// to a bundled app, so accommodate that possibility. The settings in
|
|
||||||
// that case will be established later from the parsed package.
|
|
||||||
//
|
|
||||||
// If the settings aren't null, sync them up with what we've just derived.
|
|
||||||
// note that apkRoot isn't stored in the package settings.
|
|
||||||
if (pkgSetting != null) {
|
|
||||||
pkgSetting.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi;
|
|
||||||
pkgSetting.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deduces the ABI of a bundled app and sets the relevant fields on the
|
|
||||||
* parsed pkg object.
|
|
||||||
*
|
|
||||||
* @param apkRoot the root of the installed apk, something like {@code /system} or {@code /oem}
|
|
||||||
* under which system libraries are installed.
|
|
||||||
* @param apkName the name of the installed package.
|
|
||||||
*/
|
|
||||||
private static void setBundledAppAbi(PackageParser.Package pkg, String apkRoot, String apkName) {
|
|
||||||
final File codeFile = new File(pkg.codePath);
|
|
||||||
|
|
||||||
final boolean has64BitLibs;
|
|
||||||
final boolean has32BitLibs;
|
|
||||||
if (isApkFile(codeFile)) {
|
|
||||||
// Monolithic install
|
|
||||||
has64BitLibs = (new File(apkRoot, new File(LIB64_DIR_NAME, apkName).getPath())).exists();
|
|
||||||
has32BitLibs = (new File(apkRoot, new File(LIB_DIR_NAME, apkName).getPath())).exists();
|
|
||||||
} else {
|
|
||||||
// Cluster install
|
|
||||||
final File rootDir = new File(codeFile, LIB_DIR_NAME);
|
|
||||||
if (!ArrayUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS)
|
|
||||||
&& !TextUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS[0])) {
|
|
||||||
final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_64_BIT_ABIS[0]);
|
|
||||||
has64BitLibs = (new File(rootDir, isa)).exists();
|
|
||||||
} else {
|
|
||||||
has64BitLibs = false;
|
|
||||||
}
|
|
||||||
if (!ArrayUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS)
|
|
||||||
&& !TextUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS[0])) {
|
|
||||||
final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_32_BIT_ABIS[0]);
|
|
||||||
has32BitLibs = (new File(rootDir, isa)).exists();
|
|
||||||
} else {
|
|
||||||
has32BitLibs = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (has64BitLibs && !has32BitLibs) {
|
|
||||||
// The package has 64 bit libs, but not 32 bit libs. Its primary
|
|
||||||
// ABI should be 64 bit. We can safely assume here that the bundled
|
|
||||||
// native libraries correspond to the most preferred ABI in the list.
|
|
||||||
|
|
||||||
pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
|
|
||||||
pkg.applicationInfo.secondaryCpuAbi = null;
|
|
||||||
} else if (has32BitLibs && !has64BitLibs) {
|
|
||||||
// The package has 32 bit libs but not 64 bit libs. Its primary
|
|
||||||
// ABI should be 32 bit.
|
|
||||||
|
|
||||||
pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
|
|
||||||
pkg.applicationInfo.secondaryCpuAbi = null;
|
|
||||||
} else if (has32BitLibs && has64BitLibs) {
|
|
||||||
// The application has both 64 and 32 bit bundled libraries. We check
|
|
||||||
// here that the app declares multiArch support, and warn if it doesn't.
|
|
||||||
//
|
|
||||||
// We will be lenient here and record both ABIs. The primary will be the
|
|
||||||
// ABI that's higher on the list, i.e, a device that's configured to prefer
|
|
||||||
// 64 bit apps will see a 64 bit primary ABI,
|
|
||||||
|
|
||||||
if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) == 0) {
|
|
||||||
Slog.e(TAG, "Package " + pkg + " has multiple bundled libs, but is not multiarch.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (VMRuntime.is64BitInstructionSet(getPreferredInstructionSet())) {
|
|
||||||
pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
|
|
||||||
pkg.applicationInfo.secondaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
|
|
||||||
} else {
|
|
||||||
pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
|
|
||||||
pkg.applicationInfo.secondaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pkg.applicationInfo.primaryCpuAbi = null;
|
|
||||||
pkg.applicationInfo.secondaryCpuAbi = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void killApplication(String pkgName, int appId, String reason) {
|
private void killApplication(String pkgName, int appId, String reason) {
|
||||||
killApplication(pkgName, appId, UserHandle.USER_ALL, reason);
|
killApplication(pkgName, appId, UserHandle.USER_ALL, reason);
|
||||||
}
|
}
|
||||||
@@ -13556,7 +13195,8 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
// upgrade app from instant to full; we don't allow app downgrade
|
// upgrade app from instant to full; we don't allow app downgrade
|
||||||
installed = true;
|
installed = true;
|
||||||
}
|
}
|
||||||
setInstantAppForUser(pkgSetting, userId, instantApp, fullApp);
|
setInstantAppForUser(
|
||||||
|
getUserManagerInternal(), pkgSetting, userId, instantApp, fullApp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (installed) {
|
if (installed) {
|
||||||
@@ -13604,8 +13244,8 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setInstantAppForUser(PackageSetting pkgSetting, int userId,
|
static void setInstantAppForUser(UserManagerInternal userManager, PackageSetting pkgSetting,
|
||||||
boolean instantApp, boolean fullApp) {
|
int userId, boolean instantApp, boolean fullApp) {
|
||||||
// no state specified; do nothing
|
// no state specified; do nothing
|
||||||
if (!instantApp && !fullApp) {
|
if (!instantApp && !fullApp) {
|
||||||
return;
|
return;
|
||||||
@@ -13617,7 +13257,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
pkgSetting.setInstantApp(false /*instantApp*/, userId);
|
pkgSetting.setInstantApp(false /*instantApp*/, userId);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int currentUserId : sUserManager.getUserIds()) {
|
for (int currentUserId : userManager.getUserIds()) {
|
||||||
if (instantApp && !pkgSetting.getInstantApp(currentUserId)) {
|
if (instantApp && !pkgSetting.getInstantApp(currentUserId)) {
|
||||||
pkgSetting.setInstantApp(true /*instantApp*/, currentUserId);
|
pkgSetting.setInstantApp(true /*instantApp*/, currentUserId);
|
||||||
} else if (fullApp && pkgSetting.getInstantApp(currentUserId)) {
|
} else if (fullApp && pkgSetting.getInstantApp(currentUserId)) {
|
||||||
@@ -15891,16 +15531,6 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void maybeThrowExceptionForMultiArchCopy(String message, int copyRet) throws
|
|
||||||
PackageManagerException {
|
|
||||||
if (copyRet < 0) {
|
|
||||||
if (copyRet != PackageManager.NO_NATIVE_LIBRARIES &&
|
|
||||||
copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
|
|
||||||
throw new PackageManagerException(copyRet, message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logic to handle movement of existing installed applications.
|
* Logic to handle movement of existing installed applications.
|
||||||
*/
|
*/
|
||||||
@@ -16027,26 +15657,6 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Utility method that returns the relative package path with respect
|
|
||||||
// to the installation directory. Like say for /data/data/com.test-1.apk
|
|
||||||
// string com.test-1 is returned.
|
|
||||||
static String deriveCodePathName(String codePath) {
|
|
||||||
if (codePath == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
final File codeFile = new File(codePath);
|
|
||||||
final String name = codeFile.getName();
|
|
||||||
if (codeFile.isDirectory()) {
|
|
||||||
return name;
|
|
||||||
} else if (name.endsWith(".apk") || name.endsWith(".tmp")) {
|
|
||||||
final int lastDot = name.lastIndexOf('.');
|
|
||||||
return name.substring(0, lastDot);
|
|
||||||
} else {
|
|
||||||
Slog.w(TAG, "Odd, " + codePath + " doesn't look like an APK");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class PackageInstalledInfo {
|
static class PackageInstalledInfo {
|
||||||
String name;
|
String name;
|
||||||
int uid;
|
int uid;
|
||||||
@@ -16979,7 +16589,8 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
final PrepareResult prepareResult;
|
final PrepareResult prepareResult;
|
||||||
try {
|
try {
|
||||||
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
|
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
|
||||||
prepareResult = preparePackageLI(request.args, request.installResult);
|
prepareResult =
|
||||||
|
preparePackageLI(request.args, request.installResult);
|
||||||
} catch (PrepareFailure prepareFailure) {
|
} catch (PrepareFailure prepareFailure) {
|
||||||
request.installResult.setError(prepareFailure.error,
|
request.installResult.setError(prepareFailure.error,
|
||||||
prepareFailure.getMessage());
|
prepareFailure.getMessage());
|
||||||
@@ -17639,7 +17250,11 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
|
String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
|
||||||
args.abiOverride : pkg.cpuAbiOverride);
|
args.abiOverride : pkg.cpuAbiOverride);
|
||||||
final boolean extractNativeLibs = !pkg.isLibrary();
|
final boolean extractNativeLibs = !pkg.isLibrary();
|
||||||
derivePackageAbi(pkg, abiOverride, extractNativeLibs);
|
final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
|
||||||
|
derivedAbi = mInjector.getAbiHelper().derivePackageAbi(
|
||||||
|
pkg, abiOverride, extractNativeLibs);
|
||||||
|
derivedAbi.first.applyTo(pkg);
|
||||||
|
derivedAbi.second.applyTo(pkg);
|
||||||
} catch (PackageManagerException pme) {
|
} catch (PackageManagerException pme) {
|
||||||
Slog.e(TAG, "Error deriving application ABI", pme);
|
Slog.e(TAG, "Error deriving application ABI", pme);
|
||||||
throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
|
throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
|
||||||
@@ -18168,10 +17783,6 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isMultiArch(ApplicationInfo info) {
|
|
||||||
return (info.flags & ApplicationInfo.FLAG_MULTIARCH) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isExternal(PackageParser.Package pkg) {
|
private static boolean isExternal(PackageParser.Package pkg) {
|
||||||
return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
|
return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
|
||||||
}
|
}
|
||||||
@@ -18180,7 +17791,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
return (ps.pkgFlags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
|
return (ps.pkgFlags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isSystemApp(PackageParser.Package pkg) {
|
static boolean isSystemApp(PackageParser.Package pkg) {
|
||||||
return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
|
return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -270,7 +270,8 @@ public abstract class PackageSettingBase extends SettingBase {
|
|||||||
updateAvailable = orig.updateAvailable;
|
updateAvailable = orig.updateAvailable;
|
||||||
}
|
}
|
||||||
|
|
||||||
private PackageUserState modifyUserState(int userId) {
|
@VisibleForTesting
|
||||||
|
PackageUserState modifyUserState(int userId) {
|
||||||
PackageUserState state = mUserState.get(userId);
|
PackageUserState state = mUserState.get(userId);
|
||||||
if (state == null) {
|
if (state == null) {
|
||||||
state = new PackageUserState();
|
state = new PackageUserState();
|
||||||
@@ -463,6 +464,18 @@ public abstract class PackageSettingBase extends SettingBase {
|
|||||||
state.harmfulAppWarning = harmfulAppWarning;
|
state.harmfulAppWarning = harmfulAppWarning;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setUserState(int userId, PackageUserState otherState) {
|
||||||
|
setUserState(userId, otherState.ceDataInode, otherState.enabled, otherState.installed,
|
||||||
|
otherState.stopped, otherState.notLaunched, otherState.hidden,
|
||||||
|
otherState.distractionFlags, otherState.suspended, otherState.suspendingPackage,
|
||||||
|
otherState.dialogInfo, otherState.suspendedAppExtras,
|
||||||
|
otherState.suspendedLauncherExtras, otherState.instantApp,
|
||||||
|
otherState.virtualPreload, otherState.lastDisableAppCaller,
|
||||||
|
otherState.enabledComponents, otherState.disabledComponents,
|
||||||
|
otherState.domainVerificationStatus, otherState.appLinkGeneration,
|
||||||
|
otherState.installReason, otherState.harmfulAppWarning);
|
||||||
|
}
|
||||||
|
|
||||||
ArraySet<String> getEnabledComponents(int userId) {
|
ArraySet<String> getEnabledComponents(int userId) {
|
||||||
return readUserState(userId).enabledComponents;
|
return readUserState(userId).enabledComponents;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,20 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "CtsCompilationTestCases"
|
"name": "CtsCompilationTestCases"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "FrameworksServicesTests",
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"include-filter": "com.android.server.pm."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"include-annotation": "android.platform.test.annotations.Presubmit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exclude-annotation": "androidx.test.filters.FlakyTest"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"imports": [
|
"imports": [
|
||||||
|
|||||||
@@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* 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 com.android.server.pm;
|
||||||
|
|
||||||
|
import android.content.pm.PackageParser;
|
||||||
|
|
||||||
|
import com.android.internal.util.ArrayUtils;
|
||||||
|
|
||||||
|
class PackageBuilder {
|
||||||
|
final PackageParser.Package mPkg;
|
||||||
|
|
||||||
|
PackageBuilder(String packageName) {
|
||||||
|
mPkg = new PackageParser.Package(packageName);
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageBuilder setApplicationInfoCodePath(String codePath) {
|
||||||
|
mPkg.applicationInfo.setCodePath(codePath);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageBuilder setApplicationInfoResourcePath(String resourcePath) {
|
||||||
|
mPkg.applicationInfo.setResourcePath(resourcePath);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageBuilder setCodePath(String codePath) {
|
||||||
|
mPkg.codePath = codePath;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageBuilder setBaseCodePath(String baseCodePath) {
|
||||||
|
mPkg.baseCodePath = baseCodePath;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageBuilder addUsesStaticLibrary(String name, long version) {
|
||||||
|
mPkg.usesStaticLibraries = ArrayUtils.add(mPkg.usesStaticLibraries, name);
|
||||||
|
mPkg.usesStaticLibrariesVersions =
|
||||||
|
ArrayUtils.appendLong(mPkg.usesStaticLibrariesVersions, version);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageBuilder setApplicationInfoNativeLibraryRootDir(String dir) {
|
||||||
|
mPkg.applicationInfo.nativeLibraryRootDir = dir;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageBuilder setStaticSharedLib(String staticSharedLibName, long staticSharedLibVersion) {
|
||||||
|
mPkg.staticSharedLibVersion = staticSharedLibVersion;
|
||||||
|
mPkg.staticSharedLibName = staticSharedLibName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageBuilder setManifestPackageName(String manifestPackageName) {
|
||||||
|
mPkg.manifestPackageName = manifestPackageName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageBuilder setVersionCodeMajor(int versionCodeMajor) {
|
||||||
|
mPkg.mVersionCodeMajor = versionCodeMajor;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageBuilder setVersionCode(int versionCode) {
|
||||||
|
mPkg.mVersionCode = versionCode;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageBuilder addSplitCodePath(String splitCodePath) {
|
||||||
|
mPkg.splitCodePaths =
|
||||||
|
ArrayUtils.appendElement(String.class, mPkg.splitCodePaths, splitCodePath);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageBuilder setApplicationInfoVolumeUuid(String volumeUuid) {
|
||||||
|
mPkg.applicationInfo.volumeUuid = volumeUuid;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageBuilder addLibraryName(String libraryName) {
|
||||||
|
mPkg.libraryNames = ArrayUtils.add(mPkg.libraryNames, libraryName);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageBuilder setRealPackageName(String realPackageName) {
|
||||||
|
mPkg.mRealPackage = realPackageName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageBuilder setCpuAbiOVerride(String cpuAbiOverride) {
|
||||||
|
mPkg.cpuAbiOverride = cpuAbiOverride;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageBuilder addPermissionRequest(String permissionName) {
|
||||||
|
mPkg.requestedPermissions.add(permissionName);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageParser.Package build() {
|
||||||
|
return mPkg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackageBuilder addApplicationInfoFlag(int flag) {
|
||||||
|
mPkg.applicationInfo.flags |= flag;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
/*
|
||||||
|
* 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 com.android.server.pm;
|
||||||
|
|
||||||
|
import android.content.pm.PackageUserState;
|
||||||
|
import android.util.SparseArray;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
class PackageSettingBuilder {
|
||||||
|
private String mName;
|
||||||
|
private String mRealName;
|
||||||
|
private String mCodePath;
|
||||||
|
private String mResourcePath;
|
||||||
|
private String mLegacyNativeLibraryPathString;
|
||||||
|
private String mPrimaryCpuAbiString;
|
||||||
|
private String mSecondaryCpuAbiString;
|
||||||
|
private String mCpuAbiOverrideString;
|
||||||
|
private long mPVersionCode;
|
||||||
|
private int mPkgFlags;
|
||||||
|
private int mPrivateFlags;
|
||||||
|
private String mParentPackageName;
|
||||||
|
private List<String> mChildPackageNames;
|
||||||
|
private int mSharedUserId;
|
||||||
|
private String[] mUsesStaticLibraries;
|
||||||
|
private long[] mUsesStaticLibrariesVersions;
|
||||||
|
private String mVolumeUuid;
|
||||||
|
private SparseArray<PackageUserState> mUserStates = new SparseArray<>();
|
||||||
|
|
||||||
|
public PackageSettingBuilder setName(String name) {
|
||||||
|
this.mName = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackageSettingBuilder setRealName(String realName) {
|
||||||
|
this.mRealName = realName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackageSettingBuilder setCodePath(String codePath) {
|
||||||
|
this.mCodePath = codePath;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackageSettingBuilder setResourcePath(String resourcePath) {
|
||||||
|
this.mResourcePath = resourcePath;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackageSettingBuilder setLegacyNativeLibraryPathString(
|
||||||
|
String legacyNativeLibraryPathString) {
|
||||||
|
this.mLegacyNativeLibraryPathString = legacyNativeLibraryPathString;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackageSettingBuilder setPrimaryCpuAbiString(String primaryCpuAbiString) {
|
||||||
|
this.mPrimaryCpuAbiString = primaryCpuAbiString;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackageSettingBuilder setSecondaryCpuAbiString(String secondaryCpuAbiString) {
|
||||||
|
this.mSecondaryCpuAbiString = secondaryCpuAbiString;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackageSettingBuilder setCpuAbiOverrideString(String cpuAbiOverrideString) {
|
||||||
|
this.mCpuAbiOverrideString = cpuAbiOverrideString;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackageSettingBuilder setPVersionCode(long pVersionCode) {
|
||||||
|
this.mPVersionCode = pVersionCode;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackageSettingBuilder setPkgFlags(int pkgFlags) {
|
||||||
|
this.mPkgFlags = pkgFlags;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackageSettingBuilder setPrivateFlags(int privateFlags) {
|
||||||
|
this.mPrivateFlags = privateFlags;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackageSettingBuilder setParentPackageName(String parentPackageName) {
|
||||||
|
this.mParentPackageName = parentPackageName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackageSettingBuilder setChildPackageNames(List<String> childPackageNames) {
|
||||||
|
this.mChildPackageNames = childPackageNames;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackageSettingBuilder setSharedUserId(int sharedUserId) {
|
||||||
|
this.mSharedUserId = sharedUserId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackageSettingBuilder setUsesStaticLibraries(String[] usesStaticLibraries) {
|
||||||
|
this.mUsesStaticLibraries = usesStaticLibraries;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackageSettingBuilder setUsesStaticLibrariesVersions(
|
||||||
|
long[] usesStaticLibrariesVersions) {
|
||||||
|
this.mUsesStaticLibrariesVersions = usesStaticLibrariesVersions;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackageSettingBuilder setVolumeUuid(String volumeUuid) {
|
||||||
|
this.mVolumeUuid = volumeUuid;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackageSettingBuilder setInstantAppUserState(int userId, boolean isInstant) {
|
||||||
|
if (mUserStates.indexOfKey(userId) < 0) {
|
||||||
|
mUserStates.put(userId, new PackageUserState());
|
||||||
|
}
|
||||||
|
mUserStates.get(userId).instantApp = isInstant;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackageSetting build() {
|
||||||
|
final PackageSetting packageSetting = new PackageSetting(mName, mRealName,
|
||||||
|
new File(mCodePath), new File(mResourcePath),
|
||||||
|
mLegacyNativeLibraryPathString, mPrimaryCpuAbiString, mSecondaryCpuAbiString,
|
||||||
|
mCpuAbiOverrideString, mPVersionCode, mPkgFlags, mPrivateFlags, mParentPackageName,
|
||||||
|
mChildPackageNames, mSharedUserId, mUsesStaticLibraries,
|
||||||
|
mUsesStaticLibrariesVersions);
|
||||||
|
packageSetting.volumeUuid = this.mVolumeUuid;
|
||||||
|
for (int i = 0; i < mUserStates.size(); i++) {
|
||||||
|
packageSetting.setUserState(mUserStates.keyAt(i), mUserStates.valueAt(i));
|
||||||
|
}
|
||||||
|
return packageSetting;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* 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 com.android.server.pm;
|
||||||
|
|
||||||
|
import android.content.pm.PackageParser;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
|
||||||
|
class ScanRequestBuilder {
|
||||||
|
private final PackageParser.Package mPkg;
|
||||||
|
private PackageParser.Package mOldPkg;
|
||||||
|
private SharedUserSetting mSharedUserSetting;
|
||||||
|
private PackageSetting mPkgSetting;
|
||||||
|
private PackageSetting mDisabledPkgSetting;
|
||||||
|
private PackageSetting mOriginalPkgSetting;
|
||||||
|
private String mRealPkgName;
|
||||||
|
private int mParseFlags;
|
||||||
|
private int mScanFlags;
|
||||||
|
private UserHandle mUser;
|
||||||
|
private boolean mIsPlatformPackage;
|
||||||
|
|
||||||
|
ScanRequestBuilder(PackageParser.Package pkg) {
|
||||||
|
this.mPkg = pkg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScanRequestBuilder setOldPkg(PackageParser.Package oldPkg) {
|
||||||
|
this.mOldPkg = oldPkg;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScanRequestBuilder setSharedUserSetting(SharedUserSetting sharedUserSetting) {
|
||||||
|
this.mSharedUserSetting = sharedUserSetting;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScanRequestBuilder setPkgSetting(PackageSetting pkgSetting) {
|
||||||
|
this.mPkgSetting = pkgSetting;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScanRequestBuilder setDisabledPkgSetting(PackageSetting disabledPkgSetting) {
|
||||||
|
this.mDisabledPkgSetting = disabledPkgSetting;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScanRequestBuilder setOriginalPkgSetting(PackageSetting originalPkgSetting) {
|
||||||
|
this.mOriginalPkgSetting = originalPkgSetting;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScanRequestBuilder setRealPkgName(String realPkgName) {
|
||||||
|
this.mRealPkgName = realPkgName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScanRequestBuilder setParseFlags(int parseFlags) {
|
||||||
|
this.mParseFlags = parseFlags;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScanRequestBuilder addParseFlag(int parseFlag) {
|
||||||
|
this.mParseFlags |= parseFlag;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScanRequestBuilder setScanFlags(int scanFlags) {
|
||||||
|
this.mScanFlags = scanFlags;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScanRequestBuilder addScanFlag(int scanFlag) {
|
||||||
|
this.mScanFlags |= scanFlag;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScanRequestBuilder setUser(UserHandle user) {
|
||||||
|
this.mUser = user;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScanRequestBuilder setIsPlatformPackage(boolean isPlatformPackage) {
|
||||||
|
this.mIsPlatformPackage = isPlatformPackage;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageManagerService.ScanRequest build() {
|
||||||
|
return new PackageManagerService.ScanRequest(
|
||||||
|
mPkg, mSharedUserSetting, mOldPkg, mPkgSetting, mDisabledPkgSetting,
|
||||||
|
mOriginalPkgSetting, mRealPkgName, mParseFlags, mScanFlags, mIsPlatformPackage,
|
||||||
|
mUser);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,551 @@
|
|||||||
|
/*
|
||||||
|
* 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 com.android.server.pm;
|
||||||
|
|
||||||
|
import static android.content.pm.SharedLibraryInfo.TYPE_DYNAMIC;
|
||||||
|
import static android.content.pm.SharedLibraryInfo.TYPE_STATIC;
|
||||||
|
import static android.content.pm.SharedLibraryInfo.VERSION_UNDEFINED;
|
||||||
|
|
||||||
|
import static com.android.server.pm.PackageManagerService.SCAN_AS_FULL_APP;
|
||||||
|
import static com.android.server.pm.PackageManagerService.SCAN_AS_INSTANT_APP;
|
||||||
|
import static com.android.server.pm.PackageManagerService.SCAN_FIRST_BOOT_OR_UPGRADE;
|
||||||
|
import static com.android.server.pm.PackageManagerService.SCAN_NEW_INSTALL;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.empty;
|
||||||
|
import static org.hamcrest.Matchers.hasItems;
|
||||||
|
import static org.hamcrest.Matchers.nullValue;
|
||||||
|
import static org.hamcrest.collection.IsArrayContainingInOrder.arrayContaining;
|
||||||
|
import static org.hamcrest.core.Is.is;
|
||||||
|
import static org.junit.Assert.assertNotSame;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||||
|
import static org.mockito.ArgumentMatchers.nullable;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
|
import android.content.pm.PackageParser;
|
||||||
|
import android.content.pm.SharedLibraryInfo;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
import android.os.UserManagerInternal;
|
||||||
|
import android.platform.test.annotations.Presubmit;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
|
import org.hamcrest.BaseMatcher;
|
||||||
|
import org.hamcrest.Description;
|
||||||
|
import org.hamcrest.Matcher;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
@Presubmit
|
||||||
|
// TODO: shared user tests
|
||||||
|
public class ScanTests {
|
||||||
|
|
||||||
|
private static final String DUMMY_PACKAGE_NAME = "some.app.to.test";
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
PackageAbiHelper mMockPackageAbiHelper;
|
||||||
|
@Mock
|
||||||
|
UserManagerInternal mMockUserManager;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setupDefaultUser() {
|
||||||
|
when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setupDefaultAbiBehavior() throws Exception {
|
||||||
|
when(mMockPackageAbiHelper.derivePackageAbi(
|
||||||
|
any(PackageParser.Package.class), nullable(String.class), anyBoolean()))
|
||||||
|
.thenReturn(new Pair<>(
|
||||||
|
new PackageAbiHelper.Abis("derivedPrimary", "derivedSecondary"),
|
||||||
|
new PackageAbiHelper.NativeLibraryPaths(
|
||||||
|
"derivedRootDir", true, "derivedNativeDir", "derivedNativeDir2")));
|
||||||
|
when(mMockPackageAbiHelper.getNativeLibraryPaths(
|
||||||
|
any(PackageParser.Package.class), any(File.class)))
|
||||||
|
.thenReturn(new PackageAbiHelper.NativeLibraryPaths(
|
||||||
|
"getRootDir", true, "getNativeDir", "getNativeDir2"
|
||||||
|
));
|
||||||
|
when(mMockPackageAbiHelper.getBundledAppAbis(
|
||||||
|
any(PackageParser.Package.class)))
|
||||||
|
.thenReturn(new PackageAbiHelper.Abis("bundledPrimary", "bundledSecondary"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void newInstallSimpleAllNominal() throws Exception {
|
||||||
|
final PackageManagerService.ScanRequest scanRequest =
|
||||||
|
createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
|
||||||
|
.addScanFlag(PackageManagerService.SCAN_NEW_INSTALL)
|
||||||
|
.addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
|
||||||
|
|
||||||
|
assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
|
||||||
|
assertThat(scanResult.existingSettingCopied, is(false));
|
||||||
|
assertPathsNotDerived(scanResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void newInstallForAllUsers() throws Exception {
|
||||||
|
final int[] userIds = {0, 10, 11};
|
||||||
|
when(mMockUserManager.getUserIds()).thenReturn(userIds);
|
||||||
|
|
||||||
|
final PackageManagerService.ScanRequest scanRequest =
|
||||||
|
createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
|
||||||
|
.setRealPkgName(null)
|
||||||
|
.addScanFlag(PackageManagerService.SCAN_NEW_INSTALL)
|
||||||
|
.addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
|
||||||
|
.build();
|
||||||
|
final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
|
||||||
|
|
||||||
|
for (int uid : userIds) {
|
||||||
|
assertThat(scanResult.pkgSetting.readUserState(uid).installed, is(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void installRealPackageName() throws Exception {
|
||||||
|
final PackageManagerService.ScanRequest scanRequest =
|
||||||
|
createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
|
||||||
|
.setRealPkgName("com.package.real")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
|
||||||
|
|
||||||
|
assertThat(scanResult.pkgSetting.realName, is("com.package.real"));
|
||||||
|
|
||||||
|
final PackageManagerService.ScanRequest scanRequestNoRealPkg =
|
||||||
|
createBasicScanRequestBuilder(
|
||||||
|
createBasicPackage(DUMMY_PACKAGE_NAME)
|
||||||
|
.setRealPackageName("com.package.real").build())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final PackageManagerService.ScanResult scanResultNoReal = executeScan(scanRequestNoRealPkg);
|
||||||
|
assertThat(scanResultNoReal.pkgSetting.realName, nullValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateSimpleNominal() throws Exception {
|
||||||
|
when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
|
||||||
|
|
||||||
|
final PackageSetting pkgSetting = createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
|
||||||
|
.setPrimaryCpuAbiString("primaryCpuAbi")
|
||||||
|
.setSecondaryCpuAbiString("secondaryCpuAbi")
|
||||||
|
.build();
|
||||||
|
final PackageManagerService.ScanRequest scanRequest =
|
||||||
|
createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
|
||||||
|
.addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
|
||||||
|
.setPkgSetting(pkgSetting)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
|
||||||
|
final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
|
||||||
|
|
||||||
|
assertThat(scanResult.existingSettingCopied, is(true));
|
||||||
|
|
||||||
|
// ensure we don't overwrite the existing pkgSetting, in case something post-scan fails
|
||||||
|
assertNotSame(pkgSetting, scanResult.pkgSetting);
|
||||||
|
|
||||||
|
assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
|
||||||
|
|
||||||
|
assertThat(scanResult.pkgSetting.primaryCpuAbiString, is("primaryCpuAbi"));
|
||||||
|
assertThat(scanResult.pkgSetting.secondaryCpuAbiString, is("secondaryCpuAbi"));
|
||||||
|
assertThat(scanResult.pkgSetting.cpuAbiOverrideString, nullValue());
|
||||||
|
|
||||||
|
assertPathsNotDerived(scanResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateInstantSimpleNominal() throws Exception {
|
||||||
|
when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
|
||||||
|
|
||||||
|
final PackageSetting existingPkgSetting =
|
||||||
|
createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
|
||||||
|
.setInstantAppUserState(0, true)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final PackageManagerService.ScanRequest scanRequest =
|
||||||
|
createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
|
||||||
|
.setPkgSetting(existingPkgSetting)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
|
||||||
|
final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
|
||||||
|
|
||||||
|
assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, true /*isInstant*/);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void installStaticSharedLibrary() throws Exception {
|
||||||
|
final PackageParser.Package pkg = createBasicPackage("static.lib.pkg.123")
|
||||||
|
.setStaticSharedLib("static.lib", 123L)
|
||||||
|
.setManifestPackageName("static.lib.pkg")
|
||||||
|
.setVersionCodeMajor(1)
|
||||||
|
.setVersionCode(234)
|
||||||
|
.setBaseCodePath("/some/path.apk")
|
||||||
|
.addSplitCodePath("/some/other/path.apk")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final PackageManagerService.ScanRequest scanRequest = new ScanRequestBuilder(
|
||||||
|
pkg).setUser(UserHandle.of(0)).build();
|
||||||
|
|
||||||
|
|
||||||
|
final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
|
||||||
|
|
||||||
|
assertThat(scanResult.staticSharedLibraryInfo.getPackageName(), is("static.lib.pkg.123"));
|
||||||
|
assertThat(scanResult.staticSharedLibraryInfo.getName(), is("static.lib"));
|
||||||
|
assertThat(scanResult.staticSharedLibraryInfo.getLongVersion(), is(123L));
|
||||||
|
assertThat(scanResult.staticSharedLibraryInfo.getType(), is(TYPE_STATIC));
|
||||||
|
assertThat(scanResult.staticSharedLibraryInfo.getDeclaringPackage().getPackageName(),
|
||||||
|
is("static.lib.pkg"));
|
||||||
|
assertThat(scanResult.staticSharedLibraryInfo.getDeclaringPackage().getLongVersionCode(),
|
||||||
|
is(pkg.getLongVersionCode()));
|
||||||
|
assertThat(scanResult.staticSharedLibraryInfo.getAllCodePaths(),
|
||||||
|
hasItems("/some/path.apk", "/some/other/path.apk"));
|
||||||
|
assertThat(scanResult.staticSharedLibraryInfo.getDependencies(), nullValue());
|
||||||
|
assertThat(scanResult.staticSharedLibraryInfo.getDependentPackages(), empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void installDynamicLibraries() throws Exception {
|
||||||
|
final PackageParser.Package pkg = createBasicPackage("dynamic.lib.pkg")
|
||||||
|
.setManifestPackageName("dynamic.lib.pkg")
|
||||||
|
.addLibraryName("liba")
|
||||||
|
.addLibraryName("libb")
|
||||||
|
.setVersionCodeMajor(1)
|
||||||
|
.setVersionCode(234)
|
||||||
|
.setBaseCodePath("/some/path.apk")
|
||||||
|
.addSplitCodePath("/some/other/path.apk")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final PackageManagerService.ScanRequest scanRequest =
|
||||||
|
new ScanRequestBuilder(pkg).setUser(UserHandle.of(0)).build();
|
||||||
|
|
||||||
|
|
||||||
|
final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
|
||||||
|
|
||||||
|
final SharedLibraryInfo dynamicLib0 = scanResult.dynamicSharedLibraryInfos.get(0);
|
||||||
|
assertThat(dynamicLib0.getPackageName(), is("dynamic.lib.pkg"));
|
||||||
|
assertThat(dynamicLib0.getName(), is("liba"));
|
||||||
|
assertThat(dynamicLib0.getLongVersion(), is((long) VERSION_UNDEFINED));
|
||||||
|
assertThat(dynamicLib0.getType(), is(TYPE_DYNAMIC));
|
||||||
|
assertThat(dynamicLib0.getDeclaringPackage().getPackageName(), is("dynamic.lib.pkg"));
|
||||||
|
assertThat(dynamicLib0.getDeclaringPackage().getLongVersionCode(),
|
||||||
|
is(pkg.getLongVersionCode()));
|
||||||
|
assertThat(dynamicLib0.getAllCodePaths(),
|
||||||
|
hasItems("/some/path.apk", "/some/other/path.apk"));
|
||||||
|
assertThat(dynamicLib0.getDependencies(), nullValue());
|
||||||
|
assertThat(dynamicLib0.getDependentPackages(), empty());
|
||||||
|
|
||||||
|
final SharedLibraryInfo dynamicLib1 = scanResult.dynamicSharedLibraryInfos.get(1);
|
||||||
|
assertThat(dynamicLib1.getPackageName(), is("dynamic.lib.pkg"));
|
||||||
|
assertThat(dynamicLib1.getName(), is("libb"));
|
||||||
|
assertThat(dynamicLib1.getLongVersion(), is((long) VERSION_UNDEFINED));
|
||||||
|
assertThat(dynamicLib1.getType(), is(TYPE_DYNAMIC));
|
||||||
|
assertThat(dynamicLib1.getDeclaringPackage().getPackageName(), is("dynamic.lib.pkg"));
|
||||||
|
assertThat(dynamicLib1.getDeclaringPackage().getLongVersionCode(),
|
||||||
|
is(pkg.getLongVersionCode()));
|
||||||
|
assertThat(dynamicLib1.getAllCodePaths(),
|
||||||
|
hasItems("/some/path.apk", "/some/other/path.apk"));
|
||||||
|
assertThat(dynamicLib1.getDependencies(), nullValue());
|
||||||
|
assertThat(dynamicLib1.getDependentPackages(), empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void volumeUuidChangesOnUpdate() throws Exception {
|
||||||
|
final PackageSetting pkgSetting =
|
||||||
|
createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
|
||||||
|
.setVolumeUuid("someUuid")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final PackageParser.Package basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
|
||||||
|
.setApplicationInfoVolumeUuid("someNewUuid")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
|
||||||
|
final PackageManagerService.ScanResult scanResult = executeScan(
|
||||||
|
new ScanRequestBuilder(basicPackage).setPkgSetting(pkgSetting).build());
|
||||||
|
|
||||||
|
assertThat(scanResult.pkgSetting.volumeUuid, is("someNewUuid"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void scanFirstBoot_derivesAbis() throws Exception {
|
||||||
|
final PackageSetting pkgSetting =
|
||||||
|
createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME).build();
|
||||||
|
|
||||||
|
final PackageParser.Package basicPackage =
|
||||||
|
createBasicPackage(DUMMY_PACKAGE_NAME)
|
||||||
|
.setCpuAbiOVerride("testOverride")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
|
||||||
|
final PackageManagerService.ScanResult scanResult = executeScan(new ScanRequestBuilder(
|
||||||
|
basicPackage)
|
||||||
|
.setPkgSetting(pkgSetting)
|
||||||
|
.addScanFlag(SCAN_FIRST_BOOT_OR_UPGRADE)
|
||||||
|
.build());
|
||||||
|
|
||||||
|
assertAbiAndPathssDerived(scanResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void scanWithOriginalPkgSetting_packageNameChanges() throws Exception {
|
||||||
|
final PackageSetting originalPkgSetting =
|
||||||
|
createBasicPackageSettingBuilder("original.package").build();
|
||||||
|
|
||||||
|
final PackageParser.Package basicPackage =
|
||||||
|
createBasicPackage(DUMMY_PACKAGE_NAME)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
|
||||||
|
final PackageManagerService.ScanResult result =
|
||||||
|
executeScan(new ScanRequestBuilder(basicPackage)
|
||||||
|
.setOriginalPkgSetting(originalPkgSetting)
|
||||||
|
.build());
|
||||||
|
|
||||||
|
assertThat(result.request.pkg.packageName, is("original.package"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateInstant_changeToFull() throws Exception {
|
||||||
|
when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
|
||||||
|
|
||||||
|
final PackageSetting existingPkgSetting =
|
||||||
|
createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
|
||||||
|
.setInstantAppUserState(0, true)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final PackageManagerService.ScanRequest scanRequest =
|
||||||
|
createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
|
||||||
|
.setPkgSetting(existingPkgSetting)
|
||||||
|
.addScanFlag(SCAN_AS_FULL_APP)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
|
||||||
|
final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
|
||||||
|
|
||||||
|
assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateFull_changeToInstant() throws Exception {
|
||||||
|
when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
|
||||||
|
|
||||||
|
final PackageSetting existingPkgSetting =
|
||||||
|
createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
|
||||||
|
.setInstantAppUserState(0, false)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final PackageManagerService.ScanRequest scanRequest =
|
||||||
|
createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
|
||||||
|
.setPkgSetting(existingPkgSetting)
|
||||||
|
.addScanFlag(SCAN_AS_INSTANT_APP)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
|
||||||
|
final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
|
||||||
|
|
||||||
|
assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, true /*isInstant*/);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateSystemApp_applicationInfoFlagSet() throws Exception {
|
||||||
|
final PackageSetting existingPkgSetting =
|
||||||
|
createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
|
||||||
|
.setPkgFlags(ApplicationInfo.FLAG_SYSTEM)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final PackageManagerService.ScanRequest scanRequest =
|
||||||
|
createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
|
||||||
|
.setPkgSetting(existingPkgSetting)
|
||||||
|
.setDisabledPkgSetting(existingPkgSetting)
|
||||||
|
.addScanFlag(SCAN_NEW_INSTALL)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
|
||||||
|
|
||||||
|
assertThat(scanResult.request.pkg.applicationInfo.flags,
|
||||||
|
hasFlag(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void factoryTestFlagSet() throws Exception {
|
||||||
|
final PackageParser.Package basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
|
||||||
|
.addPermissionRequest(Manifest.permission.FACTORY_TEST)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final PackageManagerService.ScanResult scanResult = PackageManagerService.scanPackageOnlyLI(
|
||||||
|
createBasicScanRequestBuilder(basicPackage).build(),
|
||||||
|
new PackageManagerService.Injector(mMockUserManager, mMockPackageAbiHelper),
|
||||||
|
true /*isUnderFactoryTest*/,
|
||||||
|
System.currentTimeMillis());
|
||||||
|
|
||||||
|
assertThat(scanResult.request.pkg.applicationInfo.flags,
|
||||||
|
hasFlag(ApplicationInfo.FLAG_FACTORY_TEST));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void scanSystemApp_isOrphanedTrue() throws Exception {
|
||||||
|
final PackageParser.Package pkg = createBasicPackage(DUMMY_PACKAGE_NAME)
|
||||||
|
.addApplicationInfoFlag(ApplicationInfo.FLAG_SYSTEM)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final PackageManagerService.ScanRequest scanRequest =
|
||||||
|
createBasicScanRequestBuilder(pkg)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
|
||||||
|
|
||||||
|
assertThat(scanResult.pkgSetting.isOrphaned, is(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Matcher<Integer> hasFlag(final int flag) {
|
||||||
|
return new BaseMatcher<Integer>() {
|
||||||
|
@Override public void describeTo(Description description) {
|
||||||
|
description.appendText("flags ");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public boolean matches(Object item) {
|
||||||
|
return ((int) item & flag) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void describeMismatch(Object item, Description mismatchDescription) {
|
||||||
|
mismatchDescription
|
||||||
|
.appendValue(item)
|
||||||
|
.appendText(" does not contain flag ")
|
||||||
|
.appendValue(flag);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private PackageManagerService.ScanResult executeScan(
|
||||||
|
PackageManagerService.ScanRequest scanRequest) throws PackageManagerException {
|
||||||
|
return PackageManagerService.scanPackageOnlyLI(
|
||||||
|
scanRequest,
|
||||||
|
new PackageManagerService.Injector(mMockUserManager, mMockPackageAbiHelper),
|
||||||
|
false /*isUnderFactoryTest*/,
|
||||||
|
System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String createResourcePath(String packageName) {
|
||||||
|
return "/data/app/" + packageName + "-randompath/base.apk";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String createCodePath(String packageName) {
|
||||||
|
return "/data/app/" + packageName + "-randompath";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PackageSettingBuilder createBasicPackageSettingBuilder(String packageName) {
|
||||||
|
return new PackageSettingBuilder()
|
||||||
|
.setName(packageName)
|
||||||
|
.setCodePath(createCodePath(packageName))
|
||||||
|
.setResourcePath(createResourcePath(packageName));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ScanRequestBuilder createBasicScanRequestBuilder(PackageParser.Package pkg) {
|
||||||
|
return new ScanRequestBuilder(pkg)
|
||||||
|
.setUser(UserHandle.of(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static PackageBuilder createBasicPackage(String packageName) {
|
||||||
|
return new PackageBuilder(packageName)
|
||||||
|
.setCodePath("/data/tmp/randompath")
|
||||||
|
.setApplicationInfoCodePath(createCodePath(packageName))
|
||||||
|
.setApplicationInfoResourcePath(createResourcePath(packageName))
|
||||||
|
.setApplicationInfoVolumeUuid("volumeUuid")
|
||||||
|
.setBaseCodePath("/data/tmp/randompath/base.apk")
|
||||||
|
.addUsesStaticLibrary("some.static.library", 234L)
|
||||||
|
.addUsesStaticLibrary("some.other.static.library", 456L)
|
||||||
|
.setApplicationInfoNativeLibraryRootDir("/data/tmp/randompath/base.apk:/lib")
|
||||||
|
.setVersionCodeMajor(1)
|
||||||
|
.setVersionCode(2345);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertBasicPackageScanResult(
|
||||||
|
PackageManagerService.ScanResult scanResult, String packageName, boolean isInstant) {
|
||||||
|
assertThat(scanResult.success, is(true));
|
||||||
|
|
||||||
|
final PackageSetting pkgSetting = scanResult.pkgSetting;
|
||||||
|
assertBasicPackageSetting(scanResult, packageName, isInstant, pkgSetting);
|
||||||
|
|
||||||
|
final ApplicationInfo applicationInfo = pkgSetting.pkg.applicationInfo;
|
||||||
|
assertBasicApplicationInfo(scanResult, applicationInfo);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertBasicPackageSetting(PackageManagerService.ScanResult scanResult,
|
||||||
|
String packageName, boolean isInstant, PackageSetting pkgSetting) {
|
||||||
|
assertThat(pkgSetting.pkg.packageName, is(packageName));
|
||||||
|
assertThat(pkgSetting.getInstantApp(0), is(isInstant));
|
||||||
|
assertThat(pkgSetting.usesStaticLibraries,
|
||||||
|
arrayContaining("some.static.library", "some.other.static.library"));
|
||||||
|
assertThat(pkgSetting.usesStaticLibrariesVersions, is(new long[]{234L, 456L}));
|
||||||
|
assertThat(pkgSetting.pkg, is(scanResult.request.pkg));
|
||||||
|
assertThat(pkgSetting.pkg.mExtras, is(pkgSetting));
|
||||||
|
assertThat(pkgSetting.codePath, is(new File(createCodePath(packageName))));
|
||||||
|
assertThat(pkgSetting.resourcePath, is(new File(createResourcePath(packageName))));
|
||||||
|
assertThat(pkgSetting.versionCode, is(PackageInfo.composeLongVersionCode(1, 2345)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertBasicApplicationInfo(PackageManagerService.ScanResult scanResult,
|
||||||
|
ApplicationInfo applicationInfo) {
|
||||||
|
assertThat(applicationInfo.processName, is(scanResult.request.pkg.packageName));
|
||||||
|
|
||||||
|
final int uid = applicationInfo.uid;
|
||||||
|
assertThat(UserHandle.getUserId(uid), is(UserHandle.USER_SYSTEM));
|
||||||
|
|
||||||
|
final String calculatedCredentialId = Environment.getDataUserCePackageDirectory(
|
||||||
|
applicationInfo.volumeUuid, UserHandle.USER_SYSTEM,
|
||||||
|
scanResult.request.pkg.packageName).getAbsolutePath();
|
||||||
|
assertThat(applicationInfo.credentialProtectedDataDir, is(calculatedCredentialId));
|
||||||
|
assertThat(applicationInfo.dataDir, is(applicationInfo.credentialProtectedDataDir));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertAbiAndPathssDerived(PackageManagerService.ScanResult scanResult) {
|
||||||
|
final ApplicationInfo applicationInfo = scanResult.pkgSetting.pkg.applicationInfo;
|
||||||
|
assertThat(applicationInfo.primaryCpuAbi, is("derivedPrimary"));
|
||||||
|
assertThat(applicationInfo.secondaryCpuAbi, is("derivedSecondary"));
|
||||||
|
|
||||||
|
assertThat(applicationInfo.nativeLibraryRootDir, is("derivedRootDir"));
|
||||||
|
assertThat(scanResult.pkgSetting.legacyNativeLibraryPathString, is("derivedRootDir"));
|
||||||
|
assertThat(applicationInfo.nativeLibraryRootRequiresIsa, is(true));
|
||||||
|
assertThat(applicationInfo.nativeLibraryDir, is("derivedNativeDir"));
|
||||||
|
assertThat(applicationInfo.secondaryNativeLibraryDir, is("derivedNativeDir2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertPathsNotDerived(PackageManagerService.ScanResult scanResult) {
|
||||||
|
final ApplicationInfo applicationInfo = scanResult.pkgSetting.pkg.applicationInfo;
|
||||||
|
assertThat(applicationInfo.nativeLibraryRootDir, is("getRootDir"));
|
||||||
|
assertThat(scanResult.pkgSetting.legacyNativeLibraryPathString, is("getRootDir"));
|
||||||
|
assertThat(applicationInfo.nativeLibraryRootRequiresIsa, is(true));
|
||||||
|
assertThat(applicationInfo.nativeLibraryDir, is("getNativeDir"));
|
||||||
|
assertThat(applicationInfo.secondaryNativeLibraryDir, is("getNativeDir2"));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user