Fix crash in PendingIntentRecord debug output.
Add null checks to a few places to avoid crashes when dumping
debug data.
Also add some sanity checks for accessing content providers in
the activity manager.
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 7f9a5c6..1070f08 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -24,6 +24,7 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
+import java.util.HashMap;
/**
* Provides access to an application's raw asset files; see {@link Resources}
@@ -59,6 +60,8 @@
private static final String TAG = "AssetManager";
private static final boolean localLOGV = Config.LOGV || false;
+ private static final boolean DEBUG_REFS = false;
+
private static final Object sSync = new Object();
private static AssetManager sSystem = null;
@@ -72,6 +75,7 @@
private int mNumRefs = 1;
private boolean mOpen = true;
+ private HashMap<Integer, RuntimeException> mRefStacks;
/**
* Create a new AssetManager containing only the basic system assets.
@@ -82,6 +86,10 @@
*/
public AssetManager() {
synchronized (this) {
+ if (DEBUG_REFS) {
+ mNumRefs = 0;
+ incRefsLocked(this.hashCode());
+ }
init();
if (localLOGV) Log.v(TAG, "New asset manager: " + this);
ensureSystemAssets();
@@ -99,6 +107,12 @@
}
private AssetManager(boolean isSystem) {
+ if (DEBUG_REFS) {
+ synchronized (this) {
+ mNumRefs = 0;
+ incRefsLocked(this.hashCode());
+ }
+ }
init();
if (localLOGV) Log.v(TAG, "New asset manager: " + this);
}
@@ -122,7 +136,7 @@
// + ", released=" + mReleased);
if (mOpen) {
mOpen = false;
- decRefsLocked();
+ decRefsLocked(this.hashCode());
}
}
}
@@ -298,8 +312,9 @@
}
int asset = openAsset(fileName, accessMode);
if (asset != 0) {
- mNumRefs++;
- return new AssetInputStream(asset);
+ AssetInputStream res = new AssetInputStream(asset);
+ incRefsLocked(res.hashCode());
+ return res;
}
}
throw new FileNotFoundException("Asset file: " + fileName);
@@ -389,8 +404,9 @@
}
int asset = openNonAssetNative(cookie, fileName, accessMode);
if (asset != 0) {
- mNumRefs++;
- return new AssetInputStream(asset);
+ AssetInputStream res = new AssetInputStream(asset);
+ incRefsLocked(res.hashCode());
+ return res;
}
}
throw new FileNotFoundException("Asset absolute file: " + fileName);
@@ -468,16 +484,17 @@
}
int xmlBlock = openXmlAssetNative(cookie, fileName);
if (xmlBlock != 0) {
- mNumRefs++;
- return new XmlBlock(this, xmlBlock);
+ XmlBlock res = new XmlBlock(this, xmlBlock);
+ incRefsLocked(res.hashCode());
+ return res;
}
}
throw new FileNotFoundException("Asset XML file: " + fileName);
}
- /*package*/ void xmlBlockGone() {
+ /*package*/ void xmlBlockGone(int id) {
synchronized (this) {
- decRefsLocked();
+ decRefsLocked(id);
}
}
@@ -486,20 +503,34 @@
if (!mOpen) {
throw new RuntimeException("Assetmanager has been closed");
}
- mNumRefs++;
- return newTheme();
+ int res = newTheme();
+ incRefsLocked(res);
+ return res;
}
}
/*package*/ final void releaseTheme(int theme) {
synchronized (this) {
deleteTheme(theme);
- decRefsLocked();
+ decRefsLocked(theme);
}
}
protected void finalize() throws Throwable {
- destroy();
+ try {
+ if (DEBUG_REFS && mNumRefs != 0) {
+ Log.w(TAG, "AssetManager " + this
+ + " finalized with non-zero refs: " + mNumRefs);
+ if (mRefStacks != null) {
+ for (RuntimeException e : mRefStacks.values()) {
+ Log.w(TAG, "Reference from here", e);
+ }
+ }
+ }
+ destroy();
+ } finally {
+ super.finalize();
+ }
}
public final class AssetInputStream extends InputStream {
@@ -526,7 +557,7 @@
if (mAsset != 0) {
destroyAsset(mAsset);
mAsset = 0;
- decRefsLocked();
+ decRefsLocked(hashCode());
}
}
}
@@ -710,7 +741,22 @@
private native final void init();
private native final void destroy();
- private final void decRefsLocked() {
+ private final void incRefsLocked(int id) {
+ if (DEBUG_REFS) {
+ if (mRefStacks == null) {
+ mRefStacks = new HashMap<Integer, RuntimeException>();
+ RuntimeException ex = new RuntimeException();
+ ex.fillInStackTrace();
+ mRefStacks.put(this.hashCode(), ex);
+ }
+ }
+ mNumRefs++;
+ }
+
+ private final void decRefsLocked(int id) {
+ if (DEBUG_REFS && mRefStacks != null) {
+ mRefStacks.remove(id);
+ }
mNumRefs--;
//System.out.println("Dec streams: mNumRefs=" + mNumRefs
// + " mReleased=" + mReleased);
diff --git a/core/java/android/content/res/XmlBlock.java b/core/java/android/content/res/XmlBlock.java
index f800232..3c2c30a 100644
--- a/core/java/android/content/res/XmlBlock.java
+++ b/core/java/android/content/res/XmlBlock.java
@@ -59,7 +59,7 @@
if (mOpenCount == 0) {
nativeDestroy(mNative);
if (mAssets != null) {
- mAssets.xmlBlockGone();
+ mAssets.xmlBlockGone(hashCode());
}
}
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 4169cc5..7b64704 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -7615,6 +7615,15 @@
? cpi.readPermission : cpi.writePermission);
}
+ if (!mSystemReady && !mDidUpdate && !mWaitingUpdate
+ && !cpi.processName.equals("system")) {
+ // If this content provider does not run in the system
+ // process, and the system is not yet ready to run other
+ // processes, then fail fast instead of hanging.
+ throw new IllegalArgumentException(
+ "Attempt to launch content provider before system ready");
+ }
+
cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
final boolean firstClass = cpr == null;
if (firstClass) {
@@ -7862,6 +7871,16 @@
public static final void installSystemProviders() {
ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
List providers = mSelf.generateApplicationProvidersLocked(app);
+ if (providers != null) {
+ for (int i=providers.size()-1; i>=0; i--) {
+ ProviderInfo pi = (ProviderInfo)providers.get(i);
+ if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
+ Log.w(TAG, "Not installing system proc provider " + pi.name
+ + ": not system .apk");
+ providers.remove(i);
+ }
+ }
+ }
mSystemThread.installSystemProviders(providers);
}
diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/java/com/android/server/am/PendingIntentRecord.java
index 94b5f56..fac47d7 100644
--- a/services/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/java/com/android/server/am/PendingIntentRecord.java
@@ -145,8 +145,9 @@
public String toString() {
return "Key{" + typeName() + " pkg=" + packageName
- + " intent=" + requestIntent.toShortString(true, false) + " flags=0x"
- + Integer.toHexString(flags) + "}";
+ + " intent="
+ + (requestIntent != null ? requestIntent.toShortString(true, false) : "<null>")
+ + " flags=0x" + Integer.toHexString(flags) + "}";
}
String typeName() {
@@ -295,8 +296,10 @@
pw.print(prefix); pw.print("requestCode="); pw.print(key.requestCode);
pw.print(" requestResolvedType="); pw.println(key.requestResolvedType);
}
- pw.print(prefix); pw.print("requestIntent=");
- pw.println(key.requestIntent.toShortString(true, true));
+ if (key.requestIntent != null) {
+ pw.print(prefix); pw.print("requestIntent=");
+ pw.println(key.requestIntent.toShortString(true, true));
+ }
if (sent || canceled) {
pw.print(prefix); pw.print("sent="); pw.print(sent);
pw.print(" canceled="); pw.println(canceled);