summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/content/pm/PackageManager.java18
-rw-r--r--core/java/android/content/pm/PackageParser.java170
-rw-r--r--core/tests/coretests/src/android/content/pm/PackageManagerTests.java20
-rw-r--r--packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java6
-rwxr-xr-xservices/core/java/com/android/server/pm/PackageManagerService.java157
6 files changed, 236 insertions, 137 deletions
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 550c1f1..8d9b8d9 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -26,6 +26,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
+import android.content.pm.PackageParser.PackageParserException;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
@@ -2873,16 +2874,17 @@ public abstract class PackageManager {
DisplayMetrics metrics = new DisplayMetrics();
metrics.setToDefaults();
final File sourceFile = new File(archiveFilePath);
- PackageParser.Package pkg = packageParser.parsePackage(
- sourceFile, archiveFilePath, metrics, 0);
- if (pkg == null) {
+ try {
+ PackageParser.Package pkg = packageParser.parseMonolithicPackage(sourceFile, metrics,
+ 0);
+ if ((flags & GET_SIGNATURES) != 0) {
+ packageParser.collectCertificates(pkg, 0);
+ }
+ PackageUserState state = new PackageUserState();
+ return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, state);
+ } catch (PackageParserException e) {
return null;
}
- if ((flags & GET_SIGNATURES) != 0) {
- packageParser.collectCertificates(pkg, 0);
- }
- PackageUserState state = new PackageUserState();
- return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, state);
}
/**
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 4cac7fd..91895ff 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -18,6 +18,7 @@ package android.content.pm;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
import android.content.ComponentName;
import android.content.Intent;
@@ -31,6 +32,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.PatternMatcher;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Base64;
import android.util.DisplayMetrics;
@@ -81,6 +83,8 @@ public class PackageParser {
private static final boolean DEBUG_PARSER = false;
private static final boolean DEBUG_BACKUP = false;
+ // TODO: switch outError users to PackageParserException
+
/** File name in an APK for the Android manifest. */
private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
@@ -207,10 +211,10 @@ public class PackageParser {
}
}
- /* Light weight package info.
- * @hide
+ /**
+ * Lightweight parsed details about a single APK file.
*/
- public static class PackageLite {
+ public static class ApkLite {
public final String packageName;
public final String splitName;
public final int versionCode;
@@ -218,7 +222,7 @@ public class PackageParser {
public final VerifierInfo[] verifiers;
public final Signature[] signatures;
- public PackageLite(String packageName, String splitName, int versionCode,
+ public ApkLite(String packageName, String splitName, int versionCode,
int installLocation, List<VerifierInfo> verifiers, Signature[] signatures) {
this.packageName = packageName;
this.splitName = splitName;
@@ -247,6 +251,10 @@ public class PackageParser {
mArchiveSourcePath = archiveSourcePath;
}
+ public PackageParser(File archiveSource) {
+ this(archiveSource.getAbsolutePath());
+ }
+
public void setSeparateProcesses(String[] procs) {
mSeparateProcesses = procs;
}
@@ -255,6 +263,10 @@ public class PackageParser {
mOnlyCoreApps = onlyCoreApps;
}
+ private static final boolean isPackageFilename(File file) {
+ return isPackageFilename(file.getName());
+ }
+
private static final boolean isPackageFilename(String name) {
return name.endsWith(".apk");
}
@@ -497,26 +509,84 @@ public class PackageParser {
public final static int PARSE_IS_PRIVILEGED = 1<<7;
public final static int PARSE_GET_SIGNATURES = 1<<8;
- public int getParseError() {
- return mParseError;
+ /**
+ * Parse all APK files under the given directory as a single package.
+ */
+ public Package parseSplitPackage(File apkDir, DisplayMetrics metrics, int flags,
+ boolean trustedOverlay) throws PackageParserException {
+ final File[] files = apkDir.listFiles();
+ if (ArrayUtils.isEmpty(files)) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+ "No packages found in split");
+ }
+
+ File baseFile = null;
+ for (File file : files) {
+ if (file.isFile() && isPackageFilename(file)) {
+ ApkLite lite = parseApkLite(file.getAbsolutePath(), 0);
+ if (lite == null) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+ "Invalid package file: " + file);
+ }
+
+ if (TextUtils.isEmpty(lite.splitName)) {
+ baseFile = file;
+ break;
+ }
+ }
+ }
+
+ if (baseFile == null) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+ "Missing base APK in " + apkDir);
+ }
+
+ final Package pkg = parseBaseApk(baseFile, metrics, flags, trustedOverlay);
+ if (pkg == null) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+ "Failed to parse base APK: " + baseFile);
+ }
+
+ for (File file : files) {
+ if (file.isFile() && isPackageFilename(file) && !file.equals(baseFile)) {
+ parseSplitApk(pkg, file, metrics, flags, trustedOverlay);
+ }
+ }
+
+ // Always use a well-defined sort order
+ if (pkg.splitCodePaths != null) {
+ Arrays.sort(pkg.splitCodePaths);
+ }
+
+ return pkg;
+ }
+
+ public Package parseMonolithicPackage(File apkFile, DisplayMetrics metrics, int flags)
+ throws PackageParserException {
+ return parseMonolithicPackage(apkFile, metrics, flags, false);
}
- public Package parsePackage(File sourceFile, String destCodePath,
- DisplayMetrics metrics, int flags) {
- return parsePackage(sourceFile, destCodePath, metrics, flags, false);
+ public Package parseMonolithicPackage(File apkFile, DisplayMetrics metrics, int flags,
+ boolean trustedOverlay) throws PackageParserException {
+ final Package pkg = parseBaseApk(apkFile, metrics, flags, trustedOverlay);
+ if (pkg != null) {
+ return pkg;
+ } else {
+ throw new PackageParserException(mParseError, "Failed to parse " + apkFile);
+ }
}
- public Package parsePackage(File sourceFile, String destCodePath,
- DisplayMetrics metrics, int flags, boolean trustedOverlay) {
+ private Package parseBaseApk(File apkFile, DisplayMetrics metrics, int flags,
+ boolean trustedOverlay) {
mParseError = PackageManager.INSTALL_SUCCEEDED;
- mArchiveSourcePath = sourceFile.getPath();
- if (!sourceFile.isFile()) {
+ mArchiveSourcePath = apkFile.getAbsolutePath();
+ if (!apkFile.isFile()) {
Slog.w(TAG, "Skipping dir: " + mArchiveSourcePath);
mParseError = PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
return null;
}
- if (!isPackageFilename(sourceFile.getName())
+ if (!isPackageFilename(apkFile.getName())
&& (flags&PARSE_MUST_BE_APK) != 0) {
if ((flags&PARSE_IS_SYSTEM) == 0) {
// We expect to have non-.apk files in the system dir,
@@ -560,13 +630,12 @@ public class PackageParser {
Exception errorException = null;
try {
// XXXX todo: need to figure out correct configuration.
- pkg = parsePackage(res, parser, flags, trustedOverlay, errorText);
+ pkg = parseBaseApk(res, parser, flags, trustedOverlay, errorText);
} catch (Exception e) {
errorException = e;
mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
}
-
if (pkg == null) {
// If we are only parsing core apps, then a null with INSTALL_SUCCEEDED
// just means to skip this app so don't make a fuss about it.
@@ -590,22 +659,25 @@ public class PackageParser {
parser.close();
assmgr.close();
- // Set code and resource paths
- pkg.mPath = destCodePath;
- pkg.mScanPath = mArchiveSourcePath;
- //pkg.applicationInfo.sourceDir = destCodePath;
- //pkg.applicationInfo.publicSourceDir = destRes;
+ pkg.codePath = mArchiveSourcePath;
pkg.mSignatures = null;
return pkg;
}
+ private void parseSplitApk(Package pkg, File apkFile, DisplayMetrics metrics, int flags,
+ boolean trustedOverlay) throws PackageParserException {
+ // TODO: expand split APK parsing
+ pkg.splitCodePaths = ArrayUtils.appendElement(String.class, pkg.splitCodePaths,
+ apkFile.getAbsolutePath());
+ }
+
/**
* Gathers the {@link ManifestDigest} for {@code pkg} if it exists in the
* APK. If it successfully scanned the package and found the
* {@code AndroidManifest.xml}, {@code true} is returned.
*/
- public boolean collectManifestDigest(Package pkg) {
+ public void collectManifestDigest(Package pkg) throws PackageParserException {
try {
final StrictJarFile jarFile = new StrictJarFile(mArchiveSourcePath);
try {
@@ -616,13 +688,19 @@ public class PackageParser {
} finally {
jarFile.close();
}
- return true;
} catch (IOException e) {
- return false;
+ throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Failed to collect manifest digest");
+ }
+ }
+
+ public void collectCertificates(Package pkg, int flags) throws PackageParserException {
+ if (!collectCertificatesInternal(pkg, flags)) {
+ throw new PackageParserException(mParseError, "Failed to collect certificates");
}
}
- public boolean collectCertificates(Package pkg, int flags) {
+ private boolean collectCertificatesInternal(Package pkg, int flags) {
pkg.mSignatures = null;
WeakReference<byte[]> readBufferRef;
@@ -808,7 +886,7 @@ public class PackageParser {
* @param flags Special parse flags
* @return PackageLite object with package information or null on failure.
*/
- public static PackageLite parsePackageLite(String packageFilePath, int flags) {
+ public static ApkLite parseApkLite(String packageFilePath, int flags) {
AssetManager assmgr = null;
final XmlResourceParser parser;
final Resources res;
@@ -844,9 +922,9 @@ public class PackageParser {
final AttributeSet attrs = parser;
final String errors[] = new String[1];
- PackageLite packageLite = null;
+ ApkLite packageLite = null;
try {
- packageLite = parsePackageLite(res, parser, attrs, flags, signatures, errors);
+ packageLite = parseApkLite(res, parser, attrs, flags, signatures, errors);
} catch (PackageParserException e) {
Slog.w(TAG, packageFilePath, e);
} catch (IOException e) {
@@ -930,7 +1008,7 @@ public class PackageParser {
(splitName != null) ? splitName.intern() : splitName);
}
- private static PackageLite parsePackageLite(Resources res, XmlPullParser parser,
+ private static ApkLite parseApkLite(Resources res, XmlPullParser parser,
AttributeSet attrs, int flags, Signature[] signatures, String[] outError)
throws IOException, XmlPullParserException, PackageParserException {
final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs, flags);
@@ -972,7 +1050,7 @@ public class PackageParser {
}
}
- return new PackageLite(packageSplit.first, packageSplit.second, versionCode,
+ return new ApkLite(packageSplit.first, packageSplit.second, versionCode,
installLocation, verifiers, signatures);
}
@@ -988,9 +1066,8 @@ public class PackageParser {
return new Signature(sig);
}
- private Package parsePackage(
- Resources res, XmlResourceParser parser, int flags, boolean trustedOverlay,
- String[] outError) throws XmlPullParserException, IOException {
+ private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
+ boolean trustedOverlay, String[] outError) throws XmlPullParserException, IOException {
AttributeSet attrs = parser;
mParseInstrumentationArgs = null;
@@ -1019,7 +1096,13 @@ public class PackageParser {
}
}
- final Package pkg = new Package(pkgName, splitName);
+ if (!TextUtils.isEmpty(splitName)) {
+ outError[0] = "Expected base APK, but found split " + splitName;
+ mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
+ return null;
+ }
+
+ final Package pkg = new Package(pkgName);
boolean foundApp = false;
TypedArray sa = res.obtainAttributes(attrs,
@@ -3580,10 +3663,17 @@ public class PackageParser {
return true;
}
+ /**
+ * Representation of a full package parsed from APK files on disk. A package
+ * consists of a single base APK, and zero or more split APKs.
+ */
public final static class Package {
public String packageName;
- public String splitName;
+
+ // TODO: work towards making these paths invariant
+ public String codePath;
+ public String[] splitCodePaths;
// For now we only support one application per package.
public final ApplicationInfo applicationInfo = new ApplicationInfo();
@@ -3615,9 +3705,6 @@ public class PackageParser {
// We store the application meta-data independently to avoid multiple unwanted references
public Bundle mAppMetaData = null;
- // If this is a 3rd party app, this is the path of the zip file.
- public String mPath;
-
// The version code declared for this package.
public int mVersionCode;
@@ -3637,10 +3724,6 @@ public class PackageParser {
// preferred up order.
public int mPreferredOrder = 0;
- // For use by the package manager to keep track of the path to the
- // file an app came from.
- public String mScanPath;
-
// For use by package manager to keep track of where it needs to do dexopt.
public boolean mDexOptNeeded = true;
@@ -3700,9 +3783,8 @@ public class PackageParser {
public Set<PublicKey> mSigningKeys;
public Map<String, Set<PublicKey>> mKeySetMapping;
- public Package(String packageName, String splitName) {
+ public Package(String packageName) {
this.packageName = packageName;
- this.splitName = splitName;
applicationInfo.packageName = packageName;
applicationInfo.uid = -1;
}
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 07a6a10..7251e7c 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -29,6 +29,7 @@ import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageParser.PackageParserException;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
import android.net.Uri;
@@ -60,7 +61,6 @@ import android.util.Log;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
-
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -303,14 +303,13 @@ public class PackageManagerTests extends AndroidTestCase {
return Uri.fromFile(outFile);
}
- private PackageParser.Package parsePackage(Uri packageURI) {
+ private PackageParser.Package parsePackage(Uri packageURI) throws PackageParserException {
final String archiveFilePath = packageURI.getPath();
PackageParser packageParser = new PackageParser(archiveFilePath);
File sourceFile = new File(archiveFilePath);
DisplayMetrics metrics = new DisplayMetrics();
metrics.setToDefaults();
- PackageParser.Package pkg = packageParser.parsePackage(sourceFile, archiveFilePath,
- metrics, 0);
+ PackageParser.Package pkg = packageParser.parseMonolithicPackage(sourceFile, metrics, 0);
packageParser = null;
return pkg;
}
@@ -579,18 +578,18 @@ public class PackageManagerTests extends AndroidTestCase {
PackageParser.Package pkg;
- InstallParams(String outFileName, int rawResId) {
+ InstallParams(String outFileName, int rawResId) throws PackageParserException {
this.pkg = getParsedPackage(outFileName, rawResId);
- this.packageURI = Uri.fromFile(new File(pkg.mScanPath));
+ this.packageURI = Uri.fromFile(new File(pkg.codePath));
}
InstallParams(PackageParser.Package pkg) {
- this.packageURI = Uri.fromFile(new File(pkg.mScanPath));
+ this.packageURI = Uri.fromFile(new File(pkg.codePath));
this.pkg = pkg;
}
long getApkSize() {
- File file = new File(pkg.mScanPath);
+ File file = new File(pkg.codePath);
return file.length();
}
}
@@ -691,7 +690,8 @@ public class PackageManagerTests extends AndroidTestCase {
}
}
- private PackageParser.Package getParsedPackage(String outFileName, int rawResId) {
+ private PackageParser.Package getParsedPackage(String outFileName, int rawResId)
+ throws PackageParserException {
PackageManager pm = mContext.getPackageManager();
File filesDir = mContext.getFilesDir();
File outFile = new File(filesDir, outFileName);
@@ -1343,7 +1343,7 @@ public class PackageManagerTests extends AndroidTestCase {
assertUninstalled(info);
}
} finally {
- File outFile = new File(ip.pkg.mScanPath);
+ File outFile = new File(ip.pkg.codePath);
if (outFile != null && outFile.exists()) {
outFile.delete();
}
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index ec87c6e..2ed3d73 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -170,7 +170,7 @@ public class DefaultContainerService extends IntentService {
DisplayMetrics metrics = new DisplayMetrics();
metrics.setToDefaults();
- PackageParser.PackageLite pkg = PackageParser.parsePackageLite(packagePath, 0);
+ PackageParser.ApkLite pkg = PackageParser.parseApkLite(packagePath, 0);
if (pkg == null) {
Slog.w(TAG, "Failed to parse package");
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 3ed73f7..dd33771 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -28,7 +28,7 @@ import android.content.pm.IPackageInstallerSession;
import android.content.pm.PackageInstallerParams;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.PackageLite;
+import android.content.pm.PackageParser.ApkLite;
import android.content.pm.Signature;
import android.os.Build;
import android.os.Bundle;
@@ -297,7 +297,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// Verify that all staged packages are internally consistent
for (File file : files) {
- final PackageLite info = PackageParser.parsePackageLite(file.getAbsolutePath(),
+ final ApkLite info = PackageParser.parseApkLite(file.getAbsolutePath(),
PackageParser.PARSE_GET_SIGNATURES);
if (info == null) {
throw new InstallFailedException(INSTALL_FAILED_INVALID_APK,
@@ -356,7 +356,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
"Missing existing base package for " + mPackageName);
}
- final PackageLite info = PackageParser.parsePackageLite(app.sourceDir,
+ final ApkLite info = PackageParser.parseApkLite(app.sourceDir,
PackageParser.PARSE_GET_SIGNATURES);
if (info == null) {
throw new InstallFailedException(INSTALL_FAILED_INVALID_APK,
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f75e7b5..1209386 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -93,6 +93,7 @@ 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;
import android.content.pm.PackageParser;
import android.content.pm.PackageStats;
import android.content.pm.PackageUserState;
@@ -2241,8 +2242,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) == 0) {
return null;
}
- // TODO: teach about reading split name
- pkg = new PackageParser.Package(packageName, null);
+ pkg = new PackageParser.Package(packageName);
pkg.applicationInfo.packageName = packageName;
pkg.applicationInfo.flags = ps.pkgFlags | ApplicationInfo.FLAG_IS_DATA_ONLY;
pkg.applicationInfo.publicSourceDir = ps.resourcePathString;
@@ -4070,19 +4070,19 @@ 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.mScanPath + " and " +
- opkg.mScanPath + ": overlay not trusted");
+ Slog.w(TAG, "Skipping target and overlay pair " + pkg.codePath + " and " +
+ opkg.codePath + ": 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.mScanPath + " and " +
- opkg.mScanPath + " but target package has no known overlays");
+ Slog.e(TAG, "was about to create idmap for " + pkg.codePath + " and " +
+ opkg.codePath + " but target package has no known overlays");
return false;
}
final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
- if (mInstaller.idmap(pkg.mScanPath, opkg.mScanPath, sharedGid) != 0) {
- Slog.e(TAG, "Failed to generate idmap for " + pkg.mScanPath + " and " + opkg.mScanPath);
+ if (mInstaller.idmap(pkg.codePath, opkg.codePath, sharedGid) != 0) {
+ Slog.e(TAG, "Failed to generate idmap for " + pkg.codePath + " and " + opkg.codePath);
return false;
}
PackageParser.Package[] overlayArray =
@@ -4177,8 +4177,10 @@ public class PackageManagerService extends IPackageManager.Stub {
Log.i(TAG, srcFile.toString() + " changed; collecting certs");
}
- if (!pp.collectCertificates(pkg, parseFlags)) {
- mLastScanError = pp.getParseError();
+ try {
+ pp.collectCertificates(pkg, parseFlags);
+ } catch (PackageParserException e) {
+ mLastScanError = e.error;
return false;
}
return true;
@@ -4197,11 +4199,13 @@ public class PackageManagerService extends IPackageManager.Stub {
PackageParser pp = new PackageParser(scanPath);
pp.setSeparateProcesses(mSeparateProcesses);
pp.setOnlyCoreApps(mOnlyCore);
- final PackageParser.Package pkg = pp.parsePackage(scanFile,
- scanPath, mMetrics, parseFlags, (scanMode & SCAN_TRUSTED_OVERLAY) != 0);
- if (pkg == null) {
- mLastScanError = pp.getParseError();
+ final PackageParser.Package pkg;
+ try {
+ pkg = pp.parseMonolithicPackage(scanFile, mMetrics, parseFlags,
+ (scanMode & SCAN_TRUSTED_OVERLAY) != 0);
+ } catch (PackageParserException e) {
+ mLastScanError = e.error;
return null;
}
@@ -4368,12 +4372,13 @@ public class PackageManagerService extends IPackageManager.Stub {
Slog.e(TAG, "Resource path not set for pkg : " + pkg.packageName);
}
} else {
- resPath = pkg.mScanPath;
+ resPath = pkg.codePath;
}
- codePath = pkg.mScanPath;
+ codePath = pkg.codePath;
// Set application objects path explicitly.
- setApplicationInfoPaths(pkg, codePath, resPath);
+ pkg.applicationInfo.sourceDir = codePath;
+ pkg.applicationInfo.publicSourceDir = resPath;
// Note that we invoke the following method only if we are about to unpack an application
PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode
| SCAN_UPDATE_SIGNATURE, currentTime, user, abiOverride);
@@ -4398,13 +4403,6 @@ public class PackageManagerService extends IPackageManager.Stub {
return scannedPkg;
}
- private static void setApplicationInfoPaths(PackageParser.Package pkg, String destCodePath,
- String destResPath) {
- pkg.mPath = pkg.mScanPath = destCodePath;
- pkg.applicationInfo.sourceDir = destCodePath;
- pkg.applicationInfo.publicSourceDir = destResPath;
- }
-
private static String fixProcessName(String defProcessName,
String processName, int uid) {
if (processName == null) {
@@ -4630,7 +4628,7 @@ public class PackageManagerService extends IPackageManager.Stub {
boolean performed = false;
if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
- String path = pkg.mScanPath;
+ String path = pkg.codePath;
try {
boolean isDexOptNeededInternal = DexFile.isDexOptNeededInternal(path,
pkg.packageName,
@@ -4820,7 +4818,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
if (p != null) {
- usesLibraryFiles.add(p.mPath);
+ usesLibraryFiles.add(p.codePath);
}
}
@@ -4907,7 +4905,7 @@ public class PackageManagerService extends IPackageManager.Stub {
private PackageParser.Package scanPackageLI(PackageParser.Package pkg,
int parseFlags, int scanMode, long currentTime, UserHandle user, String abiOverride) {
- File scanFile = new File(pkg.mScanPath);
+ final File scanFile = new File(pkg.codePath);
if (scanFile == null || pkg.applicationInfo.sourceDir == null ||
pkg.applicationInfo.publicSourceDir == null) {
// Bail out. The resource and code paths haven't been set.
@@ -5345,7 +5343,7 @@ public class PackageManagerService extends IPackageManager.Stub {
pkgSetting.uidError = uidError;
}
- String path = scanFile.getPath();
+ final String path = scanFile.getPath();
/* Note: We don't want to unpack the native binaries for
* system applications, unless they have been updated
* (the binaries are already under /system/lib).
@@ -5476,7 +5474,6 @@ public class PackageManagerService extends IPackageManager.Stub {
handle.close();
}
}
- pkg.mScanPath = path;
if ((scanMode&SCAN_BOOTING) == 0 && pkgSetting.sharedUser != null) {
// We don't do this here during boot because we can do it all
@@ -5621,7 +5618,7 @@ public class PackageManagerService extends IPackageManager.Stub {
synchronized (mPackages) {
// We don't expect installation to fail beyond this point,
if ((scanMode&SCAN_MONITOR) != 0) {
- mAppDirs.put(pkg.mPath, pkg);
+ mAppDirs.put(pkg.codePath, pkg);
}
// Add the new setting to mSettings
mSettings.insertPackageSettingLPw(pkgSetting, pkg);
@@ -6242,8 +6239,8 @@ public class PackageManagerService extends IPackageManager.Stub {
// writer
synchronized (mPackages) {
mPackages.remove(pkg.applicationInfo.packageName);
- if (pkg.mPath != null) {
- mAppDirs.remove(pkg.mPath);
+ if (pkg.codePath != null) {
+ mAppDirs.remove(pkg.codePath);
}
cleanPackageDataStructuresLILPw(pkg, chatty);
}
@@ -9810,7 +9807,7 @@ public class PackageManagerService extends IPackageManager.Stub {
res.returnCode = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
return;
}
- if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(pkg.mPath)) {
+ if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(pkg.codePath)) {
// Don't allow installation over an existing package with the same name.
Slog.w(TAG, "Attempt to re-install " + pkgName
+ " without first uninstalling.");
@@ -9822,15 +9819,12 @@ public class PackageManagerService extends IPackageManager.Stub {
PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode,
System.currentTimeMillis(), user, abiOverride);
if (newPackage == null) {
- Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);
+ Slog.w(TAG, "Package couldn't be installed in " + pkg.codePath);
if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
}
} else {
- updateSettingsLI(newPackage,
- installerPackageName,
- null, null,
- res);
+ updateSettingsLI(null, newPackage, installerPackageName, null, null, res);
// delete the partially installed application. the data directory will have to be
// restored if it was already existing
if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
@@ -9915,15 +9909,13 @@ public class PackageManagerService extends IPackageManager.Stub {
newPackage = scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_TIME,
System.currentTimeMillis(), user, abiOverride);
if (newPackage == null) {
- Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);
+ Slog.w(TAG, "Package couldn't be installed in " + pkg.codePath);
if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
}
} else {
- updateSettingsLI(newPackage,
- installerPackageName,
- allUsers, perUserInstalled,
- res);
+ updateSettingsLI(deletedPackage, newPackage, installerPackageName, allUsers,
+ perUserInstalled, res);
updatedSettings = true;
}
}
@@ -9944,7 +9936,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// package that we deleted.
if (deletedPkg) {
if (DEBUG_INSTALL) Slog.d(TAG, "Install failed, reinstalling: " + deletedPackage);
- File restoreFile = new File(deletedPackage.mPath);
+ File restoreFile = new File(deletedPackage.codePath);
// Parse old package
boolean oldOnSd = isExternal(deletedPackage);
int oldParseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY |
@@ -10029,7 +10021,7 @@ public class PackageManagerService extends IPackageManager.Stub {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
newPackage = scanPackageLI(pkg, parseFlags, scanMode, 0, user, abiOverride);
if (newPackage == null) {
- Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);
+ Slog.w(TAG, "Package couldn't be installed in " + pkg.codePath);
if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
}
@@ -10049,7 +10041,8 @@ public class PackageManagerService extends IPackageManager.Stub {
}
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
- updateSettingsLI(newPackage, installerPackageName, allUsers, perUserInstalled, res);
+ updateSettingsLI(deletedPackage, newPackage, installerPackageName, allUsers,
+ perUserInstalled, res);
updatedSettings = true;
}
}
@@ -10075,12 +10068,21 @@ public class PackageManagerService extends IPackageManager.Stub {
}
// Utility method used to move dex files during install.
- private int moveDexFilesLI(PackageParser.Package newPackage) {
- if ((newPackage.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
+ private int moveDexFilesLI(PackageParser.Package oldPackage, PackageParser.Package newPackage) {
+ // TODO: extend to handle splits
+ if ((newPackage.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) {
final String instructionSet = getAppInstructionSet(newPackage.applicationInfo);
- int retCode = mInstaller.movedex(newPackage.mScanPath, newPackage.mPath,
- instructionSet);
- if (retCode != 0) {
+
+ boolean moveSuccess = false;
+ if (oldPackage != null
+ && (oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) {
+ if (mInstaller.movedex(oldPackage.codePath, newPackage.codePath, instructionSet)
+ == 0) {
+ moveSuccess = true;
+ }
+ }
+
+ if (!moveSuccess) {
/*
* Programs may be lazily run through dexopt, so the
* source may not exist. However, something seems to
@@ -10089,17 +10091,19 @@ public class PackageManagerService extends IPackageManager.Stub {
* remove the target to make sure there isn't a stale
* file from a previous version of the package.
*/
+ if (oldPackage != null) {
+ mInstaller.rmdex(oldPackage.codePath, instructionSet);
+ }
+ mInstaller.rmdex(newPackage.codePath, instructionSet);
newPackage.mDexOptNeeded = true;
- mInstaller.rmdex(newPackage.mScanPath, instructionSet);
- mInstaller.rmdex(newPackage.mPath, instructionSet);
}
}
return PackageManager.INSTALL_SUCCEEDED;
}
- private void updateSettingsLI(PackageParser.Package newPackage, String installerPackageName,
- int[] allUsers, boolean[] perUserInstalled,
- PackageInstalledInfo res) {
+ private void updateSettingsLI(PackageParser.Package oldPackage,
+ PackageParser.Package newPackage, String installerPackageName, int[] allUsers,
+ boolean[] perUserInstalled, PackageInstalledInfo res) {
String pkgName = newPackage.packageName;
synchronized (mPackages) {
//write settings. the installStatus will be incomplete at this stage.
@@ -10109,13 +10113,13 @@ public class PackageManagerService extends IPackageManager.Stub {
mSettings.writeLPr();
}
- if ((res.returnCode = moveDexFilesLI(newPackage))
+ if ((res.returnCode = moveDexFilesLI(oldPackage, newPackage))
!= PackageManager.INSTALL_SUCCEEDED) {
// Discontinue if moving dex files failed.
return;
}
- if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + newPackage.mPath);
+ if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + newPackage.codePath);
synchronized (mPackages) {
updatePermissionsLPw(newPackage.packageName, newPackage,
@@ -10182,12 +10186,16 @@ public class PackageManagerService extends IPackageManager.Stub {
| (onSd ? PackageParser.PARSE_ON_SDCARD : 0);
PackageParser pp = new PackageParser(tmpPackageFile.getPath());
pp.setSeparateProcesses(mSeparateProcesses);
- final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile,
- null, mMetrics, parseFlags);
- if (pkg == null) {
- res.returnCode = pp.getParseError();
+
+ final PackageParser.Package pkg;
+ try {
+ pkg = pp.parseMonolithicPackage(tmpPackageFile, mMetrics,
+ parseFlags);
+ } catch (PackageParserException e) {
+ res.returnCode = e.error;
return;
}
+
String pkgName = res.name = pkg.packageName;
if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
if ((pFlags&PackageManager.INSTALL_ALLOW_TEST) == 0) {
@@ -10195,8 +10203,11 @@ public class PackageManagerService extends IPackageManager.Stub {
return;
}
}
- if (!pp.collectCertificates(pkg, parseFlags)) {
- res.returnCode = pp.getParseError();
+
+ try {
+ pp.collectCertificates(pkg, parseFlags);
+ } catch (PackageParserException e) {
+ res.returnCode = e.error;
return;
}
@@ -10301,7 +10312,9 @@ public class PackageManagerService extends IPackageManager.Stub {
return;
}
// Set application objects path explicitly after the rename
- setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath());
+ pkg.codePath = args.getCodePath();
+ pkg.applicationInfo.sourceDir = args.getCodePath();
+ pkg.applicationInfo.publicSourceDir = args.getResourcePath();
pkg.applicationInfo.nativeLibraryDir = args.getNativeLibraryPath();
if (replace) {
replacePackageLI(pkg, parseFlags, scanMode, args.user,
@@ -11181,7 +11194,7 @@ public class PackageManagerService extends IPackageManager.Stub {
publicSrcDir = applicationInfo.publicSourceDir;
}
}
- int res = mInstaller.getSizeInfo(packageName, userHandle, p.mPath, libDirPath,
+ int res = mInstaller.getSizeInfo(packageName, userHandle, p.codePath, libDirPath,
publicSrcDir, asecPath, getAppInstructionSetFromSettings(ps),
pStats);
if (res < 0) {
@@ -12814,7 +12827,7 @@ public class PackageManagerService extends IPackageManager.Stub {
+ " Aborting move and returning error");
returnCode = PackageManager.MOVE_FAILED_INTERNAL_ERROR;
} else {
- final String oldCodePath = pkg.mPath;
+ final String oldCodePath = pkg.codePath;
final String newCodePath = mp.targetArgs.getCodePath();
final String newResPath = mp.targetArgs.getResourcePath();
final String newNativePath = mp.targetArgs
@@ -12844,18 +12857,20 @@ public class PackageManagerService extends IPackageManager.Stub {
}
if (returnCode == PackageManager.MOVE_SUCCEEDED) {
- pkg.mPath = newCodePath;
+ PackageParser.Package oldPackage = new PackageParser.Package(
+ pkg.packageName);
+ oldPackage.codePath = pkg.codePath;
+ pkg.codePath = newCodePath;
// Move dex files around
- if (moveDexFilesLI(pkg) != PackageManager.INSTALL_SUCCEEDED) {
+ if (moveDexFilesLI(oldPackage, pkg) != PackageManager.INSTALL_SUCCEEDED) {
// Moving of dex files failed. Set
// error code and abort move.
- pkg.mPath = pkg.mScanPath;
+ pkg.codePath = oldPackage.codePath;
returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
}
}
if (returnCode == PackageManager.MOVE_SUCCEEDED) {
- pkg.mScanPath = newCodePath;
pkg.applicationInfo.sourceDir = newCodePath;
pkg.applicationInfo.publicSourceDir = newResPath;
pkg.applicationInfo.nativeLibraryDir = newNativePath;