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
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index d41cca6..43c2b15 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -846,7 +846,7 @@
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 @@
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 @@
* 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 6aae84d..f5d515d 100644
--- a/core/java/android/util/ExceptionUtils.java
+++ b/core/java/android/util/ExceptionUtils.java
@@ -39,4 +39,20 @@
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 e17dacb..a8732dd 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.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 @@
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 @@
}
} 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 @@
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 @@
}
} 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 @@
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 @@
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 963c796..4f1d15e 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -931,6 +931,13 @@
// Build an empty <application> tag (required).
sp<XMLNode> 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);