Merge "Slow progress towards APK clusters."

This commit is contained in:
Jeff Sharkey
2014-07-03 02:08:47 +00:00
committed by Android (Google) Code Review
11 changed files with 366 additions and 325 deletions

View File

@@ -413,6 +413,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
/**
* Full path to the base APK for this application.
*/
// TODO: verify that nobody is doing codePath comparisons against this
public String sourceDir;
/**

View File

@@ -279,11 +279,11 @@ public class PackageParser {
mMetrics = metrics;
}
private static final boolean isPackageFilename(File file) {
public static final boolean isPackageFilename(File file) {
return isPackageFilename(file.getName());
}
private static final boolean isPackageFilename(String name) {
public static final boolean isPackageFilename(String name) {
return name.endsWith(".apk");
}
@@ -552,7 +552,7 @@ public class PackageParser {
* Note that this <em>does not</em> perform signature verification; that
* must be done separately in {@link #collectCertificates(Package, int)}.
*/
public Package parseSplitPackage(File apkDir, int flags) throws PackageParserException {
public Package parseClusterPackage(File apkDir, int flags) throws PackageParserException {
final File[] files = apkDir.listFiles();
if (ArrayUtils.isEmpty(files)) {
throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
@@ -600,27 +600,23 @@ public class PackageParser {
"Missing base APK in " + apkDir);
}
// Always apply deterministic ordering based on splitName
final int size = apks.size();
final String[] splitNames = apks.keySet().toArray(new String[size]);
Arrays.sort(splitNames, sSplitNameComparator);
final File[] splitFiles = new File[size];
for (int i = 0; i < size; i++) {
splitFiles[i] = apks.get(splitNames[i]);
}
final Package pkg = parseBaseApk(baseFile, flags);
if (pkg == null) {
throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
"Failed to parse base APK: " + baseFile);
}
for (File splitFile : splitFiles) {
parseSplitApk(pkg, splitFile, flags);
// Always apply deterministic ordering based on splitName
final int size = apks.size();
final String[] splitNames = apks.keySet().toArray(new String[size]);
Arrays.sort(splitNames, sSplitNameComparator);
for (String splitName : splitNames) {
final File splitFile = apks.get(splitName);
parseSplitApk(pkg, splitFile, splitName, flags);
}
pkg.codePath = apkDir.getAbsolutePath();
return pkg;
}
@@ -632,11 +628,12 @@ public class PackageParser {
*/
public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
final Package pkg = parseBaseApk(apkFile, flags);
if (pkg != null) {
return pkg;
} else {
if (pkg == null) {
throw new PackageParserException(mParseError, "Failed to parse " + apkFile);
}
pkg.codePath = apkFile.getAbsolutePath();
return pkg;
}
private Package parseBaseApk(File apkFile, int flags) {
@@ -723,19 +720,22 @@ public class PackageParser {
parser.close();
assmgr.close();
pkg.codePath = apkPath;
pkg.baseCodePath = apkPath;
pkg.mSignatures = null;
return pkg;
}
private void parseSplitApk(Package pkg, File apkFile, int flags) throws PackageParserException {
final String apkPath = apkFile.getAbsolutePath();
private void parseSplitApk(Package pkg, File apkFile, String splitName, int flags)
throws PackageParserException {
final String splitCodePath = apkFile.getAbsolutePath();
mArchiveSourcePath = apkFile.getAbsolutePath();
// TODO: expand split APK parsing
// TODO: extract splitName during parse
pkg.splitNames = ArrayUtils.appendElement(String.class, pkg.splitNames, splitName);
pkg.splitCodePaths = ArrayUtils.appendElement(String.class, pkg.splitCodePaths,
apkFile.getAbsolutePath());
splitCodePath);
}
/**
@@ -748,7 +748,7 @@ public class PackageParser {
// TODO: extend to gather digest for split APKs
try {
final StrictJarFile jarFile = new StrictJarFile(pkg.codePath);
final StrictJarFile jarFile = new StrictJarFile(pkg.baseCodePath);
try {
final ZipEntry je = jarFile.findEntry(ANDROID_MANIFEST_FILENAME);
if (je != null) {
@@ -773,7 +773,7 @@ public class PackageParser {
pkg.mSignatures = null;
pkg.mSigningKeys = null;
collectCertificates(pkg, new File(pkg.codePath), flags);
collectCertificates(pkg, new File(pkg.baseCodePath), flags);
if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
for (String splitCodePath : pkg.splitCodePaths) {
@@ -3692,12 +3692,21 @@ public class PackageParser {
public final static class Package {
public String packageName;
/** Names of any split APKs, ordered by parsed splitName */
public String[] splitNames;
// TODO: work towards making these paths invariant
/** Base APK */
/**
* Path where this package was found on disk. For monolithic packages
* this is path to single base APK file; for cluster packages this is
* path to the cluster directory.
*/
public String codePath;
/** Split APKs, ordered by parsed splitName */
/** Path of base APK */
public String baseCodePath;
/** Paths of any split APKs, ordered by parsed splitName */
public String[] splitCodePaths;
// For now we only support one application per package.
@@ -3816,9 +3825,9 @@ public class PackageParser {
applicationInfo.uid = -1;
}
public Collection<String> getAllCodePaths() {
public List<String> getAllCodePaths() {
ArrayList<String> paths = new ArrayList<>();
paths.add(codePath);
paths.add(baseCodePath);
if (!ArrayUtils.isEmpty(splitCodePaths)) {
Collections.addAll(paths, splitCodePaths);
}

View File

@@ -384,16 +384,18 @@ public class FileUtils {
return filePath.startsWith(dirPath);
}
public static void deleteContents(File dir) {
public static boolean deleteContents(File dir) {
File[] files = dir.listFiles();
boolean success = true;
if (files != null) {
for (File file : files) {
if (file.isDirectory()) {
deleteContents(file);
success &= deleteContents(file);
}
file.delete();
success &= file.delete();
}
}
return success;
}
/**
@@ -411,4 +413,23 @@ public class FileUtils {
}
return true;
}
public static String rewriteAfterRename(File beforeDir, File afterDir, String path) {
final File result = rewriteAfterRename(beforeDir, afterDir, new File(path));
return (result != null) ? result.getAbsolutePath() : null;
}
/**
* Given a path under the "before" directory, rewrite it to live under the
* "after" directory. For example, {@code /before/foo/bar.txt} would become
* {@code /after/foo/bar.txt}.
*/
public static File rewriteAfterRename(File beforeDir, File afterDir, File file) {
if (contains(beforeDir, file)) {
final String splice = file.getAbsolutePath().substring(
beforeDir.getAbsolutePath().length());
return new File(afterDir, splice);
}
return null;
}
}

View File

@@ -171,4 +171,23 @@ public class SELinux {
return false;
}
}
/**
* Recursively restores all files under the given path to their default
* SELinux security context. If the system is not compiled with SELinux,
* then {@code true} is automatically returned. If SELinux is compiled in,
* but disabled, then {@code true} is returned.
*
* @return a boolean indicating whether the relabeling succeeded.
*/
public static boolean restoreconTree(File dir) {
final File[] files = dir.listFiles();
boolean success = true;
if (files != null) {
for (File file : files) {
success &= restorecon(file);
}
}
return success;
}
}

View File

@@ -16,27 +16,25 @@
package com.android.internal.app;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.content.pm.ContainerEncryptionParams;
import android.content.pm.PackageInfoLite;
import android.content.res.ObbInfo;
interface IMediaContainerService {
String copyResourceToContainer(in Uri packageURI, String containerId, String key,
String copyResourceToContainer(String packagePath, String containerId, String key,
String resFileName, String publicResFileName, boolean isExternal,
boolean isForwardLocked, in String abiOverride);
int copyResource(in Uri packageURI, in ContainerEncryptionParams encryptionParams,
boolean isForwardLocked, String abiOverride);
int copyResource(String packagePath, in ContainerEncryptionParams encryptionParams,
in ParcelFileDescriptor outStream);
PackageInfoLite getMinimalPackageInfo(in String packagePath, in int flags, in long threshold,
in String abiOverride);
boolean checkInternalFreeStorage(in Uri fileUri, boolean isForwardLocked, in long threshold);
boolean checkExternalFreeStorage(in Uri fileUri, boolean isForwardLocked, in String abiOverride);
ObbInfo getObbInfo(in String filename);
long calculateDirectorySize(in String directory);
PackageInfoLite getMinimalPackageInfo(String packagePath, int flags, long threshold,
String abiOverride);
boolean checkInternalFreeStorage(String packagePath, boolean isForwardLocked, long threshold);
boolean checkExternalFreeStorage(String packagePath, boolean isForwardLocked, String abiOverride);
ObbInfo getObbInfo(String filename);
long calculateDirectorySize(String directory);
/** Return file system stats: [0] is total bytes, [1] is available bytes */
long[] getFileSystemStats(in String path);
void clearDirectory(in String directory);
long calculateInstalledSize(in String packagePath, boolean isForwardLocked,
in String abiOverride);
long[] getFileSystemStats(String path);
void clearDirectory(String directory);
long calculateInstalledSize(String packagePath, boolean isForwardLocked, String abiOverride);
}

View File

@@ -138,6 +138,7 @@ public class ArrayUtils
* not found.
*/
public static <T> int indexOf(T[] array, T value) {
if (array == null) return -1;
for (int i = 0; i < array.length; i++) {
if (array[i] == null) {
if (value == null) return i;
@@ -161,6 +162,7 @@ public class ArrayUtils
}
public static boolean contains(int[] array, int value) {
if (array == null) return false;
for (int element : array) {
if (element == value) {
return true;
@@ -170,6 +172,7 @@ public class ArrayUtils
}
public static boolean contains(long[] array, long value) {
if (array == null) return false;
for (long element : array) {
if (element == value) {
return true;
@@ -325,4 +328,8 @@ public class ArrayUtils
}
return cur;
}
public static long[] cloneOrNull(long[] array) {
return (array != null) ? array.clone() : null;
}
}

View File

@@ -30,7 +30,6 @@ import android.content.pm.PackageParser;
import android.content.pm.PackageParser.PackageParserException;
import android.content.res.ObbInfo;
import android.content.res.ObbScanner;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.Environment.UserEnvironment;
@@ -45,7 +44,6 @@ import android.provider.Settings;
import android.system.ErrnoException;
import android.system.Os;
import android.system.StructStatVfs;
import android.util.DisplayMetrics;
import android.util.Slog;
import com.android.internal.app.IMediaContainerService;
@@ -53,6 +51,9 @@ import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.content.NativeLibraryHelper.ApkHandle;
import com.android.internal.content.PackageHelper;
import libcore.io.IoUtils;
import libcore.io.Streams;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
@@ -71,9 +72,6 @@ import javax.crypto.CipherInputStream;
import javax.crypto.Mac;
import javax.crypto.NoSuchPaddingException;
import libcore.io.IoUtils;
import libcore.io.Streams;
/*
* This service copies a downloaded apk to a file passed in as
* a ParcelFileDescriptor or to a newly created container specified
@@ -101,14 +99,14 @@ public class DefaultContainerService extends IntentService {
* @return Returns the new cache path where the resource has been copied into
*
*/
public String copyResourceToContainer(final Uri packageURI, final String cid,
@Override
public String copyResourceToContainer(final String packagePath, final String cid,
final String key, final String resFileName, final String publicResFileName,
boolean isExternal, boolean isForwardLocked, String abiOverride) {
if (packageURI == null || cid == null) {
if (packagePath == null || cid == null) {
return null;
}
if (isExternal) {
// Make sure the sdcard is mounted.
String status = Environment.getExternalStorageState();
@@ -120,11 +118,11 @@ public class DefaultContainerService extends IntentService {
ApkHandle handle = null;
try {
handle = ApkHandle.create(packageURI.getPath());
return copyResourceInner(packageURI, cid, key, resFileName, publicResFileName,
handle = ApkHandle.create(packagePath);
return copyResourceInner(packagePath, cid, key, resFileName, publicResFileName,
isExternal, isForwardLocked, handle, abiOverride);
} catch (IOException ioe) {
Slog.w(TAG, "Problem opening APK: " + packageURI.getPath());
Slog.w(TAG, "Problem opening APK: " + packagePath);
return null;
} finally {
IoUtils.closeQuietly(handle);
@@ -142,9 +140,10 @@ public class DefaultContainerService extends IntentService {
* @return returns status code according to those in
* {@link PackageManager}
*/
public int copyResource(final Uri packageURI, ContainerEncryptionParams encryptionParams,
ParcelFileDescriptor outStream) {
if (packageURI == null || outStream == null) {
@Override
public int copyResource(final String packagePath,
ContainerEncryptionParams encryptionParams, ParcelFileDescriptor outStream) {
if (packagePath == null || outStream == null) {
return PackageManager.INSTALL_FAILED_INVALID_URI;
}
@@ -152,18 +151,18 @@ public class DefaultContainerService extends IntentService {
= new ParcelFileDescriptor.AutoCloseOutputStream(outStream);
try {
copyFile(packageURI, autoOut, encryptionParams);
copyFile(packagePath, autoOut, encryptionParams);
return PackageManager.INSTALL_SUCCEEDED;
} catch (FileNotFoundException e) {
Slog.e(TAG, "Could not copy URI " + packageURI.toString() + " FNF: "
Slog.e(TAG, "Could not copy URI " + packagePath.toString() + " FNF: "
+ e.getMessage());
return PackageManager.INSTALL_FAILED_INVALID_URI;
} catch (IOException e) {
Slog.e(TAG, "Could not copy URI " + packageURI.toString() + " IO: "
Slog.e(TAG, "Could not copy URI " + packagePath.toString() + " IO: "
+ e.getMessage());
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
} catch (DigestException e) {
Slog.e(TAG, "Could not copy URI " + packageURI.toString() + " Security: "
Slog.e(TAG, "Could not copy URI " + packagePath.toString() + " Security: "
+ e.getMessage());
return PackageManager.INSTALL_FAILED_INVALID_APK;
} finally {
@@ -217,9 +216,9 @@ public class DefaultContainerService extends IntentService {
}
@Override
public boolean checkInternalFreeStorage(Uri packageUri, boolean isForwardLocked,
public boolean checkInternalFreeStorage(String packagePath, boolean isForwardLocked,
long threshold) throws RemoteException {
final File apkFile = new File(packageUri.getPath());
final File apkFile = new File(packagePath);
try {
return isUnderInternalThreshold(apkFile, isForwardLocked, threshold);
} catch (IOException e) {
@@ -228,9 +227,9 @@ public class DefaultContainerService extends IntentService {
}
@Override
public boolean checkExternalFreeStorage(Uri packageUri, boolean isForwardLocked,
public boolean checkExternalFreeStorage(String packagePath, boolean isForwardLocked,
String abiOverride) throws RemoteException {
final File apkFile = new File(packageUri.getPath());
final File apkFile = new File(packagePath);
try {
return isUnderExternalThreshold(apkFile, isForwardLocked, abiOverride);
} catch (IOException e) {
@@ -238,6 +237,7 @@ public class DefaultContainerService extends IntentService {
}
}
@Override
public ObbInfo getObbInfo(String filename) {
try {
return ObbScanner.getObbInfo(filename);
@@ -347,11 +347,11 @@ public class DefaultContainerService extends IntentService {
return mBinder;
}
private String copyResourceInner(Uri packageURI, String newCid, String key, String resFileName,
private String copyResourceInner(String packagePath, String newCid, String key, String resFileName,
String publicResFileName, boolean isExternal, boolean isForwardLocked,
ApkHandle handle, String abiOverride) {
// The .apk file
String codePath = packageURI.getPath();
String codePath = packagePath;
File codeFile = new File(codePath);
String[] abiList = Build.SUPPORTED_ABIS;
@@ -492,39 +492,13 @@ public class DefaultContainerService extends IntentService {
}
}
private void copyFile(Uri pPackageURI, OutputStream outStream,
private void copyFile(String packagePath, OutputStream outStream,
ContainerEncryptionParams encryptionParams) throws FileNotFoundException, IOException,
DigestException {
String scheme = pPackageURI.getScheme();
InputStream inStream = null;
try {
if (scheme == null || scheme.equals("file")) {
final InputStream is = new FileInputStream(new File(pPackageURI.getPath()));
inStream = new BufferedInputStream(is);
} else if (scheme.equals("content")) {
final ParcelFileDescriptor fd;
try {
fd = getContentResolver().openFileDescriptor(pPackageURI, "r");
} catch (FileNotFoundException e) {
Slog.e(TAG, "Couldn't open file descriptor from download service. "
+ "Failed with exception " + e);
throw e;
}
if (fd == null) {
Slog.e(TAG, "Provider returned no file descriptor for " +
pPackageURI.toString());
throw new FileNotFoundException("provider returned no file descriptor");
} else {
if (localLOGV) {
Slog.i(TAG, "Opened file descriptor from download service.");
}
inStream = new ParcelFileDescriptor.AutoCloseInputStream(fd);
}
} else {
Slog.e(TAG, "Package URI is not 'file:' or 'content:' - " + pPackageURI);
throw new FileNotFoundException("Package URI is not 'file:' or 'content:'");
}
final InputStream is = new FileInputStream(new File(packagePath));
inStream = new BufferedInputStream(is);
/*
* If this resource is encrypted, get the decrypted stream version

View File

@@ -41,6 +41,7 @@ import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.SELinux;
import android.os.UserHandle;
import android.system.ErrnoException;
import android.system.OsConstants;
import android.system.StructStat;
@@ -272,7 +273,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
};
mPm.installStage(mPackageName, this.sessionDir, localObserver, params.installFlags);
mPm.installStage(mPackageName, this.sessionDir, localObserver, params, installerPackageName,
installerUid, new UserHandle(userId));
}
/**

View File

@@ -18,7 +18,6 @@ package com.android.server.pm;
import com.android.internal.util.ArrayUtils;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@@ -35,19 +34,17 @@ public class PackageKeySetData {
private long[] mDefinedKeySets;
private final Map<String, Long> mKeySetAliases;
private final Map<String, Long> mKeySetAliases = new HashMap<String, Long>();
PackageKeySetData() {
mProperSigningKeySet = KEYSET_UNASSIGNED;
mKeySetAliases = new HashMap<String, Long>();
}
PackageKeySetData(PackageKeySetData original) {
mSigningKeySets = original.getSigningKeySets().clone();
mUpgradeKeySets = original.getUpgradeKeySets().clone();
mDefinedKeySets = original.getDefinedKeySets().clone();
mKeySetAliases = new HashMap<String, Long>();
mKeySetAliases.putAll(original.getAliases());
mSigningKeySets = ArrayUtils.cloneOrNull(original.mSigningKeySets);
mUpgradeKeySets = ArrayUtils.cloneOrNull(original.mUpgradeKeySets);
mDefinedKeySets = ArrayUtils.cloneOrNull(original.mDefinedKeySets);
mKeySetAliases.putAll(original.mKeySetAliases);
}
protected void setProperSigningKeySet(long ks) {
@@ -149,4 +146,4 @@ public class PackageKeySetData {
/* should never be the case that mUpgradeKeySets.length == 0 */
return (mUpgradeKeySets != null && mUpgradeKeySets.length > 0);
}
}
}

View File

@@ -24,6 +24,7 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
import static android.content.pm.PackageParser.isPackageFilename;
import static android.os.Process.PACKAGE_INFO_GID;
import static android.os.Process.SYSTEM_UID;
import static android.system.OsConstants.S_IRGRP;
@@ -46,6 +47,7 @@ import com.android.internal.content.PackageHelper;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.server.EventLogTags;
import com.android.server.IntentResolver;
@@ -92,6 +94,7 @@ import android.content.pm.ManifestDigest;
import android.content.pm.PackageCleanItem;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageInstallerParams;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser.ActivityIntentInfo;
import android.content.pm.PackageParser.PackageParserException;
@@ -349,6 +352,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// LOCK HELD. Can be called with mInstallLock held.
final Installer mInstaller;
/** Directory where installed third-party apps stored */
final File mAppInstallDir;
/**
@@ -361,6 +365,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// apps.
final File mDrmAppPrivateInstallDir;
/** Directory where third-party apps are staged before install */
final File mAppStagingDir;
// ----------------------------------------------------------------
@@ -1143,17 +1148,18 @@ public class PackageManagerService extends IPackageManager.Stub {
if ((state != null) && !state.timeoutExtended()) {
final InstallArgs args = state.getInstallArgs();
Slog.i(TAG, "Verification timed out for " + args.packageURI.toString());
final Uri fromUri = Uri.fromFile(args.fromFile);
Slog.i(TAG, "Verification timed out for " + fromUri);
mPendingVerification.remove(verificationId);
int ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
if (getDefaultVerificationResponse() == PackageManager.VERIFICATION_ALLOW) {
Slog.i(TAG, "Continuing with installation of "
+ args.packageURI.toString());
Slog.i(TAG, "Continuing with installation of " + fromUri);
state.setVerifierResponse(Binder.getCallingUid(),
PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
broadcastPackageVerified(verificationId, args.packageURI,
broadcastPackageVerified(verificationId, fromUri,
PackageManager.VERIFICATION_ALLOW,
state.getInstallArgs().getUser());
try {
@@ -1162,7 +1168,7 @@ public class PackageManagerService extends IPackageManager.Stub {
Slog.e(TAG, "Could not contact the ContainerService");
}
} else {
broadcastPackageVerified(verificationId, args.packageURI,
broadcastPackageVerified(verificationId, fromUri,
PackageManager.VERIFICATION_REJECT,
state.getInstallArgs().getUser());
}
@@ -1189,11 +1195,12 @@ public class PackageManagerService extends IPackageManager.Stub {
mPendingVerification.remove(verificationId);
final InstallArgs args = state.getInstallArgs();
final Uri fromUri = Uri.fromFile(args.fromFile);
int ret;
if (state.isInstallAllowed()) {
ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
broadcastPackageVerified(verificationId, args.packageURI,
broadcastPackageVerified(verificationId, fromUri,
response.code, state.getInstallArgs().getUser());
try {
ret = args.copyApk(mContainerService, true);
@@ -1528,14 +1535,14 @@ public class PackageManagerService extends IPackageManager.Stub {
// overlay packages if they reside in VENDOR_OVERLAY_DIR.
File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
mVendorOverlayInstallObserver = new AppDirObserver(
vendorOverlayDir.getPath(), OBSERVER_EVENTS, true, false);
vendorOverlayDir.getPath(), OBSERVER_EVENTS, true, false);
mVendorOverlayInstallObserver.startWatching();
scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanMode | SCAN_TRUSTED_OVERLAY, 0);
// Find base frameworks (resource packages without code).
mFrameworkInstallObserver = new AppDirObserver(
frameworkDir.getPath(), OBSERVER_EVENTS, true, false);
frameworkDir.getPath(), OBSERVER_EVENTS, true, false);
mFrameworkInstallObserver.startWatching();
scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
@@ -1547,14 +1554,14 @@ public class PackageManagerService extends IPackageManager.Stub {
mPrivilegedInstallObserver = new AppDirObserver(
privilegedAppDir.getPath(), OBSERVER_EVENTS, true, true);
mPrivilegedInstallObserver.startWatching();
scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED, scanMode, 0);
scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED, scanMode, 0);
// Collect ordinary system packages.
File systemAppDir = new File(Environment.getRootDirectory(), "app");
mSystemInstallObserver = new AppDirObserver(
systemAppDir.getPath(), OBSERVER_EVENTS, true, false);
systemAppDir.getPath(), OBSERVER_EVENTS, true, false);
mSystemInstallObserver.startWatching();
scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);
@@ -1567,7 +1574,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// failed to look up canonical path, continue with original one
}
mVendorInstallObserver = new AppDirObserver(
vendorAppDir.getPath(), OBSERVER_EVENTS, true, false);
vendorAppDir.getPath(), OBSERVER_EVENTS, true, false);
mVendorInstallObserver.startWatching();
scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);
@@ -1825,6 +1832,10 @@ public class PackageManagerService extends IPackageManager.Stub {
void cleanupInstallFailedPackage(PackageSetting ps) {
Slog.i(TAG, "Cleaning up incompletely installed app: " + ps.name);
removeDataDirsLI(ps.name);
// TODO: try cleaning up codePath directory contents first, since it
// might be a cluster
if (ps.codePath != null) {
if (!ps.codePath.delete()) {
Slog.w(TAG, "Unable to remove old code file: " + ps.codePath);
@@ -2071,15 +2082,12 @@ public class PackageManagerService extends IPackageManager.Stub {
if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) == 0) {
return null;
}
// App code is gone, so we aren't worried about split paths
// Only data remains, so we aren't worried about code paths
pkg = new PackageParser.Package(packageName);
pkg.applicationInfo.packageName = packageName;
pkg.applicationInfo.flags = ps.pkgFlags | ApplicationInfo.FLAG_IS_DATA_ONLY;
pkg.applicationInfo.sourceDir = ps.codePathString;
pkg.applicationInfo.publicSourceDir = ps.resourcePathString;
pkg.applicationInfo.dataDir =
getDataPathForPackage(packageName, 0).getPath();
pkg.applicationInfo.nativeLibraryDir = ps.nativeLibraryPathString;
pkg.applicationInfo.cpuAbi = ps.cpuAbiString;
}
return generatePackageInfo(pkg, flags, userId);
@@ -4041,20 +4049,21 @@ public class PackageManagerService extends IPackageManager.Stub {
private boolean createIdmapForPackagePairLI(PackageParser.Package pkg,
PackageParser.Package opkg) {
if (!opkg.mTrustedOverlay) {
Slog.w(TAG, "Skipping target and overlay pair " + pkg.codePath + " and " +
opkg.codePath + ": overlay not trusted");
Slog.w(TAG, "Skipping target and overlay pair " + pkg.baseCodePath + " and " +
opkg.baseCodePath + ": overlay not trusted");
return false;
}
HashMap<String, PackageParser.Package> overlaySet = mOverlays.get(pkg.packageName);
if (overlaySet == null) {
Slog.e(TAG, "was about to create idmap for " + pkg.codePath + " and " +
opkg.codePath + " but target package has no known overlays");
Slog.e(TAG, "was about to create idmap for " + pkg.baseCodePath + " and " +
opkg.baseCodePath + " but target package has no known overlays");
return false;
}
final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
// TODO: generate idmap for split APKs
if (mInstaller.idmap(pkg.codePath, opkg.codePath, sharedGid) != 0) {
Slog.e(TAG, "Failed to generate idmap for " + pkg.codePath + " and " + opkg.codePath);
if (mInstaller.idmap(pkg.baseCodePath, opkg.baseCodePath, sharedGid) != 0) {
Slog.e(TAG, "Failed to generate idmap for " + pkg.baseCodePath + " and "
+ opkg.baseCodePath);
return false;
}
PackageParser.Package[] overlayArray =
@@ -4075,8 +4084,8 @@ public class PackageManagerService extends IPackageManager.Stub {
}
private void scanDirLI(File dir, int flags, int scanMode, long currentTime) {
String[] files = dir.list();
if (files == null) {
final File[] files = dir.listFiles();
if (ArrayUtils.isEmpty(files)) {
Log.d(TAG, "No files in app dir " + dir);
return;
}
@@ -4086,10 +4095,8 @@ public class PackageManagerService extends IPackageManager.Stub {
+ " flags=0x" + Integer.toHexString(flags));
}
int i;
for (i=0; i<files.length; i++) {
File file = new File(dir, files[i]);
if (!isPackageFilename(files[i])) {
for (File file : files) {
if (!isPackageFilename(file)) {
// Ignore entries which are not apk's
continue;
}
@@ -4258,7 +4265,7 @@ public class PackageManagerService extends IPackageManager.Stub {
+ ": new version " + pkg.mVersionCode
+ " better than installed " + ps.versionCode);
InstallArgs args = createInstallArgs(packageFlagsToInstallFlags(ps),
InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
ps.codePathString, ps.resourcePathString, ps.nativeLibraryPathString,
getAppInstructionSetFromSettings(ps));
synchronized (mInstallLock) {
@@ -4323,7 +4330,7 @@ public class PackageManagerService extends IPackageManager.Stub {
Slog.w(TAG, "Package " + ps.name + " at " + scanFile + "reverting from "
+ ps.codePathString + ": new version " + pkg.mVersionCode
+ " better than installed " + ps.versionCode);
InstallArgs args = createInstallArgs(packageFlagsToInstallFlags(ps),
InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
ps.codePathString, ps.resourcePathString, ps.nativeLibraryPathString,
getAppInstructionSetFromSettings(ps));
synchronized (mInstallLock) {
@@ -4343,29 +4350,27 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
final String codePath = pkg.codePath;
final String baseCodePath = pkg.baseCodePath;
final String[] splitCodePaths = pkg.splitCodePaths;
String resPath = null;
String[] splitResPaths = null;
// TODO: extend to support forward-locked splits
String baseResPath = null;
if ((parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0 && !updatedPkgBetter) {
if (ps != null && ps.resourcePathString != null) {
resPath = ps.resourcePathString;
splitResPaths = deriveSplitResPaths(pkg.splitCodePaths);
baseResPath = ps.resourcePathString;
} else {
// Should not happen at all. Just log an error.
Slog.e(TAG, "Resource path not set for pkg : " + pkg.packageName);
}
} else {
resPath = pkg.codePath;
splitResPaths = pkg.splitCodePaths;
baseResPath = pkg.baseCodePath;
}
// Set application objects path explicitly.
pkg.applicationInfo.sourceDir = codePath;
pkg.applicationInfo.publicSourceDir = resPath;
pkg.applicationInfo.sourceDir = baseCodePath;
pkg.applicationInfo.publicSourceDir = baseResPath;
pkg.applicationInfo.splitSourceDirs = splitCodePaths;
pkg.applicationInfo.splitPublicSourceDirs = splitResPaths;
pkg.applicationInfo.splitPublicSourceDirs = splitCodePaths;
// Note that we invoke the following method only if we are about to unpack an application
PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode
@@ -6419,10 +6424,6 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
private static final boolean isPackageFilename(String name) {
return name != null && name.endsWith(".apk");
}
private static boolean hasPermission(PackageParser.Package pkgInfo, String perm) {
for (int i=pkgInfo.permissions.size()-1; i>=0; i--) {
if (pkgInfo.permissions.get(i).info.name.equals(perm)) {
@@ -7701,8 +7702,13 @@ public class PackageManagerService extends IPackageManager.Stub {
verificationParams.setInstallerUid(uid);
if (!"file".equals(packageURI.getScheme())) {
throw new UnsupportedOperationException("Only file:// URIs are supported");
}
final File fromFile = new File(packageURI.getPath());
final Message msg = mHandler.obtainMessage(INIT_COPY);
msg.obj = new InstallParams(packageURI, observer, observer2, filteredFlags,
msg.obj = new InstallParams(fromFile, observer, observer2, filteredFlags,
installerPackageName, verificationParams, encryptionParams, user,
packageAbiOverride);
mHandler.sendMessage(msg);
@@ -7820,11 +7826,12 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
void installStage(String basePackageName, File stageDir, IPackageInstallObserver2 observer,
int flags) {
// TODO: install stage!
void installStage(String packageName, File stageDir, IPackageInstallObserver2 observer2,
PackageInstallerParams params, String installerPackageName, int installerUid,
UserHandle user) {
Slog.e(TAG, "TODO: install stage!");
try {
observer.packageInstalled(basePackageName, null,
observer2.packageInstalled(packageName, null,
PackageManager.INSTALL_FAILED_INTERNAL_ERROR);
} catch (RemoteException ignored) {
}
@@ -8407,30 +8414,38 @@ public class PackageManagerService extends IPackageManager.Stub {
}
class InstallParams extends HandlerParams {
/**
* Location where install is coming from, before it has been
* copied/renamed into place. This could be a single monolithic APK
* file, or a cluster directory. This location may be untrusted.
*/
private final File mFromFile;
/**
* Local copy of {@link #mFromFile}, if generated.
*/
private File mLocalFromFile;
final IPackageInstallObserver observer;
final IPackageInstallObserver2 observer2;
int flags;
private final Uri mPackageURI;
final String installerPackageName;
final VerificationParams verificationParams;
private InstallArgs mArgs;
private int mRet;
private File mTempPackage;
final ContainerEncryptionParams encryptionParams;
final String packageAbiOverride;
final String packageInstructionSetOverride;
InstallParams(Uri packageURI,
IPackageInstallObserver observer, IPackageInstallObserver2 observer2,
int flags, String installerPackageName, VerificationParams verificationParams,
ContainerEncryptionParams encryptionParams, UserHandle user,
String packageAbiOverride) {
InstallParams(File fromFile, IPackageInstallObserver observer,
IPackageInstallObserver2 observer2, int flags, String installerPackageName,
VerificationParams verificationParams, ContainerEncryptionParams encryptionParams,
UserHandle user, String packageAbiOverride) {
super(user);
this.mPackageURI = packageURI;
this.flags = flags;
mFromFile = Preconditions.checkNotNull(fromFile);
this.observer = observer;
this.observer2 = observer2;
this.flags = flags;
this.installerPackageName = installerPackageName;
this.verificationParams = verificationParams;
this.encryptionParams = encryptionParams;
@@ -8443,7 +8458,7 @@ public class PackageManagerService extends IPackageManager.Stub {
public String toString() {
return "InstallParams{"
+ Integer.toHexString(System.identityHashCode(this))
+ " " + mPackageURI + "}";
+ " " + mFromFile + "}";
}
public ManifestDigest getManifestDigest() {
@@ -8543,76 +8558,55 @@ public class PackageManagerService extends IPackageManager.Stub {
Log.w(TAG, "Couldn't get low memory threshold; no free limit imposed");
}
try {
mContext.grantUriPermission(DEFAULT_CONTAINER_PACKAGE, mPackageURI,
Intent.FLAG_GRANT_READ_URI_PERMISSION);
final File packageFile;
if (encryptionParams != null || !"file".equals(mPackageURI.getScheme())) {
mTempPackage = createTempPackageFile(mDrmAppPrivateInstallDir);
if (mTempPackage != null) {
ParcelFileDescriptor out;
try {
out = ParcelFileDescriptor.open(mTempPackage,
ParcelFileDescriptor.MODE_READ_WRITE);
} catch (FileNotFoundException e) {
out = null;
Slog.e(TAG, "Failed to create temporary file for : " + mPackageURI);
}
// Make a temporary file for decryption.
ret = mContainerService
.copyResource(mPackageURI, encryptionParams, out);
if (encryptionParams != null) {
// Make a temporary file for decryption.
mLocalFromFile = createTempPackageFile(mDrmAppPrivateInstallDir);
if (mLocalFromFile != null) {
ParcelFileDescriptor out = null;
try {
out = ParcelFileDescriptor.open(mLocalFromFile,
ParcelFileDescriptor.MODE_READ_WRITE);
ret = mContainerService.copyResource(mFromFile.getAbsolutePath(),
encryptionParams, out);
} catch (FileNotFoundException e) {
Slog.e(TAG, "Failed to create temporary file for: " + mFromFile);
} finally {
IoUtils.closeQuietly(out);
packageFile = mTempPackage;
FileUtils.setPermissions(packageFile.getAbsolutePath(),
FileUtils.S_IRUSR | FileUtils.S_IWUSR | FileUtils.S_IRGRP
| FileUtils.S_IROTH,
-1, -1);
} else {
packageFile = null;
}
} else {
packageFile = new File(mPackageURI.getPath());
}
if (packageFile != null) {
// Remote call to find out default install location
final String packageFilePath = packageFile.getAbsolutePath();
pkgLite = mContainerService.getMinimalPackageInfo(packageFilePath, flags,
lowThreshold, packageAbiOverride);
/*
* If we have too little free space, try to free cache
* before giving up.
*/
if (pkgLite.recommendedInstallLocation
== PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
final long size = mContainerService.calculateInstalledSize(
packageFilePath, isForwardLocked(), packageAbiOverride);
if (mInstaller.freeCache(size + lowThreshold) >= 0) {
pkgLite = mContainerService.getMinimalPackageInfo(packageFilePath,
flags, lowThreshold, packageAbiOverride);
}
/*
* The cache free must have deleted the file we
* downloaded to install.
*
* TODO: fix the "freeCache" call to not delete
* the file we care about.
*/
if (pkgLite.recommendedInstallLocation
== PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
pkgLite.recommendedInstallLocation
= PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
}
}
FileUtils.setPermissions(mLocalFromFile, 0644, -1, -1);
}
}
// Remote call to find out default install location
final String fromPath = getFromFile().getAbsolutePath();
pkgLite = mContainerService.getMinimalPackageInfo(fromPath, flags, lowThreshold,
packageAbiOverride);
/*
* If we have too little free space, try to free cache
* before giving up.
*/
if (pkgLite.recommendedInstallLocation
== PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
final long size = mContainerService.calculateInstalledSize(
fromPath, isForwardLocked(), packageAbiOverride);
if (mInstaller.freeCache(size + lowThreshold) >= 0) {
pkgLite = mContainerService.getMinimalPackageInfo(fromPath,
flags, lowThreshold, packageAbiOverride);
}
/*
* The cache free must have deleted the file we
* downloaded to install.
*
* TODO: fix the "freeCache" call to not delete
* the file we care about.
*/
if (pkgLite.recommendedInstallLocation
== PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
pkgLite.recommendedInstallLocation
= PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
}
} finally {
mContext.revokeUriPermission(mPackageURI,
Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
}
@@ -8672,9 +8666,10 @@ public class PackageManagerService extends IPackageManager.Stub {
final int requiredUid = mRequiredVerifierPackage == null ? -1
: getPackageUid(mRequiredVerifierPackage, userIdentifier);
if (requiredUid != -1 && isVerificationEnabled(userIdentifier, flags)) {
// TODO: send verifier the install session instead of uri
final Intent verification = new Intent(
Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
verification.setDataAndType(getPackageUri(), PACKAGE_MIME_TYPE);
verification.setDataAndType(Uri.fromFile(getFromFile()), PACKAGE_MIME_TYPE);
verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
final List<ResolveInfo> receivers = queryIntentReceivers(verification,
@@ -8802,10 +8797,9 @@ public class PackageManagerService extends IPackageManager.Stub {
if (mArgs != null) {
processPendingInstall(mArgs, mRet);
if (mTempPackage != null) {
if (!mTempPackage.delete()) {
Slog.w(TAG, "Couldn't delete temporary file: " +
mTempPackage.getAbsolutePath());
if (mLocalFromFile != null) {
if (!mLocalFromFile.delete()) {
Slog.w(TAG, "Couldn't delete temporary file: " + mLocalFromFile);
}
}
}
@@ -8821,11 +8815,11 @@ public class PackageManagerService extends IPackageManager.Stub {
return (flags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
}
public Uri getPackageUri() {
if (mTempPackage != null) {
return Uri.fromFile(mTempPackage);
public File getFromFile() {
if (mLocalFromFile != null) {
return mLocalFromFile;
} else {
return mPackageURI;
return mFromFile;
}
}
}
@@ -8856,8 +8850,9 @@ public class PackageManagerService extends IPackageManager.Stub {
this.packageName = packageName;
this.uid = uid;
if (srcArgs != null) {
Uri packageUri = Uri.fromFile(new File(srcArgs.getCodePath()));
targetArgs = createInstallArgs(packageUri, flags, packageName, dataDir, instructionSet);
final String codePath = srcArgs.getCodePath();
targetArgs = createInstallArgsForMoveTarget(codePath, flags, packageName, dataDir,
instructionSet);
} else {
targetArgs = null;
}
@@ -8958,6 +8953,8 @@ public class PackageManagerService extends IPackageManager.Stub {
}
private InstallArgs createInstallArgs(InstallParams params) {
// TODO: extend to support incoming zero-copy locations
if (installOnSd(params.flags) || params.isForwardLocked()) {
return new AsecInstallArgs(params);
} else {
@@ -8965,14 +8962,18 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
private InstallArgs createInstallArgs(int flags, String fullCodePath, String fullResourcePath,
String nativeLibraryPath, String instructionSet) {
/**
* Create args that describe an existing installed package. Typically used
* when cleaning up old installs, or used as a move source.
*/
private InstallArgs createInstallArgsForExisting(int flags, String codePath,
String resourcePath, String nativeLibraryPath, String instructionSet) {
final boolean isInAsec;
if (installOnSd(flags)) {
/* Apps on SD card are always in ASEC containers. */
isInAsec = true;
} else if (installForwardLocked(flags)
&& !fullCodePath.startsWith(mDrmAppPrivateInstallDir.getAbsolutePath())) {
&& !codePath.startsWith(mDrmAppPrivateInstallDir.getAbsolutePath())) {
/*
* Forward-locked apps are only in ASEC containers if they're the
* new style
@@ -8983,44 +8984,49 @@ public class PackageManagerService extends IPackageManager.Stub {
}
if (isInAsec) {
return new AsecInstallArgs(fullCodePath, fullResourcePath, nativeLibraryPath,
return new AsecInstallArgs(codePath, resourcePath, nativeLibraryPath,
instructionSet, installOnSd(flags), installForwardLocked(flags));
} else {
return new FileInstallArgs(fullCodePath, fullResourcePath, nativeLibraryPath,
instructionSet);
return new FileInstallArgs(codePath, resourcePath, nativeLibraryPath, instructionSet);
}
}
// Used by package mover
private InstallArgs createInstallArgs(Uri packageURI, int flags, String pkgName, String dataDir,
String instructionSet) {
private InstallArgs createInstallArgsForMoveTarget(String codePath, int flags, String pkgName,
String dataDir, String instructionSet) {
final File codeFile = new File(codePath);
if (installOnSd(flags) || installForwardLocked(flags)) {
String cid = getNextCodePath(packageURI.getPath(), pkgName, "/"
String cid = getNextCodePath(codePath, pkgName, "/"
+ AsecInstallArgs.RES_FILE_NAME);
return new AsecInstallArgs(packageURI, cid, instructionSet, installOnSd(flags),
return new AsecInstallArgs(codeFile, cid, instructionSet, installOnSd(flags),
installForwardLocked(flags));
} else {
return new FileInstallArgs(packageURI, pkgName, dataDir, instructionSet);
return new FileInstallArgs(codeFile, pkgName, dataDir, instructionSet);
}
}
static abstract class InstallArgs {
/**
* Location where install is coming from, before it has been
* copied/renamed into place. This could be a single monolithic APK
* file, or a cluster directory. This location is typically untrusted.
*/
final File fromFile;
final IPackageInstallObserver observer;
final IPackageInstallObserver2 observer2;
// Always refers to PackageManager flags only
final int flags;
final Uri packageURI;
final String installerPackageName;
final ManifestDigest manifestDigest;
final UserHandle user;
final String instructionSet;
final String abiOverride;
InstallArgs(Uri packageURI,
IPackageInstallObserver observer, IPackageInstallObserver2 observer2,
int flags, String installerPackageName, ManifestDigest manifestDigest,
UserHandle user, String instructionSet, String abiOverride) {
this.packageURI = packageURI;
InstallArgs(File fromFile, IPackageInstallObserver observer,
IPackageInstallObserver2 observer2, int flags, String installerPackageName,
ManifestDigest manifestDigest, UserHandle user, String instructionSet,
String abiOverride) {
this.fromFile = fromFile;
this.flags = flags;
this.observer = observer;
this.observer2 = observer2;
@@ -9031,24 +9037,23 @@ public class PackageManagerService extends IPackageManager.Stub {
this.abiOverride = abiOverride;
}
abstract void createCopyFile();
abstract int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException;
abstract int doPreInstall(int status);
abstract boolean doRename(int status, String pkgName, String oldCodePath);
abstract int doPostInstall(int status, int uid);
/** @see PackageSettingBase#codePathString */
abstract String getCodePath();
/** @see PackageSettingBase#resourcePathString */
abstract String getResourcePath();
/** @see PackageSettingBase#nativeLibraryPathString */
abstract String getNativeLibraryPath();
// Need installer lock especially for dex file removal.
abstract void cleanUpResourcesLI();
abstract boolean doPostDeleteLI(boolean delete);
abstract boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException;
String[] getSplitCodePaths() {
return null;
}
/**
* Called before the source arguments are copied. This is used mostly
* for MoveParams when it needs to read the source file to put it in the
@@ -9078,20 +9083,27 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
/**
* Logic to handle installation of non-ASEC applications, including copying
* and renaming logic.
*/
class FileInstallArgs extends InstallArgs {
// TODO: teach about handling cluster directories
File installDir;
String codeFileName;
String resourceFileName;
String libraryPath;
boolean created = false;
/** New install */
FileInstallArgs(InstallParams params) {
super(params.getPackageUri(), params.observer, params.observer2, params.flags,
params.installerPackageName, params.getManifestDigest(),
params.getUser(), params.packageInstructionSetOverride,
params.packageAbiOverride);
super(params.getFromFile(), params.observer, params.observer2, params.flags,
params.installerPackageName, params.getManifestDigest(), params.getUser(),
params.packageInstructionSetOverride, params.packageAbiOverride);
}
/** Existing install */
FileInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath,
String instructionSet) {
super(null, null, null, 0, null, null, null, instructionSet, null);
@@ -9102,8 +9114,9 @@ public class PackageManagerService extends IPackageManager.Stub {
libraryPath = nativeLibraryPath;
}
FileInstallArgs(Uri packageURI, String pkgName, String dataDir, String instructionSet) {
super(packageURI, null, null, 0, null, null, null, instructionSet, null);
/** New install from existing */
FileInstallArgs(File fromFile, String pkgName, String dataDir, String instructionSet) {
super(fromFile, null, null, 0, null, null, null, instructionSet, null);
installDir = isFwdLocked() ? mDrmAppPrivateInstallDir : mAppInstallDir;
String apkName = getNextCodePath(null, pkgName, ".apk");
codeFileName = new File(installDir, apkName + ".apk").getPath();
@@ -9128,13 +9141,8 @@ public class PackageManagerService extends IPackageManager.Stub {
lowThreshold = dsm.getMemoryLowThreshold();
}
try {
mContext.grantUriPermission(DEFAULT_CONTAINER_PACKAGE, packageURI,
Intent.FLAG_GRANT_READ_URI_PERMISSION);
return imcs.checkInternalFreeStorage(packageURI, isFwdLocked(), lowThreshold);
} finally {
mContext.revokeUriPermission(packageURI, Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
return imcs.checkInternalFreeStorage(fromFile.getAbsolutePath(), isFwdLocked(),
lowThreshold);
}
void createCopyFile() {
@@ -9175,12 +9183,9 @@ public class PackageManagerService extends IPackageManager.Stub {
// Copy the resource now
int ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
try {
mContext.grantUriPermission(DEFAULT_CONTAINER_PACKAGE, packageURI,
Intent.FLAG_GRANT_READ_URI_PERMISSION);
ret = imcs.copyResource(packageURI, null, out);
ret = imcs.copyResource(fromFile.getAbsolutePath(), null, out);
} finally {
IoUtils.closeQuietly(out);
mContext.revokeUriPermission(packageURI, Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
if (isFwdLocked()) {
@@ -9432,7 +9437,13 @@ public class PackageManagerService extends IPackageManager.Stub {
return subStr1.substring(sidx+1, eidx);
}
/**
* Logic to handle installation of ASEC applications, including copying and
* renaming logic.
*/
class AsecInstallArgs extends InstallArgs {
// TODO: teach about handling cluster directories
static final String RES_FILE_NAME = "pkg.apk";
static final String PUBLIC_RES_FILE_NAME = "res.zip";
@@ -9441,13 +9452,14 @@ public class PackageManagerService extends IPackageManager.Stub {
String resourcePath;
String libraryPath;
/** New install */
AsecInstallArgs(InstallParams params) {
super(params.getPackageUri(), params.observer, params.observer2, params.flags,
params.installerPackageName, params.getManifestDigest(),
params.getUser(), params.packageInstructionSetOverride,
params.packageAbiOverride);
super(params.getFromFile(), params.observer, params.observer2, params.flags,
params.installerPackageName, params.getManifestDigest(), params.getUser(),
params.packageInstructionSetOverride, params.packageAbiOverride);
}
/** Existing install */
AsecInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath,
String instructionSet, boolean isExternal, boolean isForwardLocked) {
super(null, null, null, (isExternal ? PackageManager.INSTALL_EXTERNAL : 0)
@@ -9469,9 +9481,10 @@ public class PackageManagerService extends IPackageManager.Stub {
setCachePath(PackageHelper.getSdDir(cid));
}
AsecInstallArgs(Uri packageURI, String cid, String instructionSet,
/** New install from existing */
AsecInstallArgs(File fromFile, String cid, String instructionSet,
boolean isExternal, boolean isForwardLocked) {
super(packageURI, null, null, (isExternal ? PackageManager.INSTALL_EXTERNAL : 0)
super(fromFile, null, null, (isExternal ? PackageManager.INSTALL_EXTERNAL : 0)
| (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0),
null, null, null, instructionSet, null);
this.cid = cid;
@@ -9482,13 +9495,8 @@ public class PackageManagerService extends IPackageManager.Stub {
}
boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException {
try {
mContext.grantUriPermission(DEFAULT_CONTAINER_PACKAGE, packageURI,
Intent.FLAG_GRANT_READ_URI_PERMISSION);
return imcs.checkExternalFreeStorage(packageURI, isFwdLocked(), abiOverride);
} finally {
mContext.revokeUriPermission(packageURI, Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
return imcs.checkExternalFreeStorage(fromFile.getAbsolutePath(), isFwdLocked(),
abiOverride);
}
private final boolean isExternal() {
@@ -9506,16 +9514,9 @@ public class PackageManagerService extends IPackageManager.Stub {
PackageHelper.destroySdDir(cid);
}
final String newCachePath;
try {
mContext.grantUriPermission(DEFAULT_CONTAINER_PACKAGE, packageURI,
Intent.FLAG_GRANT_READ_URI_PERMISSION);
newCachePath = imcs.copyResourceToContainer(packageURI, cid, getEncryptKey(),
RES_FILE_NAME, PUBLIC_RES_FILE_NAME, isExternal(), isFwdLocked(),
abiOverride);
} finally {
mContext.revokeUriPermission(packageURI, Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
final String newCachePath = imcs.copyResourceToContainer(fromFile.getAbsolutePath(),
cid, getEncryptKey(), RES_FILE_NAME, PUBLIC_RES_FILE_NAME, isExternal(),
isFwdLocked(), abiOverride);
if (newCachePath != null) {
setCachePath(newCachePath);
@@ -10078,7 +10079,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// We didn't need to disable the .apk as a current system package,
// which means we are replacing another update that is already
// installed. We need to make sure to delete the older one's .apk.
res.removedInfo.args = createInstallArgs(0,
res.removedInfo.args = createInstallArgsForExisting(0,
deletedPackage.applicationInfo.sourceDir,
deletedPackage.applicationInfo.publicSourceDir,
deletedPackage.applicationInfo.nativeLibraryDir,
@@ -10143,7 +10144,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// TODO: extend to move split APK dex files
if ((newPackage.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
final String instructionSet = getAppInstructionSet(newPackage.applicationInfo);
int retCode = mInstaller.movedex(oldCodePath, newPackage.codePath,
int retCode = mInstaller.movedex(oldCodePath, newPackage.baseCodePath,
instructionSet);
if (retCode != 0) {
/*
@@ -10156,7 +10157,7 @@ public class PackageManagerService extends IPackageManager.Stub {
*/
newPackage.mDexOptNeeded = true;
mInstaller.rmdex(oldCodePath, instructionSet);
mInstaller.rmdex(newPackage.codePath, instructionSet);
mInstaller.rmdex(newPackage.baseCodePath, instructionSet);
}
}
return PackageManager.INSTALL_SUCCEEDED;
@@ -10221,8 +10222,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
private void installPackageLI(InstallArgs args,
boolean newInstall, PackageInstalledInfo res) {
private void installPackageLI(InstallArgs args, boolean newInstall, PackageInstalledInfo res) {
int pFlags = args.flags;
String installerPackageName = args.installerPackageName;
File tmpPackageFile = new File(args.getCodePath());
@@ -10367,14 +10367,18 @@ public class PackageManagerService extends IPackageManager.Stub {
res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
return;
}
// Set application objects path explicitly after the rename
// TODO: derive split paths from original scan after rename
pkg.codePath = args.getCodePath();
pkg.baseCodePath = args.getCodePath();
pkg.splitCodePaths = null;
pkg.applicationInfo.sourceDir = args.getCodePath();
pkg.applicationInfo.publicSourceDir = args.getResourcePath();
pkg.applicationInfo.splitSourceDirs = args.getSplitCodePaths();
pkg.applicationInfo.splitPublicSourceDirs = deriveSplitResPaths(
pkg.applicationInfo.splitSourceDirs);
pkg.applicationInfo.splitSourceDirs = null;
pkg.applicationInfo.splitPublicSourceDirs = null;
pkg.applicationInfo.nativeLibraryDir = args.getNativeLibraryPath();
if (replace) {
replacePackageLI(pkg, parseFlags, scanMode, args.user,
installerPackageName, res, args.abiOverride);
@@ -10847,8 +10851,8 @@ public class PackageManagerService extends IPackageManager.Stub {
// Delete application code and resources
if (deleteCodeAndResources && (outInfo != null)) {
outInfo.args = createInstallArgs(packageFlagsToInstallFlags(ps), ps.codePathString,
ps.resourcePathString, ps.nativeLibraryPathString,
outInfo.args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
ps.codePathString, ps.resourcePathString, ps.nativeLibraryPathString,
getAppInstructionSetFromSettings(ps));
}
return true;
@@ -11253,7 +11257,8 @@ public class PackageManagerService extends IPackageManager.Stub {
publicSrcDir = applicationInfo.publicSourceDir;
}
}
int res = mInstaller.getSizeInfo(packageName, userHandle, p.codePath, libDirPath,
// TODO: extend to measure size of split APKs
int res = mInstaller.getSizeInfo(packageName, userHandle, p.baseCodePath, libDirPath,
publicSrcDir, asecPath, getAppInstructionSetFromSettings(ps),
pStats);
if (res < 0) {
@@ -12843,9 +12848,9 @@ public class PackageManagerService extends IPackageManager.Stub {
} else {
Message msg = mHandler.obtainMessage(INIT_COPY);
final String instructionSet = getAppInstructionSet(pkg.applicationInfo);
InstallArgs srcArgs = createInstallArgs(currFlags, pkg.applicationInfo.sourceDir,
pkg.applicationInfo.publicSourceDir, pkg.applicationInfo.nativeLibraryDir,
instructionSet);
InstallArgs srcArgs = createInstallArgsForExisting(currFlags,
pkg.applicationInfo.sourceDir, pkg.applicationInfo.publicSourceDir,
pkg.applicationInfo.nativeLibraryDir, instructionSet);
MoveParams mp = new MoveParams(srcArgs, observer, newFlags, packageName,
pkg.applicationInfo.dataDir, instructionSet, pkg.applicationInfo.uid, user);
msg.obj = mp;
@@ -12943,11 +12948,13 @@ public class PackageManagerService extends IPackageManager.Stub {
if (returnCode == PackageManager.MOVE_SUCCEEDED) {
pkg.codePath = newCodePath;
pkg.baseCodePath = newCodePath;
// Move dex files around
if (moveDexFilesLI(oldCodePath, pkg) != PackageManager.INSTALL_SUCCEEDED) {
// Moving of dex files failed. Set
// error code and abort move.
pkg.codePath = oldCodePath;
pkg.baseCodePath = oldCodePath;
returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
}
}

View File

@@ -45,6 +45,12 @@ class PackageSettingBase extends GrantedPermissions {
final String name;
final String realName;
/**
* Path where this package was found on disk. For monolithic packages
* this is path to single base APK file; for cluster packages this is
* path to the cluster directory.
*/
File codePath;
String codePathString;
File resourcePath;