【问题描述】
使用安兔兔,AIDA64等apk检测时,部分数值不正确
【问题分析】
这里展开聊聊为什么检测出来的内部存储以及运行内存要比真实的要小
为什么应用中的内部存储总大小比物理内部存储小?
实际是16GB的机器,但是被检测出来的只有9025MB,可用的也只有8446MB。差异如此之大,肯定是APK的计算出了问题
使用指令查看内部存储,发现实际只计算了挂载/data路径的大小,并没有把系统空间计算进来
9242148 / 1024 = 9025.5
为什么应用中的总内存比物理内存小?
关系:
物理内存 >= memblock管理的内存 > 伙伴系统管理的内存
物理内存 = memblock管理的内存 + 预申请内存
memblock管理的内存 = 伙伴系统管理的内存 + reserverd内存(memblock的reserved type)
/proc/meminfo中的MemTotal相比物理内存少了两个部分:
- kernel进入前预申请的部分,此时memblock还未初始化。这部分的大小可以统计 /d/memblock/memory相对物理内存少的部分。
- kernel reserved的部分。这部分内存的大小可以统计/d/memblock/reserved中的各部分之和。
而APK检测出来的运行内存数值一般为/proc/meminfo 中的MemTotal,正是因为缺少了reserverd内存以及 预申请内存,所以显示比实际的物理内存要少。
//关系:4006912K(memblock管理的内存) = 3685040K + 297296K + 24576K //4006912K比起真正的4GB(4194304), 少了187392K,这部分就是预申请内存的大小 //3685040K 是此时 totalram_pages*4K 的大小, 也即memblcok管理的memory type部分 I/Memory ( 0): 3685040K/4006912K available (11702K kernel code, 878K rwdata, 2660K rodata, 640K init, 1807K bss, 297296K reserved, 24576K cma-reserved)
MemTotal: 3718748 kB
为什么开机时 totalram_pages的大小(上例中3685040K) 和 totalram_pages的大小(上例中3718748K) 开机后 不一致呢?
这是因为memblock管理的reserved type中部分内存在初始化完毕后释放了,添加到了伙伴系统(buddy system)中. 详细代码见free_initmem()
【修改对策】
虽说这个并不是系统的bug,但是改还是要改的,那么怎么通过修改系统源码实现更改无源码的第三方APK里的显示内容呢?
一开始我的思路其实是在StringBuilder中判断特定的字符串,但这个对策的弊端在于无法判断包名,如果其他应用也有用到相同的字符串,就可能会有意想不到的bug。
所以最终选择在TextView.java 中修改
public void append(CharSequence text, int start, int end) { if (!(mText instanceof Editable)) { setText(mText, BufferType.EDITABLE); } ((Editable) mText).append(text, start, end); if (mAutoLinkMask != 0) { boolean linksWereAdded = Linkify.addLinks(mSpannable, mAutoLinkMask); // Do not change the movement method for text that support text selection as it // would prevent an arbitrary cursor displacement. if (linksWereAdded && mLinksClickable && !textCanBeSelected()) { setMovementMethod(LinkMovementMethod.getInstance()); } } // Text_Replace start CharSequence typetext = getCustomText(mText); if (typetext != null) { setText(typetext, mBufferType); } // Text_Replace end } public final void setText(CharSequence text) { // Text_Replace start CharSequence typetext = getCustomText(text); if (typetext != null) { text = typetext; } // Text_Replace end setText(text, mBufferType); } private CharSequence getCustomText(CharSequence text) { if (text == null) { return null; } String packagename = mContext.getPackageName(); if (packagename.startsWith("com.antutu.ABenchMark") || packagename.startsWith("com.cpuid.cpu_z") || packagename.startsWith("com.abs.cpu_z_advance") || packagename.startsWith("com.finalwire.aida64")) { String typeText = text.toString(); if (typeText.contains("23.08")) { typeText = typeText.replace("23.08", "32.00"); } else if (typeText.contains("3631")) { typeText = typeText.replace("3631", "4096"); } return typeText; } return text; }
【参考文章】
Android内存占用分析 - 知乎