diff options
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; |