diff options
| -rw-r--r-- | apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java | 303 | ||||
| -rw-r--r-- | cmds/statsd/src/external/StatsPullerManager.cpp | 39 | ||||
| -rw-r--r-- | services/core/java/com/android/server/stats/pull/IonMemoryUtil.java (renamed from services/core/java/com/android/server/stats/IonMemoryUtil.java) | 15 | ||||
| -rw-r--r-- | services/core/java/com/android/server/stats/pull/ProcfsMemoryUtil.java (renamed from services/core/java/com/android/server/stats/ProcfsMemoryUtil.java) | 12 | ||||
| -rw-r--r-- | services/core/java/com/android/server/stats/pull/StatsPullAtomService.java (renamed from services/core/java/com/android/server/stats/StatsPullAtomService.java) | 409 | ||||
| -rw-r--r-- | services/java/com/android/server/SystemServer.java | 2 | ||||
| -rw-r--r-- | services/tests/servicestests/src/com/android/server/stats/pull/IonMemoryUtilTest.java (renamed from services/tests/servicestests/src/com/android/server/stats/IonMemoryUtilTest.java) | 8 |
7 files changed, 397 insertions, 391 deletions
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java index 8bc14d70ff87..17573bb22fea 100644 --- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java +++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java @@ -24,11 +24,11 @@ import static android.os.storage.VolumeInfo.TYPE_PRIVATE; import static android.os.storage.VolumeInfo.TYPE_PUBLIC; import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem; -import static com.android.server.stats.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs; -import static com.android.server.stats.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs; -import static com.android.server.stats.ProcfsMemoryUtil.forEachPid; -import static com.android.server.stats.ProcfsMemoryUtil.readCmdlineFromProcfs; -import static com.android.server.stats.ProcfsMemoryUtil.readMemorySnapshotFromProcfs; +import static com.android.server.stats.pull.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs; +import static com.android.server.stats.pull.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs; +import static com.android.server.stats.pull.ProcfsMemoryUtil.forEachPid; +import static com.android.server.stats.pull.ProcfsMemoryUtil.readCmdlineFromProcfs; +import static com.android.server.stats.pull.ProcfsMemoryUtil.readMemorySnapshotFromProcfs; import android.annotation.NonNull; import android.annotation.Nullable; @@ -135,8 +135,8 @@ import com.android.server.SystemServiceManager; import com.android.server.am.MemoryStatUtil.MemoryStat; import com.android.server.notification.NotificationManagerService; import com.android.server.role.RoleManagerInternal; -import com.android.server.stats.IonMemoryUtil.IonAllocations; -import com.android.server.stats.ProcfsMemoryUtil.MemorySnapshot; +import com.android.server.stats.pull.IonMemoryUtil.IonAllocations; +import com.android.server.stats.pull.ProcfsMemoryUtil.MemorySnapshot; import com.android.server.storage.DiskStatsFileLogger; import com.android.server.storage.DiskStatsLoggingService; @@ -722,207 +722,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { pulledData.add(e); } - private void pullProcessMemoryState( - int tagId, long elapsedNanos, long wallClockNanos, - List<StatsLogEventWrapper> pulledData) { - List<ProcessMemoryState> processMemoryStates = - LocalServices.getService( - ActivityManagerInternal.class).getMemoryStateForProcesses(); - for (ProcessMemoryState processMemoryState : processMemoryStates) { - final MemoryStat memoryStat = readMemoryStatFromFilesystem(processMemoryState.uid, - processMemoryState.pid); - if (memoryStat == null) { - continue; - } - StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); - e.writeInt(processMemoryState.uid); - e.writeString(processMemoryState.processName); - e.writeInt(processMemoryState.oomScore); - e.writeLong(memoryStat.pgfault); - e.writeLong(memoryStat.pgmajfault); - e.writeLong(memoryStat.rssInBytes); - e.writeLong(memoryStat.cacheInBytes); - e.writeLong(memoryStat.swapInBytes); - e.writeLong(-1); // unused - e.writeLong(-1); // unused - e.writeInt(-1); // unsed - pulledData.add(e); - } - } - - private void pullProcessMemoryHighWaterMark( - int tagId, long elapsedNanos, long wallClockNanos, - List<StatsLogEventWrapper> pulledData) { - List<ProcessMemoryState> managedProcessList = - LocalServices.getService( - ActivityManagerInternal.class).getMemoryStateForProcesses(); - for (ProcessMemoryState managedProcess : managedProcessList) { - final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(managedProcess.pid); - if (snapshot == null) { - continue; - } - StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); - e.writeInt(managedProcess.uid); - e.writeString(managedProcess.processName); - // RSS high-water mark in bytes. - e.writeLong((long) snapshot.rssHighWaterMarkInKilobytes * 1024L); - e.writeInt(snapshot.rssHighWaterMarkInKilobytes); - pulledData.add(e); - } - forEachPid((pid, cmdLine) -> { - if (!MEMORY_INTERESTING_NATIVE_PROCESSES.contains(cmdLine)) { - return; - } - final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(pid); - if (snapshot == null) { - return; - } - // Sometimes we get here a process that is not included in the whitelist. It comes - // from forking the zygote for an app. We can ignore that sample because this process - // is collected by ProcessMemoryState. - if (isAppUid(snapshot.uid)) { - return; - } - StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); - e.writeInt(snapshot.uid); - e.writeString(cmdLine); - // RSS high-water mark in bytes. - e.writeLong((long) snapshot.rssHighWaterMarkInKilobytes * 1024L); - e.writeInt(snapshot.rssHighWaterMarkInKilobytes); - pulledData.add(e); - }); - // Invoke rss_hwm_reset binary to reset RSS HWM counters for all processes. - SystemProperties.set("sys.rss_hwm_reset.on", "1"); - } - - private void pullProcessMemorySnapshot( - int tagId, long elapsedNanos, long wallClockNanos, - List<StatsLogEventWrapper> pulledData) { - List<ProcessMemoryState> managedProcessList = - LocalServices.getService( - ActivityManagerInternal.class).getMemoryStateForProcesses(); - for (ProcessMemoryState managedProcess : managedProcessList) { - final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(managedProcess.pid); - if (snapshot == null) { - continue; - } - StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); - e.writeInt(managedProcess.uid); - e.writeString(managedProcess.processName); - e.writeInt(managedProcess.pid); - e.writeInt(managedProcess.oomScore); - e.writeInt(snapshot.rssInKilobytes); - e.writeInt(snapshot.anonRssInKilobytes); - e.writeInt(snapshot.swapInKilobytes); - e.writeInt(snapshot.anonRssInKilobytes + snapshot.swapInKilobytes); - pulledData.add(e); - } - forEachPid((pid, cmdLine) -> { - if (!MEMORY_INTERESTING_NATIVE_PROCESSES.contains(cmdLine)) { - return; - } - final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(pid); - if (snapshot == null) { - return; - } - // Sometimes we get here a process that is not included in the whitelist. It comes - // from forking the zygote for an app. We can ignore that sample because this process - // is collected by ProcessMemoryState. - if (isAppUid(snapshot.uid)) { - return; - } - StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); - e.writeInt(snapshot.uid); - e.writeString(cmdLine); - e.writeInt(pid); - e.writeInt(-1001); // Placeholder for native processes, OOM_SCORE_ADJ_MIN - 1. - e.writeInt(snapshot.rssInKilobytes); - e.writeInt(snapshot.anonRssInKilobytes); - e.writeInt(snapshot.swapInKilobytes); - e.writeInt(snapshot.anonRssInKilobytes + snapshot.swapInKilobytes); - pulledData.add(e); - }); - } - - private static boolean isAppUid(int uid) { - return uid >= MIN_APP_UID; - } - - private void pullSystemIonHeapSize( - int tagId, long elapsedNanos, long wallClockNanos, - List<StatsLogEventWrapper> pulledData) { - final long systemIonHeapSizeInBytes = readSystemIonHeapSizeFromDebugfs(); - StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); - e.writeLong(systemIonHeapSizeInBytes); - pulledData.add(e); - } - - private void pullProcessSystemIonHeapSize( - int tagId, long elapsedNanos, long wallClockNanos, - List<StatsLogEventWrapper> pulledData) { - List<IonAllocations> result = readProcessSystemIonHeapSizesFromDebugfs(); - for (IonAllocations allocations : result) { - StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); - e.writeInt(getUidForPid(allocations.pid)); - e.writeString(readCmdlineFromProcfs(allocations.pid)); - e.writeInt((int) (allocations.totalSizeInBytes / 1024)); - e.writeInt(allocations.count); - e.writeInt((int) (allocations.maxSizeInBytes / 1024)); - pulledData.add(e); - } - } - - private void pullBinderCallsStats( - int tagId, long elapsedNanos, long wallClockNanos, - List<StatsLogEventWrapper> pulledData) { - BinderCallsStatsService.Internal binderStats = - LocalServices.getService(BinderCallsStatsService.Internal.class); - if (binderStats == null) { - throw new IllegalStateException("binderStats is null"); - } - - List<ExportedCallStat> callStats = binderStats.getExportedCallStats(); - binderStats.reset(); - for (ExportedCallStat callStat : callStats) { - StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); - e.writeInt(callStat.workSourceUid); - e.writeString(callStat.className); - e.writeString(callStat.methodName); - e.writeLong(callStat.callCount); - e.writeLong(callStat.exceptionCount); - e.writeLong(callStat.latencyMicros); - e.writeLong(callStat.maxLatencyMicros); - e.writeLong(callStat.cpuTimeMicros); - e.writeLong(callStat.maxCpuTimeMicros); - e.writeLong(callStat.maxReplySizeBytes); - e.writeLong(callStat.maxRequestSizeBytes); - e.writeLong(callStat.recordedCallCount); - e.writeInt(callStat.screenInteractive ? 1 : 0); - e.writeInt(callStat.callingUid); - pulledData.add(e); - } - } - - private void pullBinderCallsStatsExceptions( - int tagId, long elapsedNanos, long wallClockNanos, - List<StatsLogEventWrapper> pulledData) { - BinderCallsStatsService.Internal binderStats = - LocalServices.getService(BinderCallsStatsService.Internal.class); - if (binderStats == null) { - throw new IllegalStateException("binderStats is null"); - } - - ArrayMap<String, Integer> exceptionStats = binderStats.getExportedExceptionStats(); - // TODO: decouple binder calls exceptions with the rest of the binder calls data so that we - // can reset the exception stats. - for (Entry<String, Integer> entry : exceptionStats.entrySet()) { - StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); - e.writeString(entry.getKey()); - e.writeInt(entry.getValue()); - pulledData.add(e); - } - } - private void pullLooperStats(int tagId, long elapsedNanos, long wallClockNanos, List<StatsLogEventWrapper> pulledData) { LooperStats looperStats = LocalServices.getService(LooperStats.class); @@ -1397,49 +1196,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } - private void pullTemperature(int tagId, long elapsedNanos, long wallClockNanos, - List<StatsLogEventWrapper> pulledData) { - long callingToken = Binder.clearCallingIdentity(); - try { - List<Temperature> temperatures = sThermalService.getCurrentTemperatures(); - for (Temperature temp : temperatures) { - StatsLogEventWrapper e = - new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); - e.writeInt(temp.getType()); - e.writeString(temp.getName()); - e.writeInt((int) (temp.getValue() * 10)); - e.writeInt(temp.getStatus()); - pulledData.add(e); - } - } catch (RemoteException e) { - // Should not happen. - Slog.e(TAG, "Disconnected from thermal service. Cannot pull temperatures."); - } finally { - Binder.restoreCallingIdentity(callingToken); - } - } - - private void pullCoolingDevices(int tagId, long elapsedNanos, long wallClockNanos, - List<StatsLogEventWrapper> pulledData) { - long callingToken = Binder.clearCallingIdentity(); - try { - List<CoolingDevice> devices = sThermalService.getCurrentCoolingDevices(); - for (CoolingDevice device : devices) { - StatsLogEventWrapper e = - new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); - e.writeInt(device.getType()); - e.writeString(device.getName()); - e.writeInt((int) (device.getValue())); - pulledData.add(e); - } - } catch (RemoteException e) { - // Should not happen. - Slog.e(TAG, "Disconnected from thermal service. Cannot pull temperatures."); - } finally { - Binder.restoreCallingIdentity(callingToken); - } - } - private void pullDebugElapsedClock(int tagId, long elapsedNanos, final long wallClockNanos, List<StatsLogEventWrapper> pulledData) { final long elapsedMillis = SystemClock.elapsedRealtime(); @@ -1823,41 +1579,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { break; } - case StatsLog.PROCESS_MEMORY_STATE: { - pullProcessMemoryState(tagId, elapsedNanos, wallClockNanos, ret); - break; - } - - case StatsLog.PROCESS_MEMORY_HIGH_WATER_MARK: { - pullProcessMemoryHighWaterMark(tagId, elapsedNanos, wallClockNanos, ret); - break; - } - - case StatsLog.PROCESS_MEMORY_SNAPSHOT: { - pullProcessMemorySnapshot(tagId, elapsedNanos, wallClockNanos, ret); - break; - } - - case StatsLog.SYSTEM_ION_HEAP_SIZE: { - pullSystemIonHeapSize(tagId, elapsedNanos, wallClockNanos, ret); - break; - } - - case StatsLog.PROCESS_SYSTEM_ION_HEAP_SIZE: { - pullProcessSystemIonHeapSize(tagId, elapsedNanos, wallClockNanos, ret); - break; - } - - case StatsLog.BINDER_CALLS: { - pullBinderCallsStats(tagId, elapsedNanos, wallClockNanos, ret); - break; - } - - case StatsLog.BINDER_CALLS_EXCEPTIONS: { - pullBinderCallsStatsExceptions(tagId, elapsedNanos, wallClockNanos, ret); - break; - } - case StatsLog.LOOPER_STATS: { pullLooperStats(tagId, elapsedNanos, wallClockNanos, ret); break; @@ -1920,16 +1641,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { break; } - case StatsLog.TEMPERATURE: { - pullTemperature(tagId, elapsedNanos, wallClockNanos, ret); - break; - } - - case StatsLog.COOLING_DEVICE: { - pullCoolingDevices(tagId, elapsedNanos, wallClockNanos, ret); - break; - } - case StatsLog.DEBUG_ELAPSED_CLOCK: { pullDebugElapsedClock(tagId, elapsedNanos, wallClockNanos, ret); break; diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index 591d7277b299..d5cda85f412a 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -95,45 +95,6 @@ std::map<PullerKey, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { {{.atomTag = android::util::BATTERY_CYCLE_COUNT}, {.puller = new ResourceHealthManagerPuller(android::util::BATTERY_CYCLE_COUNT)}}, - // process_memory_state - {{.atomTag = android::util::PROCESS_MEMORY_STATE}, - {.additiveFields = {4, 5, 6, 7, 8}, - .puller = new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}}, - - // process_memory_high_water_mark - {{.atomTag = android::util::PROCESS_MEMORY_HIGH_WATER_MARK}, - {.puller = - new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_HIGH_WATER_MARK)}}, - - // process_memory_snapshot - {{.atomTag = android::util::PROCESS_MEMORY_SNAPSHOT}, - {.puller = new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_SNAPSHOT)}}, - - // system_ion_heap_size - {{.atomTag = android::util::SYSTEM_ION_HEAP_SIZE}, - {.puller = new StatsCompanionServicePuller(android::util::SYSTEM_ION_HEAP_SIZE)}}, - - // process_system_ion_heap_size - {{.atomTag = android::util::PROCESS_SYSTEM_ION_HEAP_SIZE}, - {.puller = new StatsCompanionServicePuller(android::util::PROCESS_SYSTEM_ION_HEAP_SIZE)}}, - - // temperature - {{.atomTag = android::util::TEMPERATURE}, - {.puller = new StatsCompanionServicePuller(android::util::TEMPERATURE)}}, - - // cooling_device - {{.atomTag = android::util::COOLING_DEVICE}, - {.puller = new StatsCompanionServicePuller(android::util::COOLING_DEVICE)}}, - - // binder_calls - {{.atomTag = android::util::BINDER_CALLS}, - {.additiveFields = {4, 5, 6, 8, 12}, - .puller = new StatsCompanionServicePuller(android::util::BINDER_CALLS)}}, - - // binder_calls_exceptions - {{.atomTag = android::util::BINDER_CALLS_EXCEPTIONS}, - {.puller = new StatsCompanionServicePuller(android::util::BINDER_CALLS_EXCEPTIONS)}}, - // looper_stats {{.atomTag = android::util::LOOPER_STATS}, {.additiveFields = {5, 6, 7, 8, 9}, diff --git a/services/core/java/com/android/server/stats/IonMemoryUtil.java b/services/core/java/com/android/server/stats/pull/IonMemoryUtil.java index c9be96f08876..fde0a590df34 100644 --- a/services/core/java/com/android/server/stats/IonMemoryUtil.java +++ b/services/core/java/com/android/server/stats/pull/IonMemoryUtil.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.server.stats; +package com.android.server.stats.pull; import android.os.FileUtils; import android.util.Slog; @@ -30,8 +30,11 @@ import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; -/** Utility methods for reading ion memory stats. */ -final class IonMemoryUtil { +/** + * Utility methods for reading ion memory stats. + * TODO: Consider making package private after puller migration + */ +public final class IonMemoryUtil { private static final String TAG = "IonMemoryUtil"; /** Path to debugfs file for the system ion heap. */ @@ -50,7 +53,7 @@ final class IonMemoryUtil { * Returns value of the total size in bytes of the system ion heap from * /sys/kernel/debug/ion/heaps/system. */ - static long readSystemIonHeapSizeFromDebugfs() { + public static long readSystemIonHeapSizeFromDebugfs() { return parseIonHeapSizeFromDebugfs(readFile(DEBUG_SYSTEM_ION_HEAP_FILE)); } @@ -78,7 +81,7 @@ final class IonMemoryUtil { * Returns values of allocation sizes in bytes on the system ion heap from * /sys/kernel/debug/ion/heaps/system. */ - static List<IonAllocations> readProcessSystemIonHeapSizesFromDebugfs() { + public static List<IonAllocations> readProcessSystemIonHeapSizesFromDebugfs() { return parseProcessIonHeapSizesFromDebugfs(readFile(DEBUG_SYSTEM_ION_HEAP_FILE)); } @@ -130,7 +133,7 @@ final class IonMemoryUtil { } /** Summary information about process ion allocations. */ - static final class IonAllocations { + public static final class IonAllocations { /** PID these allocations belong to. */ public int pid; /** Size of all individual allocations added together. */ diff --git a/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java b/services/core/java/com/android/server/stats/pull/ProcfsMemoryUtil.java index c1eacce1f304..638dfd23c27f 100644 --- a/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java +++ b/services/core/java/com/android/server/stats/pull/ProcfsMemoryUtil.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.server.stats; +package com.android.server.stats.pull; import static android.os.Process.PROC_OUT_STRING; @@ -22,7 +22,7 @@ import android.os.Process; import java.util.function.BiConsumer; -final class ProcfsMemoryUtil { +public final class ProcfsMemoryUtil { private static final int[] CMDLINE_OUT = new int[] { PROC_OUT_STRING }; private static final String[] STATUS_KEYS = new String[] { "Uid:", @@ -39,7 +39,7 @@ final class ProcfsMemoryUtil { * VmSwap fields in /proc/pid/status in kilobytes or null if not available. */ @Nullable - static MemorySnapshot readMemorySnapshotFromProcfs(int pid) { + public static MemorySnapshot readMemorySnapshotFromProcfs(int pid) { long[] output = new long[STATUS_KEYS.length]; output[0] = -1; Process.readProcLines("/proc/" + pid + "/status", STATUS_KEYS, output); @@ -63,7 +63,7 @@ final class ProcfsMemoryUtil { * Returns content of /proc/pid/cmdline (e.g. /system/bin/statsd) or an empty string * if the file is not available. */ - static String readCmdlineFromProcfs(int pid) { + public static String readCmdlineFromProcfs(int pid) { String[] cmdline = new String[1]; if (!Process.readProcFile("/proc/" + pid + "/cmdline", CMDLINE_OUT, cmdline, null, null)) { return ""; @@ -71,7 +71,7 @@ final class ProcfsMemoryUtil { return cmdline[0]; } - static void forEachPid(BiConsumer<Integer, String> func) { + public static void forEachPid(BiConsumer<Integer, String> func) { int[] pids = new int[1024]; pids = Process.getPids("/proc", pids); for (int pid : pids) { @@ -86,7 +86,7 @@ final class ProcfsMemoryUtil { } } - static final class MemorySnapshot { + public static final class MemorySnapshot { public int uid; public int rssHighWaterMarkInKilobytes; public int rssInKilobytes; diff --git a/services/core/java/com/android/server/stats/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java index f78330e9e7d2..3bc860adff0c 100644 --- a/services/core/java/com/android/server/stats/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.stats; +package com.android.server.stats.pull; import static android.app.AppOpsManager.OP_FLAGS_ALL_TRUSTED; import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED; @@ -26,11 +26,11 @@ import static android.os.storage.VolumeInfo.TYPE_PRIVATE; import static android.os.storage.VolumeInfo.TYPE_PUBLIC; import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem; -import static com.android.server.stats.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs; -import static com.android.server.stats.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs; -import static com.android.server.stats.ProcfsMemoryUtil.forEachPid; -import static com.android.server.stats.ProcfsMemoryUtil.readCmdlineFromProcfs; -import static com.android.server.stats.ProcfsMemoryUtil.readMemorySnapshotFromProcfs; +import static com.android.server.stats.pull.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs; +import static com.android.server.stats.pull.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs; +import static com.android.server.stats.pull.ProcfsMemoryUtil.forEachPid; +import static com.android.server.stats.pull.ProcfsMemoryUtil.readCmdlineFromProcfs; +import static com.android.server.stats.pull.ProcfsMemoryUtil.readMemorySnapshotFromProcfs; import android.annotation.NonNull; import android.annotation.Nullable; @@ -142,8 +142,8 @@ import com.android.server.SystemServiceManager; import com.android.server.am.MemoryStatUtil.MemoryStat; import com.android.server.notification.NotificationManagerService; import com.android.server.role.RoleManagerInternal; -import com.android.server.stats.IonMemoryUtil.IonAllocations; -import com.android.server.stats.ProcfsMemoryUtil.MemorySnapshot; +import com.android.server.stats.pull.IonMemoryUtil.IonAllocations; +import com.android.server.stats.pull.ProcfsMemoryUtil.MemorySnapshot; import com.android.server.storage.DiskStatsFileLogger; import com.android.server.storage.DiskStatsLoggingService; @@ -270,8 +270,8 @@ public class StatsPullAtomService extends SystemService { registerProcessSystemIonHeapSize(); registerTemperature(); registerCoolingDevice(); - registerBinderCalls(); - registerBinderCallsExceptions(); + registerBinderCallsStats(); + registerBinderCallsStatsExceptions(); registerLooperStats(); registerDiskStats(); registerDirectoryUsage(); @@ -1004,35 +1004,227 @@ public class StatsPullAtomService extends SystemService { } private void registerProcessMemoryState() { - // No op. + int tagId = StatsLog.PROCESS_MEMORY_STATE; + PullAtomMetadata metadata = PullAtomMetadata.newBuilder() + .setAdditiveFields(new int[] {4, 5, 6, 7, 8}) + .build(); + mStatsManager.registerPullAtomCallback( + tagId, + metadata, + (atomTag, data) -> pullProcessMemoryState(atomTag, data), + BackgroundThread.getExecutor() + ); } - private void pullProcessMemoryState() { - // No op. + private int pullProcessMemoryState(int atomTag, List<StatsEvent> pulledData) { + List<ProcessMemoryState> processMemoryStates = + LocalServices.getService(ActivityManagerInternal.class) + .getMemoryStateForProcesses(); + for (ProcessMemoryState processMemoryState : processMemoryStates) { + final MemoryStat memoryStat = readMemoryStatFromFilesystem(processMemoryState.uid, + processMemoryState.pid); + if (memoryStat == null) { + continue; + } + StatsEvent e = StatsEvent.newBuilder() + .setAtomId(atomTag) + .writeInt(processMemoryState.uid) + .writeString(processMemoryState.processName) + .writeInt(processMemoryState.oomScore) + .writeLong(memoryStat.pgfault) + .writeLong(memoryStat.pgmajfault) + .writeLong(memoryStat.rssInBytes) + .writeLong(memoryStat.cacheInBytes) + .writeLong(memoryStat.swapInBytes) + .writeLong(-1) // unused + .writeLong(-1) // unused + .writeInt(-1) // unused + .build(); + pulledData.add(e); + } + return StatsManager.PULL_SUCCESS; + } + + /** + * Which native processes to snapshot memory for. + * + * <p>Processes are matched by their cmdline in procfs. Example: cat /proc/pid/cmdline returns + * /system/bin/statsd for the stats daemon. + */ + private static final Set<String> MEMORY_INTERESTING_NATIVE_PROCESSES = Sets.newHashSet( + "/system/bin/statsd", // Stats daemon. + "/system/bin/surfaceflinger", + "/system/bin/apexd", // APEX daemon. + "/system/bin/audioserver", + "/system/bin/cameraserver", + "/system/bin/drmserver", + "/system/bin/healthd", + "/system/bin/incidentd", + "/system/bin/installd", + "/system/bin/lmkd", // Low memory killer daemon. + "/system/bin/logd", + "media.codec", + "media.extractor", + "media.metrics", + "/system/bin/mediadrmserver", + "/system/bin/mediaserver", + "/system/bin/performanced", + "/system/bin/tombstoned", + "/system/bin/traced", // Perfetto. + "/system/bin/traced_probes", // Perfetto. + "webview_zygote", + "zygote", + "zygote64"); + + /** + * Lowest available uid for apps. + * + * <p>Used to quickly discard memory snapshots of the zygote forks from native process + * measurements. + */ + private static final int MIN_APP_UID = 10_000; + + private static boolean isAppUid(int uid) { + return uid >= MIN_APP_UID; } private void registerProcessMemoryHighWaterMark() { - // No op. + int tagId = StatsLog.PROCESS_MEMORY_HIGH_WATER_MARK; + mStatsManager.registerPullAtomCallback( + tagId, + null, // use default PullAtomMetadata values + (atomTag, data) -> pullProcessMemoryHighWaterMark(atomTag, data), + BackgroundThread.getExecutor() + ); } - private void pullProcessMemoryHighWaterMark() { - // No op. + private int pullProcessMemoryHighWaterMark(int atomTag, List<StatsEvent> pulledData) { + List<ProcessMemoryState> managedProcessList = + LocalServices.getService(ActivityManagerInternal.class) + .getMemoryStateForProcesses(); + for (ProcessMemoryState managedProcess : managedProcessList) { + final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(managedProcess.pid); + if (snapshot == null) { + continue; + } + StatsEvent e = StatsEvent.newBuilder() + .setAtomId(atomTag) + .writeInt(managedProcess.uid) + .writeString(managedProcess.processName) + // RSS high-water mark in bytes. + .writeLong(snapshot.rssHighWaterMarkInKilobytes * 1024L) + .writeInt(snapshot.rssHighWaterMarkInKilobytes) + .build(); + pulledData.add(e); + } + forEachPid((pid, cmdLine) -> { + if (!MEMORY_INTERESTING_NATIVE_PROCESSES.contains(cmdLine)) { + return; + } + final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(pid); + if (snapshot == null) { + return; + } + // Sometimes we get here a process that is not included in the whitelist. It comes + // from forking the zygote for an app. We can ignore that sample because this process + // is collected by ProcessMemoryState. + if (isAppUid(snapshot.uid)) { + return; + } + StatsEvent e = StatsEvent.newBuilder() + .setAtomId(atomTag) + .writeInt(snapshot.uid) + .writeString(cmdLine) + // RSS high-water mark in bytes. + .writeLong(snapshot.rssHighWaterMarkInKilobytes * 1024L) + .writeInt(snapshot.rssHighWaterMarkInKilobytes) + .build(); + pulledData.add(e); + }); + // Invoke rss_hwm_reset binary to reset RSS HWM counters for all processes. + SystemProperties.set("sys.rss_hwm_reset.on", "1"); + return StatsManager.PULL_SUCCESS; } private void registerProcessMemorySnapshot() { - // No op. + int tagId = StatsLog.PROCESS_MEMORY_SNAPSHOT; + mStatsManager.registerPullAtomCallback( + tagId, + null, // use default PullAtomMetadata values + (atomTag, data) -> pullProcessMemorySnapshot(atomTag, data), + BackgroundThread.getExecutor() + ); } - private void pullProcessMemorySnapshot() { - // No op. + private int pullProcessMemorySnapshot(int atomTag, List<StatsEvent> pulledData) { + List<ProcessMemoryState> managedProcessList = + LocalServices.getService(ActivityManagerInternal.class) + .getMemoryStateForProcesses(); + for (ProcessMemoryState managedProcess : managedProcessList) { + final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(managedProcess.pid); + if (snapshot == null) { + continue; + } + StatsEvent e = StatsEvent.newBuilder() + .writeInt(managedProcess.uid) + .writeString(managedProcess.processName) + .writeInt(managedProcess.pid) + .writeInt(managedProcess.oomScore) + .writeInt(snapshot.rssInKilobytes) + .writeInt(snapshot.anonRssInKilobytes) + .writeInt(snapshot.swapInKilobytes) + .writeInt(snapshot.anonRssInKilobytes + snapshot.swapInKilobytes) + .build(); + pulledData.add(e); + } + forEachPid((pid, cmdLine) -> { + if (!MEMORY_INTERESTING_NATIVE_PROCESSES.contains(cmdLine)) { + return; + } + final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(pid); + if (snapshot == null) { + return; + } + // Sometimes we get here a process that is not included in the whitelist. It comes + // from forking the zygote for an app. We can ignore that sample because this process + // is collected by ProcessMemoryState. + if (isAppUid(snapshot.uid)) { + return; + } + StatsEvent e = StatsEvent.newBuilder() + .setAtomId(atomTag) + .writeInt(snapshot.uid) + .writeString(cmdLine) + .writeInt(pid) + .writeInt(-1001) // Placeholder for native processes, OOM_SCORE_ADJ_MIN - 1. + .writeInt(snapshot.rssInKilobytes) + .writeInt(snapshot.anonRssInKilobytes) + .writeInt(snapshot.swapInKilobytes) + .writeInt(snapshot.anonRssInKilobytes + snapshot.swapInKilobytes) + .build(); + pulledData.add(e); + }); + return StatsManager.PULL_SUCCESS; } private void registerSystemIonHeapSize() { - // No op. + int tagId = StatsLog.SYSTEM_ION_HEAP_SIZE; + mStatsManager.registerPullAtomCallback( + tagId, + null, // use default PullAtomMetadata values + (atomTag, data) -> pullSystemIonHeapSize(atomTag, data), + BackgroundThread.getExecutor() + ); } - private void pullSystemIonHeapSize() { - // No op. + private int pullSystemIonHeapSize(int atomTag, List<StatsEvent> pulledData) { + final long systemIonHeapSizeInBytes = readSystemIonHeapSizeFromDebugfs(); + StatsEvent e = StatsEvent.newBuilder() + .setAtomId(atomTag) + .writeLong(systemIonHeapSizeInBytes) + .build(); + pulledData.add(e); + return StatsManager.PULL_SUCCESS; } private void registerIonHeapSize() { @@ -1056,43 +1248,182 @@ public class StatsPullAtomService extends SystemService { } private void registerProcessSystemIonHeapSize() { - // No op. + int tagId = StatsLog.PROCESS_SYSTEM_ION_HEAP_SIZE; + mStatsManager.registerPullAtomCallback( + tagId, + null, // use default PullAtomMetadata values + (atomTag, data) -> pullProcessSystemIonHeapSize(atomTag, data), + BackgroundThread.getExecutor() + ); } - private void pullProcessSystemIonHeapSize() { - // No op. + private int pullProcessSystemIonHeapSize(int atomTag, List<StatsEvent> pulledData) { + List<IonAllocations> result = readProcessSystemIonHeapSizesFromDebugfs(); + for (IonAllocations allocations : result) { + StatsEvent e = StatsEvent.newBuilder() + .setAtomId(atomTag) + .writeInt(getUidForPid(allocations.pid)) + .writeString(readCmdlineFromProcfs(allocations.pid)) + .writeInt((int) (allocations.totalSizeInBytes / 1024)) + .writeInt(allocations.count) + .writeInt((int) (allocations.maxSizeInBytes / 1024)) + .build(); + pulledData.add(e); + } + return StatsManager.PULL_SUCCESS; } private void registerTemperature() { - // No op. + int tagId = StatsLog.TEMPERATURE; + mStatsManager.registerPullAtomCallback( + tagId, + null, // use default PullAtomMetadata values + (atomTag, data) -> pullTemperature(atomTag, data), + BackgroundThread.getExecutor() + ); } - private void pullTemperature() { - // No op. + private int pullTemperature(int atomTag, List<StatsEvent> pulledData) { + IThermalService thermalService = getIThermalService(); + if (thermalService == null) { + return StatsManager.PULL_SKIP; + } + final long callingToken = Binder.clearCallingIdentity(); + try { + List<Temperature> temperatures = thermalService.getCurrentTemperatures(); + for (Temperature temp : temperatures) { + StatsEvent e = StatsEvent.newBuilder() + .setAtomId(atomTag) + .writeInt(temp.getType()) + .writeString(temp.getName()) + .writeInt((int) (temp.getValue() * 10)) + .writeInt(temp.getStatus()) + .build(); + pulledData.add(e); + } + } catch (RemoteException e) { + // Should not happen. + Slog.e(TAG, "Disconnected from thermal service. Cannot pull temperatures."); + return StatsManager.PULL_SKIP; + } finally { + Binder.restoreCallingIdentity(callingToken); + } + return StatsManager.PULL_SUCCESS; } private void registerCoolingDevice() { - // No op. + int tagId = StatsLog.COOLING_DEVICE; + mStatsManager.registerPullAtomCallback( + tagId, + null, // use default PullAtomMetadata values + (atomTag, data) -> pullCooldownDevice(atomTag, data), + BackgroundThread.getExecutor() + ); } - private void pullCooldownDevice() { - // No op. + private int pullCooldownDevice(int atomTag, List<StatsEvent> pulledData) { + IThermalService thermalService = getIThermalService(); + if (thermalService == null) { + return StatsManager.PULL_SKIP; + } + final long callingToken = Binder.clearCallingIdentity(); + try { + List<CoolingDevice> devices = thermalService.getCurrentCoolingDevices(); + for (CoolingDevice device : devices) { + StatsEvent e = StatsEvent.newBuilder() + .setAtomId(atomTag) + .writeInt(device.getType()) + .writeString(device.getName()) + .writeInt((int) (device.getValue())) + .build(); + pulledData.add(e); + } + } catch (RemoteException e) { + // Should not happen. + Slog.e(TAG, "Disconnected from thermal service. Cannot pull temperatures."); + return StatsManager.PULL_SKIP; + } finally { + Binder.restoreCallingIdentity(callingToken); + } + return StatsManager.PULL_SUCCESS; } - private void registerBinderCalls() { - // No op. + private void registerBinderCallsStats() { + int tagId = StatsLog.BINDER_CALLS; + PullAtomMetadata metadata = PullAtomMetadata.newBuilder() + .setAdditiveFields(new int[] {4, 5, 6, 8, 12}) + .build(); + mStatsManager.registerPullAtomCallback( + tagId, + metadata, + (atomTag, data) -> pullBinderCallsStats(atomTag, data), + BackgroundThread.getExecutor() + ); } - private void pullBinderCalls() { - // No op. + private int pullBinderCallsStats(int atomTag, List<StatsEvent> pulledData) { + BinderCallsStatsService.Internal binderStats = + LocalServices.getService(BinderCallsStatsService.Internal.class); + if (binderStats == null) { + Slog.e(TAG, "failed to get binderStats"); + return StatsManager.PULL_SKIP; + } + + List<ExportedCallStat> callStats = binderStats.getExportedCallStats(); + binderStats.reset(); + for (ExportedCallStat callStat : callStats) { + StatsEvent e = StatsEvent.newBuilder() + .setAtomId(atomTag) + .writeInt(callStat.workSourceUid) + .writeString(callStat.className) + .writeString(callStat.methodName) + .writeLong(callStat.callCount) + .writeLong(callStat.exceptionCount) + .writeLong(callStat.latencyMicros) + .writeLong(callStat.maxLatencyMicros) + .writeLong(callStat.cpuTimeMicros) + .writeLong(callStat.maxCpuTimeMicros) + .writeLong(callStat.maxReplySizeBytes) + .writeLong(callStat.maxRequestSizeBytes) + .writeLong(callStat.recordedCallCount) + .writeInt(callStat.screenInteractive ? 1 : 0) + .writeInt(callStat.callingUid) + .build(); + pulledData.add(e); + } + return StatsManager.PULL_SUCCESS; } - private void registerBinderCallsExceptions() { - // No op. + private void registerBinderCallsStatsExceptions() { + int tagId = StatsLog.BINDER_CALLS_EXCEPTIONS; + mStatsManager.registerPullAtomCallback( + tagId, + null, // use default PullAtomMetadata values + (atomTag, data) -> pullBinderCallsStatsExceptions(atomTag, data), + BackgroundThread.getExecutor() + ); } - private void pullBinderCallsExceptions() { - // No op. + private int pullBinderCallsStatsExceptions(int atomTag, List<StatsEvent> pulledData) { + BinderCallsStatsService.Internal binderStats = + LocalServices.getService(BinderCallsStatsService.Internal.class); + if (binderStats == null) { + Slog.e(TAG, "failed to get binderStats"); + return StatsManager.PULL_SKIP; + } + + ArrayMap<String, Integer> exceptionStats = binderStats.getExportedExceptionStats(); + // TODO: decouple binder calls exceptions with the rest of the binder calls data so that we + // can reset the exception stats. + for (Map.Entry<String, Integer> entry : exceptionStats.entrySet()) { + StatsEvent e = StatsEvent.newBuilder() + .setAtomId(atomTag) + .writeString(entry.getKey()) + .writeInt(entry.getValue()) + .build(); + pulledData.add(e); + } + return StatsManager.PULL_SUCCESS; } private void registerLooperStats() { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 3dee913ac035..109a6fd528b8 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -218,7 +218,7 @@ public final class SystemServer { private static final String STATS_COMPANION_LIFECYCLE_CLASS = "com.android.server.stats.StatsCompanion$Lifecycle"; private static final String STATS_PULL_ATOM_SERVICE_CLASS = - "com.android.server.stats.StatsPullAtomService"; + "com.android.server.stats.pull.StatsPullAtomService"; private static final String USB_SERVICE_CLASS = "com.android.server.usb.UsbService$Lifecycle"; private static final String MIDI_SERVICE_CLASS = diff --git a/services/tests/servicestests/src/com/android/server/stats/IonMemoryUtilTest.java b/services/tests/servicestests/src/com/android/server/stats/pull/IonMemoryUtilTest.java index 8cbf8e56edeb..d4d4b4d6a8c9 100644 --- a/services/tests/servicestests/src/com/android/server/stats/IonMemoryUtilTest.java +++ b/services/tests/servicestests/src/com/android/server/stats/pull/IonMemoryUtilTest.java @@ -13,16 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.server.stats; +package com.android.server.stats.pull; -import static com.android.server.stats.IonMemoryUtil.parseIonHeapSizeFromDebugfs; -import static com.android.server.stats.IonMemoryUtil.parseProcessIonHeapSizesFromDebugfs; +import static com.android.server.stats.pull.IonMemoryUtil.parseIonHeapSizeFromDebugfs; +import static com.android.server.stats.pull.IonMemoryUtil.parseProcessIonHeapSizesFromDebugfs; import static com.google.common.truth.Truth.assertThat; import androidx.test.filters.SmallTest; -import com.android.server.stats.IonMemoryUtil.IonAllocations; +import com.android.server.stats.pull.IonMemoryUtil.IonAllocations; import org.junit.Test; |