Fix issue #2048263: More debugging information
We now hopefully do better about generating the anr reports, and include
information about the malloc loaded assets in meminfo.
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 32a2891..e045105 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1701,6 +1701,14 @@
printRow(pw, TWO_COUNT_COLUMNS, "numPagers:", stats.numPagers, "inactivePageKB:",
(stats.totalBytes - stats.referencedBytes) / 1024);
printRow(pw, ONE_COUNT_COLUMN, "activePageKB:", stats.referencedBytes / 1024);
+
+ // Asset details.
+ String assetAlloc = AssetManager.getAssetAllocations();
+ if (assetAlloc != null) {
+ pw.println(" ");
+ pw.println(" Asset Allocations");
+ pw.print(assetAlloc);
+ }
}
private void printRow(PrintWriter pw, String format, Object...objs) {
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 8ebe093..0bc8a9d 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -667,6 +667,11 @@
/**
* {@hide}
*/
+ public native static final String getAssetAllocations();
+
+ /**
+ * {@hide}
+ */
public native static final int getGlobalAssetManagerCount();
private native final int newTheme();
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 66b2506..562cc8f 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -1536,6 +1536,22 @@
return Asset::getGlobalCount();
}
+static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
+{
+ String8 alloc = Asset::getAssetAllocations();
+ if (alloc.length() <= 0) {
+ return NULL;
+ }
+
+ jstring str = env->NewStringUTF(alloc.string());
+ if (str == NULL) {
+ doThrow(env, "java/lang/OutOfMemoryError");
+ return NULL;
+ }
+
+ return str;
+}
+
static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
{
return AssetManager::getGlobalCount();
@@ -1646,6 +1662,8 @@
(void*) android_content_AssetManager_destroy },
{ "getGlobalAssetCount", "()I",
(void*) android_content_AssetManager_getGlobalAssetCount },
+ { "getAssetAllocations", "()Ljava/lang/String;",
+ (void*) android_content_AssetManager_getAssetAllocations },
{ "getGlobalAssetManagerCount", "()I",
(void*) android_content_AssetManager_getGlobalAssetCount },
};
diff --git a/include/utils/Asset.h b/include/utils/Asset.h
index 453a204..5908bcc 100644
--- a/include/utils/Asset.h
+++ b/include/utils/Asset.h
@@ -45,6 +45,7 @@
virtual ~Asset(void);
static int32_t getGlobalCount();
+ static String8 getAssetAllocations();
/* used when opening an asset */
typedef enum AccessMode {
@@ -110,6 +111,12 @@
virtual int openFileDescriptor(off_t* outStart, off_t* outLength) const = 0;
/*
+ * Return whether this asset's buffer is allocated in RAM (not mmapped).
+ * Note: not virtual so it is safe to call even when being destroyed.
+ */
+ virtual bool isAllocated(void) const { return false; }
+
+ /*
* Get a string identifying the asset's source. This might be a full
* path, it might be a colon-separated list of identifiers.
*
@@ -197,6 +204,9 @@
AccessMode mAccessMode; // how the asset was opened
String8 mAssetSource; // debug string
+
+ Asset* mNext; // linked list.
+ Asset* mPrev;
};
@@ -239,6 +249,7 @@
virtual off_t getLength(void) const { return mLength; }
virtual off_t getRemainingLength(void) const { return mLength-mOffset; }
virtual int openFileDescriptor(off_t* outStart, off_t* outLength) const;
+ virtual bool isAllocated(void) const { return mBuf != NULL; }
private:
off_t mStart; // absolute file offset of start of chunk
@@ -295,6 +306,7 @@
virtual off_t getLength(void) const { return mUncompressedLen; }
virtual off_t getRemainingLength(void) const { return mUncompressedLen-mOffset; }
virtual int openFileDescriptor(off_t* outStart, off_t* outLength) const { return -1; }
+ virtual bool isAllocated(void) const { return mBuf != NULL; }
private:
off_t mStart; // offset to start of compressed data
diff --git a/libs/utils/Asset.cpp b/libs/utils/Asset.cpp
index 23cb72d..4295123 100644
--- a/libs/utils/Asset.cpp
+++ b/libs/utils/Asset.cpp
@@ -27,6 +27,7 @@
#include <utils/ZipUtils.h>
#include <utils/ZipFileRO.h>
#include <utils/Log.h>
+#include <utils/threads.h>
#include <string.h>
#include <memory.h>
@@ -40,24 +41,71 @@
# define O_BINARY 0
#endif
-static volatile int32_t gCount = 0;
+static Mutex gAssetLock;
+static int32_t gCount = 0;
+static Asset* gHead = NULL;
+static Asset* gTail = NULL;
int32_t Asset::getGlobalCount()
{
+ AutoMutex _l(gAssetLock);
return gCount;
}
+String8 Asset::getAssetAllocations()
+{
+ AutoMutex _l(gAssetLock);
+ String8 res;
+ Asset* cur = gHead;
+ while (cur != NULL) {
+ if (cur->isAllocated()) {
+ res.append(" ");
+ res.append(cur->getAssetSource());
+ off_t size = (cur->getLength()+512)/1024;
+ char buf[64];
+ sprintf(buf, ": %dK\n", (int)size);
+ res.append(buf);
+ }
+ cur = cur->mNext;
+ }
+
+ return res;
+}
+
Asset::Asset(void)
: mAccessMode(ACCESS_UNKNOWN)
{
- int count = android_atomic_inc(&gCount)+1;
- //LOGI("Creating Asset %p #%d\n", this, count);
+ AutoMutex _l(gAssetLock);
+ gCount++;
+ mNext = mPrev = NULL;
+ if (gTail == NULL) {
+ gHead = gTail = this;
+ } else {
+ mPrev = gTail;
+ gTail->mNext = this;
+ gTail = this;
+ }
+ //LOGI("Creating Asset %p #%d\n", this, gCount);
}
Asset::~Asset(void)
{
- int count = android_atomic_dec(&gCount);
- //LOGI("Destroying Asset in %p #%d\n", this, count);
+ AutoMutex _l(gAssetLock);
+ gCount--;
+ if (gHead == this) {
+ gHead = mNext;
+ }
+ if (gTail == this) {
+ gTail = mPrev;
+ }
+ if (mNext != NULL) {
+ mNext->mPrev = mPrev;
+ }
+ if (mPrev != NULL) {
+ mPrev->mNext = mNext;
+ }
+ mNext = mPrev = NULL;
+ //LOGI("Destroying Asset in %p #%d\n", this, gCount);
}
/*
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index ae790c9..04bfae6 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -4449,7 +4449,7 @@
}
final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
- final String annotation) {
+ HistoryRecord reportedActivity, final String annotation) {
if (app.notResponding || app.crashing) {
return;
}
@@ -4477,8 +4477,13 @@
StringBuilder info = mStringBuilder;
info.setLength(0);
- info.append("ANR (application not responding) in process: ");
+ info.append("ANR in process: ");
info.append(app.processName);
+ if (reportedActivity != null && reportedActivity.app != null) {
+ info.append(" (last in ");
+ info.append(reportedActivity.app.processName);
+ info.append(")");
+ }
if (annotation != null) {
info.append("\nAnnotation: ");
info.append(annotation);
@@ -4498,10 +4503,44 @@
} else {
// Dumping traces to a file so dump all active processes we know about
synchronized (this) {
- for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
+ // First, these are the most important processes.
+ final int[] imppids = new int[3];
+ int i=0;
+ imppids[0] = app.pid;
+ i++;
+ if (reportedActivity != null && reportedActivity.app != null
+ && reportedActivity.app.thread != null
+ && reportedActivity.app.pid != app.pid) {
+ imppids[i] = reportedActivity.app.pid;
+ i++;
+ }
+ imppids[i] = Process.myPid();
+ for (i=0; i<imppids.length && imppids[i] != 0; i++) {
+ Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
+ synchronized (this) {
+ try {
+ wait(200);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ for (i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
ProcessRecord r = mLRUProcesses.get(i);
- if (r.thread != null) {
+ boolean done = false;
+ for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
+ if (imppids[j] == r.pid) {
+ done = true;
+ break;
+ }
+ }
+ if (!done && r.thread != null) {
Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
+ synchronized (this) {
+ try {
+ wait(200);
+ } catch (InterruptedException e) {
+ }
+ }
}
}
}
@@ -4565,7 +4604,7 @@
if (!dir.exists()) {
fileReady = dir.mkdirs();
FileUtils.setPermissions(dir.getAbsolutePath(),
- FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IRWXO, -1, -1);
+ FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
} else if (dir.isDirectory()) {
fileReady = true;
}
@@ -4575,6 +4614,18 @@
Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
fileReady = f.delete();
}
+
+ if (removeExisting) {
+ try {
+ f.createNewFile();
+ FileUtils.setPermissions(f.getAbsolutePath(),
+ FileUtils.S_IRWXU | FileUtils.S_IRWXG
+ | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
+ fileReady = true;
+ } catch (IOException e) {
+ Log.w(TAG, "Unable to make ANR traces file", e);
+ }
+ }
}
return fileReady;
@@ -10597,7 +10648,7 @@
}
if (timeout != null && mLRUProcesses.contains(proc)) {
Log.w(TAG, "Timeout executing service: " + timeout);
- appNotRespondingLocked(proc, null, "Executing service "
+ appNotRespondingLocked(proc, null, null, "Executing service "
+ timeout.name);
} else {
Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
@@ -11392,7 +11443,8 @@
}
if (app != null) {
- appNotRespondingLocked(app, null, "Broadcast of " + r.intent.toString());
+ appNotRespondingLocked(app, null, null,
+ "Broadcast of " + r.intent.toString());
}
if (mPendingBroadcast == r) {
diff --git a/services/java/com/android/server/am/HistoryRecord.java b/services/java/com/android/server/am/HistoryRecord.java
index b3fc313..84ded22 100644
--- a/services/java/com/android/server/am/HistoryRecord.java
+++ b/services/java/com/android/server/am/HistoryRecord.java
@@ -470,7 +470,8 @@
}
if (r.app.instrumentationClass == null) {
- service.appNotRespondingLocked(r.app, r, "keyDispatchingTimedOut");
+ service.appNotRespondingLocked(r.app, r, this,
+ "keyDispatchingTimedOut");
} else {
Bundle info = new Bundle();
info.putString("shortMsg", "keyDispatchingTimedOut");