From 78a130144bdd047665f00782c481d31edb3e5fb7 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 15 Jul 2014 20:18:34 -0700 Subject: [PATCH] Mark resource-only splits as hasCode=false. PackageManagerService now skips dexopt for split APKs that don't declare they have code. Also surface more detailed error messages in logs. Bug: 14975160 Change-Id: Ie6078dba724815020cee59b7fc52317e88ca097a --- .../android/content/pm/PackageParser.java | 10 ++++--- core/java/android/util/ExceptionUtils.java | 16 ++++++++++++ .../server/pm/PackageManagerService.java | 26 +++++++++++++------ tools/aapt/Resource.cpp | 7 +++++ 4 files changed, 48 insertions(+), 11 deletions(-) diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index d41cca601ffc4..43c2b15202d60 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -846,7 +846,7 @@ public class PackageParser { throw e; } catch (Exception e) { throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, - "Unable to read AndroidManifest.xml of " + apkPath); + "Failed to read manifest from " + apkPath, e); } finally { IoUtils.closeQuietly(parser); IoUtils.closeQuietly(assets); @@ -895,7 +895,7 @@ public class PackageParser { throw e; } catch (Exception e) { throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, - "Unable to read AndroidManifest.xml of " + apkPath); + "Failed to read manifest from " + apkPath, e); } finally { IoUtils.closeQuietly(parser); IoUtils.closeQuietly(assets); @@ -910,9 +910,13 @@ public class PackageParser { * omitted here. */ private Package parseSplitApk(Package pkg, Resources res, XmlResourceParser parser, int flags, - int splitIndex, String[] outError) throws XmlPullParserException, IOException { + int splitIndex, String[] outError) throws XmlPullParserException, IOException, + PackageParserException { AttributeSet attrs = parser; + // We parsed manifest tag earlier; just skip past it + parsePackageSplitNames(parser, attrs, flags); + mParseInstrumentationArgs = null; mParseActivityArgs = null; mParseServiceArgs = null; diff --git a/core/java/android/util/ExceptionUtils.java b/core/java/android/util/ExceptionUtils.java index 6aae84ddb41dd..f5d515d5e5d5f 100644 --- a/core/java/android/util/ExceptionUtils.java +++ b/core/java/android/util/ExceptionUtils.java @@ -39,4 +39,20 @@ public class ExceptionUtils { throw new IOException(e.getMessage().substring(PREFIX_IO.length())); } } + + public static String getCompleteMessage(String msg, Throwable t) { + final StringBuilder builder = new StringBuilder(); + if (msg != null) { + builder.append(msg).append(": "); + } + builder.append(t.getMessage()); + while ((t = t.getCause()) != null) { + builder.append(": ").append(t.getMessage()); + } + return builder.toString(); + } + + public static String getCompleteMessage(Throwable t) { + return getCompleteMessage(null, t); + } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index e17dacbe252e5..a8732dd922977 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -165,6 +165,7 @@ import android.util.ArraySet; import android.util.AtomicFile; import android.util.DisplayMetrics; import android.util.EventLog; +import android.util.ExceptionUtils; import android.util.Log; import android.util.LogPrinter; import android.util.PrintStreamPrinter; @@ -9855,6 +9856,18 @@ public class PackageManagerService extends IPackageManager.Stub { Slog.w(TAG, msg); } + public void setError(String msg, PackageParserException e) { + returnCode = e.error; + returnMsg = ExceptionUtils.getCompleteMessage(msg, e); + Slog.w(TAG, msg, e); + } + + public void setError(String msg, PackageManagerException e) { + returnCode = e.error; + returnMsg = ExceptionUtils.getCompleteMessage(msg, e); + Slog.w(TAG, msg, e); + } + // In some error cases we want to convey more info back to the observer String origPackage; String origPermission; @@ -9908,8 +9921,7 @@ public class PackageManagerService extends IPackageManager.Stub { } } catch (PackageManagerException e) { - res.setError(e.error, - "Package couldn't be installed in " + pkg.codePath + ": " + e.getMessage()); + res.setError("Package couldn't be installed in " + pkg.codePath, e); } } @@ -10007,8 +10019,7 @@ public class PackageManagerService extends IPackageManager.Stub { updateSettingsLI(newPackage, installerPackageName, allUsers, perUserInstalled, res); updatedSettings = true; } catch (PackageManagerException e) { - res.setError(e.error, - "Package couldn't be installed in " + pkg.codePath + ": " + e.getMessage()); + res.setError("Package couldn't be installed in " + pkg.codePath, e); } } @@ -10139,8 +10150,7 @@ public class PackageManagerService extends IPackageManager.Stub { } } catch (PackageManagerException e) { - res.setError(e.error, - "Package couldn't be installed in " + pkg.codePath + ": " + e.getMessage()); + res.setError("Package couldn't be installed in " + pkg.codePath, e); } if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) { @@ -10278,7 +10288,7 @@ public class PackageManagerService extends IPackageManager.Stub { try { pkg = pp.parsePackage(tmpPackageFile, parseFlags); } catch (PackageParserException e) { - res.setError(e.error, "Failed parse during installPackageLI: " + e.getMessage()); + res.setError("Failed parse during installPackageLI", e); return; } @@ -10294,7 +10304,7 @@ public class PackageManagerService extends IPackageManager.Stub { pp.collectCertificates(pkg, parseFlags); pp.collectManifestDigest(pkg); } catch (PackageParserException e) { - res.setError(e.error, "Failed collect during installPackageLI: " + e.getMessage()); + res.setError("Failed collect during installPackageLI", e); return; } diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp index 963c7962fdbb6..4f1d15ec23e1b 100644 --- a/tools/aapt/Resource.cpp +++ b/tools/aapt/Resource.cpp @@ -931,6 +931,13 @@ status_t generateAndroidManifestForSplit(Bundle* bundle, const sp& a // Build an empty tag (required). sp app = XMLNode::newElement(filename, String16(), String16("application")); + + // Add the 'hasCode' attribute which is never true for resource splits. + if (!addTagAttribute(app, RESOURCES_ANDROID_NAMESPACE, "hasCode", + "false", true, true)) { + return UNKNOWN_ERROR; + } + manifest->addChild(app); root->addChild(manifest);