diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 32a289122cf2b..e045105ce9453 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -1701,6 +1701,14 @@ public final class ActivityThread { 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 8ebe0932c2140..0bc8a9d2e4827 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -664,6 +664,11 @@ public final class AssetManager { */ public native static final int getGlobalAssetCount(); + /** + * {@hide} + */ + public native static final String getAssetAllocations(); + /** * {@hide} */ diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index 66b250670fee3..562cc8feb4291 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -1536,6 +1536,22 @@ static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobjec 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 @@ static JNINativeMethod gAssetManagerMethods[] = { (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 453a2049ad3c6..5908bccedd64d 100644 --- a/include/utils/Asset.h +++ b/include/utils/Asset.h @@ -45,6 +45,7 @@ public: virtual ~Asset(void); static int32_t getGlobalCount(); + static String8 getAssetAllocations(); /* used when opening an asset */ typedef enum AccessMode { @@ -109,6 +110,12 @@ public: */ 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 @@ private: AccessMode mAccessMode; // how the asset was opened String8 mAssetSource; // debug string + + Asset* mNext; // linked list. + Asset* mPrev; }; @@ -239,6 +249,7 @@ public: 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 @@ public: 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 23cb72d4efca2..42951237d6274 100644 --- a/libs/utils/Asset.cpp +++ b/libs/utils/Asset.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -40,24 +41,71 @@ using namespace android; # 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 6907443e7ccb2..c59c9cc3754bd 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -4455,7 +4455,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity, - final String annotation) { + HistoryRecord reportedActivity, final String annotation) { if (app.notResponding || app.crashing) { return; } @@ -4483,8 +4483,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen 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); @@ -4504,10 +4509,44 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } 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= 0 ; i--) { ProcessRecord r = mLRUProcesses.get(i); - if (r.thread != null) { + boolean done = false; + for (int j=0; j