blob: 174571de1e4cfcf8b6e8fc9ea0d927bfcc206f5b [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.am;
import static com.android.server.am.MemoryStatUtil.BYTES_IN_KILOBYTE;
import static com.android.server.am.MemoryStatUtil.JIFFY_NANOS;
import static com.android.server.am.MemoryStatUtil.MemoryStat;
import static com.android.server.am.MemoryStatUtil.parseCmdlineFromProcfs;
import static com.android.server.am.MemoryStatUtil.parseIonHeapSizeFromDebugfs;
import static com.android.server.am.MemoryStatUtil.parseMemoryStatFromMemcg;
import static com.android.server.am.MemoryStatUtil.parseMemoryStatFromProcfs;
import static com.android.server.am.MemoryStatUtil.parseVmHWMFromProcfs;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import androidx.test.filters.SmallTest;
import org.junit.Test;
import java.io.ByteArrayOutputStream;
import java.util.Collections;
/**
* Build/Install/Run:
* atest FrameworksServicesTests:MemoryStatUtilTest
*/
@SmallTest
public class MemoryStatUtilTest {
private static final String MEMORY_STAT_CONTENTS = String.join(
"\n",
"cache 96", // keep different from total_cache to catch reading wrong value
"rss 97", // keep different from total_rss to catch reading wrong value
"rss_huge 0",
"mapped_file 524288",
"writeback 0",
"swap 95", // keep different from total_rss to catch reading wrong value
"pgpgin 16717",
"pgpgout 5037",
"pgfault 99", // keep different from total_pgfault to catch reading wrong value
"pgmajfault 98", // keep different from total_pgmajfault to catch reading wrong value
"inactive_anon 503808",
"active_anon 46309376",
"inactive_file 876544",
"active_file 81920",
"unevictable 0",
"hierarchical_memory_limit 18446744073709551615",
"hierarchical_memsw_limit 18446744073709551615",
"total_cache 4",
"total_rss 3",
"total_rss_huge 0",
"total_mapped_file 524288",
"total_writeback 0",
"total_swap 5",
"total_pgpgin 16717",
"total_pgpgout 5037",
"total_pgfault 1",
"total_pgmajfault 2",
"total_inactive_anon 503808",
"total_active_anon 46309376",
"total_inactive_file 876544",
"total_active_file 81920",
"total_unevictable 0");
private static final String PROC_STAT_CONTENTS = String.join(
" ",
"1040",
"(system_server)",
"S",
"544",
"544",
"0",
"0",
"-1",
"1077936448",
"1", // this is pgfault
"0",
"2", // this is pgmajfault
"0",
"44533",
"13471",
"0",
"0",
"18",
"-2",
"117",
"0",
"2222", // this in start time (in ticks per second)
"1257177088",
"3",
"4294967295",
"2936971264",
"2936991289",
"3198888320",
"3198879848",
"2903927664",
"0",
"4612",
"0",
"1073775864",
"4294967295",
"0",
"0",
"17",
"0",
"0",
"0",
"0",
"0",
"0",
"2936999088",
"2936999936",
"2958692352",
"3198888595",
"3198888671",
"3198888671",
"3198889956",
"0");
private static final String PROC_STATUS_CONTENTS = "Name:\tandroid.youtube\n"
+ "State:\tS (sleeping)\n"
+ "Tgid:\t12088\n"
+ "Pid:\t12088\n"
+ "PPid:\t723\n"
+ "TracerPid:\t0\n"
+ "Uid:\t10083\t10083\t10083\t10083\n"
+ "Gid:\t10083\t10083\t10083\t10083\n"
+ "Ngid:\t0\n"
+ "FDSize:\t128\n"
+ "Groups:\t3003 9997 20083 50083 \n"
+ "VmPeak:\t 4546844 kB\n"
+ "VmSize:\t 4542636 kB\n"
+ "VmLck:\t 0 kB\n"
+ "VmPin:\t 0 kB\n"
+ "VmHWM:\t 137668 kB\n" // RSS high-water mark
+ "VmRSS:\t 126776 kB\n" // RSS
+ "RssAnon:\t 37860 kB\n"
+ "RssFile:\t 88764 kB\n"
+ "RssShmem:\t 152 kB\n"
+ "VmData:\t 4125112 kB\n"
+ "VmStk:\t 8192 kB\n"
+ "VmExe:\t 24 kB\n"
+ "VmLib:\t 102432 kB\n"
+ "VmPTE:\t 1300 kB\n"
+ "VmPMD:\t 36 kB\n"
+ "VmSwap:\t 22 kB\n" // Swap
+ "Threads:\t95\n"
+ "SigQ:\t0/13641\n"
+ "SigPnd:\t0000000000000000\n"
+ "ShdPnd:\t0000000000000000\n"
+ "SigBlk:\t0000000000001204\n"
+ "SigIgn:\t0000000000000001\n"
+ "SigCgt:\t00000006400084f8\n"
+ "CapInh:\t0000000000000000\n"
+ "CapPrm:\t0000000000000000\n"
+ "CapEff:\t0000000000000000\n"
+ "CapBnd:\t0000000000000000\n"
+ "CapAmb:\t0000000000000000\n"
+ "Seccomp:\t2\n"
+ "Cpus_allowed:\tff\n"
+ "Cpus_allowed_list:\t0-7\n"
+ "Mems_allowed:\t1\n"
+ "Mems_allowed_list:\t0\n"
+ "voluntary_ctxt_switches:\t903\n"
+ "nonvoluntary_ctxt_switches:\t104\n";
private static final String DEBUG_SYSTEM_ION_HEAP_CONTENTS = String.join(
" client pid size\n",
"----------------------------------------------------\n",
" audio@2.0-servi 765 4096\n",
" audio@2.0-servi 765 61440\n",
" audio@2.0-servi 765 4096\n",
" voip_client 96 8192\n",
" voip_client 96 4096\n",
" system_server 1232 16728064\n",
" surfaceflinger 611 50642944\n",
"----------------------------------------------------\n",
"orphaned allocations (info is from last known client):\n",
"----------------------------------------------------\n",
" total orphaned 0\n",
" total 55193600\n",
" deferred free 0\n",
"----------------------------------------------------\n",
"0 order 4 highmem pages in uncached pool = 0 total\n",
"0 order 4 lowmem pages in uncached pool = 0 total\n",
"1251 order 4 lowmem pages in cached pool = 81985536 total\n",
"VMID 8: 0 order 4 highmem pages in secure pool = 0 total\n",
"VMID 8: 0 order 4 lowmem pages in secure pool = 0 total\n",
"--------------------------------------------\n",
"uncached pool = 4096 cached pool = 83566592 secure pool = 0\n",
"pool total (uncached + cached + secure) = 83570688\n",
"--------------------------------------------\n");
@Test
public void testParseMemoryStatFromMemcg_parsesCorrectValues() {
MemoryStat stat = parseMemoryStatFromMemcg(MEMORY_STAT_CONTENTS);
assertEquals(1, stat.pgfault);
assertEquals(2, stat.pgmajfault);
assertEquals(3, stat.rssInBytes);
assertEquals(4, stat.cacheInBytes);
assertEquals(5, stat.swapInBytes);
}
@Test
public void testParseMemoryStatFromMemcg_emptyMemoryStatContents() {
MemoryStat stat = parseMemoryStatFromMemcg("");
assertNull(stat);
stat = parseMemoryStatFromMemcg(null);
assertNull(stat);
}
@Test
public void testParseMemoryStatFromProcfs_parsesCorrectValues() {
MemoryStat stat = parseMemoryStatFromProcfs(PROC_STAT_CONTENTS, PROC_STATUS_CONTENTS);
assertEquals(1, stat.pgfault);
assertEquals(2, stat.pgmajfault);
assertEquals(126776 * BYTES_IN_KILOBYTE, stat.rssInBytes);
assertEquals(0, stat.cacheInBytes);
assertEquals(22 * BYTES_IN_KILOBYTE, stat.swapInBytes);
assertEquals(2222 * JIFFY_NANOS, stat.startTimeNanos);
}
@Test
public void testParseMemoryStatFromProcfs_emptyContents() {
MemoryStat stat = parseMemoryStatFromProcfs("", PROC_STATUS_CONTENTS);
assertNull(stat);
stat = parseMemoryStatFromProcfs(null, PROC_STATUS_CONTENTS);
assertNull(stat);
stat = parseMemoryStatFromProcfs(PROC_STAT_CONTENTS, "");
assertNull(stat);
stat = parseMemoryStatFromProcfs(PROC_STAT_CONTENTS, null);
assertNull(stat);
}
@Test
public void testParseMemoryStatFromProcfs_invalidValue() {
String contents = String.join(" ", Collections.nCopies(24, "memory"));
assertNull(parseMemoryStatFromProcfs(contents, PROC_STATUS_CONTENTS));
}
@Test
public void testParseVmHWMFromProcfs_parsesCorrectValue() {
assertEquals(137668, parseVmHWMFromProcfs(PROC_STATUS_CONTENTS) / BYTES_IN_KILOBYTE);
}
@Test
public void testParseVmHWMFromProcfs_emptyContents() {
assertEquals(0, parseVmHWMFromProcfs(""));
assertEquals(0, parseVmHWMFromProcfs(null));
}
@Test
public void testParseCmdlineFromProcfs_invalidValue() {
byte[] nothing = new byte[] {0x00, 0x74, 0x65, 0x73, 0x74}; // \0test
assertEquals("", parseCmdlineFromProcfs(bytesToString(nothing)));
}
@Test
public void testParseCmdlineFromProcfs_correctValue_noNullBytes() {
assertEquals("com.google.app", parseCmdlineFromProcfs("com.google.app"));
}
@Test
public void testParseCmdlineFromProcfs_correctValue_withNullBytes() {
byte[] trailing = new byte[] {0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x00}; // test\0\0\0
assertEquals("test", parseCmdlineFromProcfs(bytesToString(trailing)));
// test\0\0test
byte[] inside = new byte[] {0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74};
assertEquals("test", parseCmdlineFromProcfs(bytesToString(trailing)));
}
@Test
public void testParseCmdlineFromProcfs_emptyContents() {
assertEquals("", parseCmdlineFromProcfs(""));
assertEquals("", parseCmdlineFromProcfs(null));
}
private static String bytesToString(byte[] bytes) {
ByteArrayOutputStream output = new ByteArrayOutputStream();
output.write(bytes, 0, bytes.length);
return output.toString();
}
@Test
public void testParseIonHeapSizeFromDebugfs_emptyContents() {
assertEquals(0, parseIonHeapSizeFromDebugfs(""));
assertEquals(0, parseIonHeapSizeFromDebugfs(null));
}
@Test
public void testParseIonHeapSizeFromDebugfs_invalidValue() {
assertEquals(0, parseIonHeapSizeFromDebugfs("<<no-value>>"));
assertEquals(0, parseIonHeapSizeFromDebugfs("\ntotal 12345678901234567890\n"));
}
@Test
public void testParseIonHeapSizeFromDebugfs_correctValue() {
assertEquals(55193600, parseIonHeapSizeFromDebugfs(DEBUG_SYSTEM_ION_HEAP_CONTENTS));
}
}