• GTS 中testPersistentProcessMemory fail 详解


    0. 前言

    GTS 在测试 case armeabi-v7a GtsMemoryTestCases 的时候出现下面异常,本文总结一下。

    com.google.android.memory.gts.MemoryTest#testPersistentProcessMemory

    1. error log

    1. 09-14 09:41:40.523 10182 13340 13359 E TestRunner: failed: testPersistentProcessMemory(com.google.android.memory.gts.MemoryTest)
    2. 09-14 09:41:40.523 10182 13340 13359 E TestRunner: ----- begin exception -----
    3. 09-14 09:41:40.525 10182 13340 13359 E TestRunner: java.lang.AssertionError: memory usage for persistent processes is too high: 140867 > 133120
    4. 09-14 09:41:40.525 10182 13340 13359 E TestRunner: at org.junit.Assert.fail(Assert.java:89)
    5. 09-14 09:41:40.525 10182 13340 13359 E TestRunner: at org.junit.Assert.assertTrue(Assert.java:42)
    6. 09-14 09:41:40.525 10182 13340 13359 E TestRunner: at com.google.android.memory.gts.MemoryTest.testPersistentProcessMemory(MemoryTest.java:75)
    7. 09-14 09:41:40.525 10182 13340 13359 E TestRunner: at java.lang.reflect.Method.invoke(Native Method)
    8. 09-14 09:41:40.525 10182 13340 13359 E TestRunner: at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
    9. 09-14 09:41:40.525 10182 13340 13359 E TestRunner: at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    10. 09-14 09:41:40.525 10182 13340 13359 E TestRunner: at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:61)
    11. 09-14 09:41:40.525 10182 13340 13359 E TestRunner: at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    12. 09-14 09:41:40.525 10182 13340 13359 E TestRunner: at org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:148)
    13. 09-14 09:41:40.525 10182 13340 13359 E TestRunner: at org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:142)
    14. 09-14 09:41:40.525 10182 13340 13359 E TestRunner: at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    15. 09-14 09:41:40.525 10182 13340 13359 E TestRunner: at java.lang.Thread.run(Thread.java:923)
    16. 09-14 09:41:40.525 10182 13340 13359 E TestRunner: ----- end exception -----
    17. 09-14 09:41:40.530 10182 13340 13359 I TestRunner: finished: testPersistentProcessMemory(com.google.android.memory.gts.MemoryTest)

    从log 上来看,出现了 persistent processes 使用的memory 太高了,达到了140867Kb ,而GTS 测试允许的 persistent processes memory 为 133120Kb。

    E TestRunner: java.lang.AssertionError: memory usage for persistent processes is too high: 140867 > 133120

    2. source code

    同其他的GTS 测试,找到对应的测试case,将其反编译之后就可以查看源码: 

    1. package com.google.android.memory.gts;
    2. import android.app.ActivityManager;
    3. import androidx.test.InstrumentationRegistry;
    4. import androidx.test.runner.AndroidJUnit4;
    5. import com.android.compatibility.common.util.DynamicConfigDeviceSide;
    6. import com.android.compatibility.common.util.SystemUtil;
    7. import com.android.xts.common.util.GmsUtil;
    8. import java.util.ArrayList;
    9. import java.util.regex.Matcher;
    10. import java.util.regex.Pattern;
    11. import org.junit.Assert;
    12. import org.junit.Assume;
    13. import org.junit.Before;
    14. import org.junit.Test;
    15. import org.junit.runner.RunWith;
    16. @RunWith(AndroidJUnit4.class)
    17. public class MemoryTest {
    18. private static final Pattern DEVICE_HEIGHT_PATTERN = Pattern.compile("deviceHeight=(\\d+)");
    19. private static final Pattern DEVICE_WIDTH_PATTERN = Pattern.compile("deviceWidth=(\\d+)");
    20. private static final String DUMPSYS_DISPLAY = "dumpsys display";
    21. private static final String DUMPSYS_MEMINFO_CMD = "dumpsys -t 30 meminfo";
    22. private static final String MEMORY_USAGE_HIGH_MSG = "memory usage for persistent processes is too high: %d > %d";
    23. private static final long ONE_MEGABYTE = 1048576;
    24. private static final String PERSISTENT_MEMORY_KEY_FORMAT = "max_memory_persistent_%s_%s";
    25. private static final String PERSISTENT_MEMORY_REGEX = "(?=([\\d,]+)K: Persistent)(?!.*Service).*";
    26. private ActivityManager mActivityManager;
    27. @Before
    28. public void checkGoDevice() {
    29. Assume.assumeTrue("Skipping MemoryTest on non-Go device", GmsUtil.isGoDevice());
    30. this.mActivityManager = (ActivityManager) InstrumentationRegistry.getTargetContext().getSystemService(ActivityManager.class);
    31. }
    32. @Test
    33. public void testPersistentProcessMemory() throws Exception {
    34. long memoryKb = calculatePersistentMemoryUsage();
    35. long maxMemoryKb = getMaxPersistentMemoryAllowed();
    36. boolean z = false;
    37. String format = String.format(MEMORY_USAGE_HIGH_MSG, new Object[]{Long.valueOf(memoryKb), Long.valueOf(maxMemoryKb)});
    38. if (memoryKb < maxMemoryKb) {
    39. z = true;
    40. }
    41. Assert.assertTrue(format, z);
    42. }
    43. private long calculatePersistentMemoryUsage() throws Exception {
    44. String memoryUsage = findMatch(PERSISTENT_MEMORY_REGEX, SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(), DUMPSYS_MEMINFO_CMD));
    45. Assert.assertNotNull("Could not get meminfo total", memoryUsage);
    46. return Long.valueOf(memoryUsage.replaceAll("[^0-9]", "")).longValue();
    47. }
    48. private long getMaxPersistentMemoryAllowed() throws Exception {
    49. return getLongFromConfig(keyForDeviceBasedOnMemoryAndScreenLayoutSize());
    50. }
    51. private String findMatch(String regex, String input) {
    52. Matcher matcher = Pattern.compile(regex).matcher(input);
    53. ArrayList arrayList = new ArrayList();
    54. while (matcher.find()) {
    55. arrayList.add(matcher.group(0));
    56. }
    57. if (arrayList.isEmpty()) {
    58. return null;
    59. }
    60. return (String) (arrayList.size() > 1 ? arrayList.get(1) : arrayList.get(0));
    61. }
    62. private long getLongFromConfig(String key) throws Exception {
    63. DynamicConfigDeviceSide dcds = new DynamicConfigDeviceSide("GtsMemoryTestCases");
    64. Assert.assertNotNull("Unable to get key from config: " + key, dcds.getValue(key));
    65. return new Long(dcds.getValue(key)).longValue();
    66. }
    67. private String keyForDeviceBasedOnMemoryAndScreenLayoutSize() throws Exception {
    68. return String.format(PERSISTENT_MEMORY_KEY_FORMAT, new Object[]{memoryClass(), calculateScreenLayoutSize()});
    69. }
    70. private String memoryClass() throws Exception {
    71. ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
    72. this.mActivityManager.getMemoryInfo(memoryInfo);
    73. long totalMemoryBytes = memoryInfo.totalMem;
    74. if (totalMemoryBytes <= 536870912) {
    75. return "512";
    76. }
    77. if (totalMemoryBytes <= 1073741824) {
    78. return "1gb";
    79. }
    80. return "2gb";
    81. }
    82. private String calculateScreenLayoutSize() throws Exception {
    83. Matcher matcher = DEVICE_WIDTH_PATTERN.matcher(SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(), DUMPSYS_DISPLAY));
    84. Assert.assertTrue("deviceWidth not found", matcher.find());
    85. long deviceWidth = Long.valueOf(matcher.group(1)).longValue();
    86. matcher.usePattern(DEVICE_HEIGHT_PATTERN);
    87. Assert.assertTrue("deviceHeight not found", matcher.find());
    88. long deviceHeight = Long.valueOf(matcher.group(1)).longValue();
    89. long shortSide = Math.min(deviceWidth, deviceHeight);
    90. long longSide = Math.max(deviceWidth, deviceHeight);
    91. if (shortSide <= 480 && longSide <= 640) {
    92. return "vga";
    93. }
    94. if (shortSide <= 480 && longSide <= 854) {
    95. return "wvga";
    96. }
    97. if (shortSide > 540 || longSide > 960) {
    98. return "hd";
    99. }
    100. return "qhd";
    101. }
    102. }

    进入测试函数 testPersistentProcessMemory():

    • 首先通过 calculatePersistentMemoryUsage() 函数确定经过 dupmsys -t 30 meminfo 之后所有 Persistent 进程的内存,存放在变量 memoryKb 中。
    • 接着通过 getMaxPersistentMemoryAllowed() 函数,确定 GTS 允许的最大 persistent memory,存放在变量 maxMemoryKb中。
      • 主要是解析 GtsMemoryTestCases.dynamic 文件中的某一个属性值;
      • 该dynamic 中属性 key 通过函数 keyForDeviceBasedOnMemoryAndScreenLayoutSize() 获取;
      • 从 log 来看,显然解析的是 max_memory_persistent_2gb_hd 属性的值 133120
    • GTS 要求,memoryKb 不能大于等于 maxMemroyKb;

    另外,需要注意的是memoryKb 是通过 Java 的Pattern 类进行正则表达式匹配:

    private static final String PERSISTENT_MEMORY_REGEX = "(?=([\\d,]+)K: Persistent)(?!.*Service).*";

    应该就是匹配 dumpsys meminfo 中带有 Persistent 的一行,但不包括Persistent Service 这一行。例如,

        261,364K: Persistent

    但不统计:

         26,620K: Persistent Service

    2.1 GtsMemroyTestCases.synamic

    1. <dynamicConfig>
    2. <entry key="max_memory_persistent">
    3. <value>90000value>
    4. entry>
    5. <entry key="max_memory_persistent_512_vga">
    6. <value>81920value>
    7. entry>
    8. <entry key="max_memory_persistent_512_wvga">
    9. <value>87040value>
    10. entry>
    11. <entry key="max_memory_persistent_1gb_vga">
    12. <value>87040value>
    13. entry>
    14. <entry key="max_memory_persistent_1gb_wvga">
    15. <value>92160value>
    16. entry>
    17. <entry key="max_memory_persistent_1gb_qhd">
    18. <value>97280value>
    19. entry>
    20. <entry key="max_memory_persistent_1gb_hd">
    21. <value>102400value>
    22. entry>
    23. <entry key="max_memory_persistent_2gb_vga">
    24. <value>102400value>
    25. entry>
    26. <entry key="max_memory_persistent_2gb_wvga">
    27. <value>112640value>
    28. entry>
    29. <entry key="max_memory_persistent_2gb_qhd">
    30. <value>122880value>
    31. entry>
    32. <entry key="max_memory_persistent_2gb_hd">
    33. <value>133120value>
    34. entry>
    35. dynamicConfig>

    代码中会通过 dumpsys display 解析设备的 width 和 height:

      mViewports=[DisplayViewport{type=INTERNAL, valid=true, isActive=false, displayId=0, uniqueId='local:0', physicalPort=0, orientation=0, logicalFrame=Rect(0, 0 - 720, 1650), physicalFrame=Rect(0, 0 - 720, 1650), deviceWidth=720, deviceHeight=1650}]

    在函数 calculateScreenLayoutSiz() 中确定 layout size

    3. 解决方案

    dumpsys meminfo,确认 persistent 进程的内存使用,要求不要超过 GTS 设置的max 值

    另外,在case 调用最开始会确认是否为 GO device:

    1. public void checkGoDevice() {
    2. Assume.assumeTrue("Skipping MemoryTest on non-Go device", GmsUtil.isGoDevice());
    3. this.mActivityManager = (ActivityManager) InstrumentationRegistry.getTargetContext().getSystemService(ActivityManager.class);
    4. }

    该 case 只有在 GO device 下才会调用,而非 GO device,则会认为 ASSUMPTION_FAILURE 而跳过该 case,并在运行的时候打印:

    1. 9-22 10:57:49 I/ModuleListener: [1/1] caab02bd com.google.android.memory.gts.MemoryTest#testPersistentProcessMemory ASSUMPTION_FAILURE: org.junit.AssumptionViolatedException: Skipping MemoryTest on non-Go device
    2. at org.junit.Assume.assumeTrue(Assume.java:68)
    3. at com.google.android.memory.gts.MemoryTest.checkGoDevice(MemoryTest.java:62)
    4. at java.lang.reflect.Method.invoke(Native Method)
    5. at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
    6. at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    7. at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:61)
    8. at androidx.test.internal.runner.junit4.statement.RunBefores.evaluate(RunBefores.java:76)
    9. at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    10. at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
    11. at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
    12. at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
    13. at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
    14. at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
    15. at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
    16. at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
    17. at org.junit.runners.ParentRunner.-$$Nest$mrunChildren(Unknown Source:0)
    18. at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
    19. at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    20. at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
    21. at androidx.test.runner.AndroidJUnit4.run(AndroidJUnit4.java:111)
    22. at org.junit.runners.Suite.runChild(Suite.java:128)
    23. at org.junit.runners.Suite.runChild(Suite.java:27)
    24. at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
    25. at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
    26. at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
    27. at org.junit.runners.ParentRunner.-$$Nest$mrunChildren(Unknown Source:0)
    28. at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
    29. at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    30. at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
    31. at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    32. at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
    33. at androidx.test.internal.runner.TestExecutor.execute(TestExecutor.java:67)
    34. at androidx.test.internal.runner.TestExecutor.execute(TestExecutor.java:58)
    35. at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:445)
    36. at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2205)

     

     

    参考:

    https://blog.csdn.net/yaomingyang/article/details/79175333

  • 相关阅读:
    基于GoLang实现API短信网关
    本地 Android repo 仓库迁移、恢复源码树
    c++迭代器STL中的vector简单概述
    贾扬清开源 AI 框架 Caffe | 开源英雄
    VMware中安装centos无网络,配置教程
    java运算符
    医学图像数据增强-重采样itk
    【python基础】复杂数据类型-字典(遍历)
    Element的MessageBox自定义图标
    @AspectJ注解配置切面编程(注解方式)
  • 原文地址:https://blog.csdn.net/jingerppp/article/details/132882587