diff options
| author | 2018-03-02 21:28:05 +0000 | |
|---|---|---|
| committer | 2018-03-02 21:28:05 +0000 | |
| commit | e2ade72500ef0a1afaf81c41de872609116141f5 (patch) | |
| tree | 9f648201f6d57746d98525388c1060609e945687 | |
| parent | df7105a993a101a5e21c6dc30cf780a626fd112a (diff) | |
| parent | e2b4c876284eb5e58f1a58cb23ee967e7d2e965b (diff) | |
Merge "Add stats logging in appDiedLocked."
3 files changed, 94 insertions, 16 deletions
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 0de4f860d642..29d4e922e28d 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -192,7 +192,8 @@ import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS import static com.android.server.am.ActivityStackSupervisor.ON_TOP; import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS; -import static com.android.server.am.MemoryStatUtil.readMemoryStatFromMemcg; +import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem; +import static com.android.server.am.MemoryStatUtil.hasMemcg; import static com.android.server.am.TaskRecord.INVALID_TASK_ID; import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK; import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT; @@ -5925,6 +5926,12 @@ public class ActivityManagerService extends IActivityManager.Stub Slog.d(TAG_PROCESSES, "Received spurious death notification for thread " + thread.asBinder()); } + + // On the device which doesn't have Cgroup, log LmkStateChanged which is used as a signal + // for pulling memory stats of other running processes when this process died. + if (!hasMemcg()) { + StatsLog.write(StatsLog.APP_DIED, SystemClock.elapsedRealtime()); + } } /** @@ -26155,7 +26162,7 @@ public class ActivityManagerService extends IActivityManager.Stub final ProcessRecord r = mPidsSelfLocked.valueAt(i); final int pid = r.pid; final int uid = r.uid; - final MemoryStat memoryStat = readMemoryStatFromMemcg(uid, pid); + final MemoryStat memoryStat = readMemoryStatFromFilesystem(uid, pid); if (memoryStat == null) { continue; } diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java index 5d5ed550a00c..352b75704d6e 100644 --- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java @@ -34,7 +34,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_METRICS; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.am.MemoryStatUtil.MemoryStat; -import static com.android.server.am.MemoryStatUtil.readMemoryStatFromMemcg; +import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem; import android.content.Context; import android.content.pm.ApplicationInfo; @@ -635,7 +635,7 @@ class ActivityMetricsLogger { final int pid = info.processRecord.pid; final int uid = info.applicationInfo.uid; - final MemoryStat memoryStat = readMemoryStatFromMemcg(uid, pid); + final MemoryStat memoryStat = readMemoryStatFromFilesystem(uid, pid); if (memoryStat == null) { if (DEBUG_METRICS) Slog.i(TAG, "logAppStartMemoryStateCapture memoryStat null"); return; diff --git a/services/core/java/com/android/server/am/MemoryStatUtil.java b/services/core/java/com/android/server/am/MemoryStatUtil.java index a2a84ec43ed2..da36bd12781b 100644 --- a/services/core/java/com/android/server/am/MemoryStatUtil.java +++ b/services/core/java/com/android/server/am/MemoryStatUtil.java @@ -38,8 +38,12 @@ import java.util.regex.Pattern; final class MemoryStatUtil { private static final String TAG = TAG_WITH_CLASS_NAME ? "MemoryStatUtil" : TAG_AM; + /** Path to check if device has memcg */ + private static final String MEMCG_TEST_PATH = "/dev/memcg/apps/memory.stat"; /** Path to memory stat file for logging app start memory state */ private static final String MEMORY_STAT_FILE_FMT = "/dev/memcg/apps/uid_%d/pid_%d/memory.stat"; + /** Path to procfs stat file for logging app start memory state */ + private static final String PROC_STAT_FILE_FMT = "/proc/%d/stat"; private static final Pattern PGFAULT = Pattern.compile("total_pgfault (\\d+)"); private static final Pattern PGMAJFAULT = Pattern.compile("total_pgmajfault (\\d+)"); @@ -47,24 +51,57 @@ final class MemoryStatUtil { private static final Pattern CACHE_IN_BYTES = Pattern.compile("total_cache (\\d+)"); private static final Pattern SWAP_IN_BYTES = Pattern.compile("total_swap (\\d+)"); + private static final int PGFAULT_INDEX = 9; + private static final int PGMAJFAULT_INDEX = 11; + private static final int RSS_IN_BYTES_INDEX = 23; + + /** True if device has memcg */ + private static volatile Boolean sDeviceHasMemCg; + private MemoryStatUtil() {} /** + * Reads memory stat for a process. + * + * Reads from memcg if available on device, else fallback to procfs. + * Returns null if no stats can be read. + */ + @Nullable + static MemoryStat readMemoryStatFromFilesystem(int uid, int pid) { + return hasMemcg() ? readMemoryStatFromMemcg(uid, pid) : readMemoryStatFromProcfs(pid); + } + + /** * Reads memory.stat of a process from memcg. + * + * Returns null if file is not found in memcg or if file has unrecognized contents. */ @Nullable static MemoryStat readMemoryStatFromMemcg(int uid, int pid) { - final String memoryStatPath = String.format(Locale.US, MEMORY_STAT_FILE_FMT, uid, pid); - final File memoryStatFile = new File(memoryStatPath); - if (!memoryStatFile.exists()) { - if (DEBUG_METRICS) Slog.i(TAG, memoryStatPath + " not found"); + final String path = String.format(Locale.US, MEMORY_STAT_FILE_FMT, uid, pid); + return parseMemoryStatFromMemcg(readFileContents(path)); + } + + /** + * Reads memory stat of a process from procfs. + * + * Returns null if file is not found in procfs or if file has unrecognized contents. + */ + @Nullable + static MemoryStat readMemoryStatFromProcfs(int pid) { + final String path = String.format(Locale.US, PROC_STAT_FILE_FMT, pid); + return parseMemoryStatFromProcfs(readFileContents(path)); + } + + private static String readFileContents(String path) { + final File file = new File(path); + if (!file.exists()) { + if (DEBUG_METRICS) Slog.i(TAG, path + " not found"); return null; } try { - final String memoryStatContents = FileUtils.readTextFile( - memoryStatFile, 0 /* max */, null /* ellipsis */); - return parseMemoryStat(memoryStatContents); + return FileUtils.readTextFile(file, 0 /* max */, null /* ellipsis */); } catch (IOException e) { Slog.e(TAG, "Failed to read file:", e); return null; @@ -76,12 +113,12 @@ final class MemoryStatUtil { */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) @Nullable - static MemoryStat parseMemoryStat(String memoryStatContents) { - MemoryStat memoryStat = new MemoryStat(); - if (memoryStatContents == null) { - return memoryStat; + static MemoryStat parseMemoryStatFromMemcg(String memoryStatContents) { + if (memoryStatContents == null || memoryStatContents.isEmpty()) { + return null; } + final MemoryStat memoryStat = new MemoryStat(); Matcher m; m = PGFAULT.matcher(memoryStatContents); memoryStat.pgfault = m.find() ? Long.valueOf(m.group(1)) : 0; @@ -96,6 +133,40 @@ final class MemoryStatUtil { return memoryStat; } + /** + * Parses relevant statistics out from the contents of a /proc/pid/stat file in procfs. + */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + @Nullable + static MemoryStat parseMemoryStatFromProcfs(String procStatContents) { + if (procStatContents == null || procStatContents.isEmpty()) { + return null; + } + + final String[] splits = procStatContents.split(" "); + if (splits.length < 24) { + return null; + } + + final MemoryStat memoryStat = new MemoryStat(); + memoryStat.pgfault = Long.valueOf(splits[PGFAULT_INDEX]); + memoryStat.pgmajfault = Long.valueOf(splits[PGMAJFAULT_INDEX]); + memoryStat.rssInBytes = Long.valueOf(splits[RSS_IN_BYTES_INDEX]); + return memoryStat; + } + + /** + * Checks if memcg is available on device. + * + * Touches the filesystem to do the check. + */ + static boolean hasMemcg() { + if (sDeviceHasMemCg == null) { + sDeviceHasMemCg = (new File(MEMCG_TEST_PATH)).exists(); + } + return sDeviceHasMemCg; + } + static final class MemoryStat { /** Number of page faults */ long pgfault; @@ -108,4 +179,4 @@ final class MemoryStatUtil { /** Number of bytes of swap usage */ long swapInBytes; } -} +}
\ No newline at end of file |