概述
1. memtrack hal层的作用
memtrack HAL(Memory Tracker HAL)是用来返回特定于设备的内存使用情况的信息。主要目标是能够跟踪无法以任何其他方式跟踪的内存,例如,由进程分配但未映射到该进程的地址空间的纹理内存。第二个目标是能够将进程使用的内存分类为GL,图形等。所有内存大小都必须是实际内存使用情况,统计计算的时候要考虑跨度,位深度,然后四舍五入到页面大小。
图片来自(侵删):https://blog.csdn.net/feelabclihu/article/details/105534175
2. dumpsys meminfo字段解析
执行dumpsys meminfo com.android.settings命令:
图片来自(侵删):https://blog.csdn.net/feelabclihu/article/details/105534175
A部分是进程内存的详细信息:
- A.1部分的信息是通过/proc/pid/smaps获得的
- A.2通过IPC(binder和pipe)方式获得
- A.3通过memtrack hal来获得的(下面源码解析的,就是这部分的内容)
B部分是对详细信息进行的总结
3. dumpsys meminfo的示例输出
Applications Memory Usage (in Kilobytes):
Uptime: 29569761 Realtime: 166986008
** MEMINFO in pid 13651 [com.android.settings] **
Pss Private Private Swap Rss Heap Heap Heap
Total Dirty Clean Dirty Total Size Alloc Free
------ ------ ------ ------ ------ ------ ------ ------
Native Heap 7488 7456 0 0 9220 9368 7537 1830
Dalvik Heap 4011 3936 0 0 6264 6140 3070 3070
Dalvik Other 740 412 0 0 1588
Stack 452 452 0 0 456
Ashmem 2 0 0 0 20
Other dev 56 0 56 0 272
.so mmap 1967 208 0 0 31368
.jar mmap 1876 0 68 0 27096
.apk mmap 13605 0 8052 0 45160
.ttf mmap 65 0 0 0 296
.dex mmap 657 16 636 0 792
.oat mmap 716 0 0 0 12872
.art mmap 2443 1948 8 0 15604
Other mmap 427 32 308 0 1848
Unknown 422 420 0 0 632
TOTAL 34927 14880 9128 0 34927 15508 10607 4900
App Summary
Pss(KB) Rss(KB)
------ ------
Java Heap: 5892 21868
Native Heap: 7456 9220
Code: 8980 118240
Stack: 452 456
Graphics: 0 0
Private Other: 1228
System: 10919
Unknown: 3704
TOTAL PSS: 34927 TOTAL RSS: 153488 TOTAL SWAP (KB): 0
Objects
Views: 145 ViewRootImpl: 1
AppContexts: 6 Activities: 1
Assets: 22 AssetManagers: 0
Local Binders: 40 Proxy Binders: 44
Parcel memory: 127 Parcel count: 52
Death Recipients: 2 OpenSSL Sockets: 0
WebViews: 0
SQL
MEMORY_USED: 0
PAGECACHE_OVERFLOW: 0 MALLOC_SIZE: 0
4. memtrack hal接口解析
4.1 函数接口
// 输入pid和MemtrackType,返回MemtrackRecord,flags计算的是这种类型:(uint32_t)MemtrackFlag::SMAPS_UNACCOUNTED)
MemtrackRecord[] getMemory(in int pid, in MemtrackType type);
// 返回GPU的信息,例如:
{ { 0, <gpu-device-name> },
{ 1, <gpu-device-name> } }
DeviceInfo[] getGpuDeviceInfo();
4.2 enum MemtrackType
enum MemtrackType {
OTHER = 0,
GL = 1,
GRAPHICS = 2,
MULTIMEDIA = 3,
CAMERA = 4,
}
4.3 parcelable MemtrackRecord
parcelable MemtrackRecord {
/* Memtrack Flags */
const int FLAG_SMAPS_ACCOUNTED = 1 << 1;
const int FLAG_SMAPS_UNACCOUNTED = 1 << 2; // 返回和计算的都是这个flags类型的内存
const int FLAG_SHARED = 1 << 3;
const int FLAG_SHARED_PSS = 1 << 4;
const int FLAG_PRIVATE = 1 << 5;
const int FLAG_SYSTEM = 1 << 6;
const int FLAG_DEDICATED = 1 << 7;
const int FLAG_NONSECURE = 1 << 8;
const int FLAG_SECURE = 1 << 9;
/* Bitfield indicating all flags that are valid for this record */
int flags;
long sizeInBytes;
}
源码解析
1. dumpsys meminfo
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
可以通过Android studio 单步调试来看dumpsys meminfo的执行流程
1.1 setSystemProcess-在AMS中注册meminfo服务
public void setSystemProcess() {
try {
ServiceManager.addService(Context.ACTIVITY_SERVICE, this, /* allowIsolated= */ true,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO);
ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
// 注册meminfo服务
ServiceManager.addService("meminfo", new MemBinder(this), /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_HIGH);
.........
}
1.2 MemBinder
static class MemBinder extends Binder {
ActivityManagerService mActivityManagerService;
private final PriorityDump.PriorityDumper mPriorityDumper =
new PriorityDump.PriorityDumper() {
@Override
// dumpsys --priority HIGH会执行这里,相当于执行dumpsys meminfo -a
public void dumpHigh(FileDescriptor fd, PrintWriter pw, String[] args,
boolean asProto) {
dump(fd, pw, new String[] {"-a"}, asProto);
}
@Override
// 执行dumpsys meminfo com.android.settings命令,会走到这里来
public void dump(FileDescriptor fd, PrintWriter pw, String[] args, boolean asProto) {
mActivityManagerService.dumpApplicationMemoryUsage(
fd, pw, " ", args, false, null, asProto);
}
};
MemBinder(ActivityManagerService activityManagerService) {
mActivityManagerService = activityManagerService;
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
try {
mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(false);
if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
"meminfo", pw)) return;
PriorityDump.dump(mPriorityDumper, fd, pw, args);
} finally {
mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(true);
}
}
}
1.3 dumpApplicationMemoryUsage-解析参数
final void dumpApplicationMemoryUsage(FileDescriptor fd, PrintWriter pw, String prefix,
String[] args, boolean brief, PrintWriter categoryPw, boolean asProto) {
MemoryUsageDumpOptions opts = new MemoryUsageDumpOptions();
.....
String[] innerArgs = new String[args.length-opti];
System.arraycopy(args, opti, innerArgs, 0, args.length-opti);
// procs = com.android.settings的ProcessRecord
ArrayList<ProcessRecord> procs = collectProcesses(pw, opti, opts.packages, args);
if (opts.dumpProto) {
dumpApplicationMemoryUsage(fd, opts, innerArgs, brief, procs);
} else {
// 会走这里
dumpApplicationMemoryUsage(fd, pw, prefix, opts, innerArgs, brief, procs, categoryPw);
}
}
1.4 dumpApplicationMemoryUsage-真正干活的
innerArgs = com.android.settings
uptime = 339996
realtime = 345991
procs = com.android.settings的ProcessRecord
private final void dumpApplicationMemoryUsage(FileDescriptor fd, PrintWriter pw, String prefix,
MemoryUsageDumpOptions opts, final String[] innerArgs, boolean brief,
ArrayList<ProcessRecord> procs, PrintWriter categoryPw) {
long uptime = SystemClock.uptimeMillis();
long realtime = SystemClock.elapsedRealtime();
final long[] tmpLong = new long[3];
// procs为null,所以不走这里
if (procs == null) {
.....
}
pw.println("No process found for: " + proc);
return;
}
if (!brief && !opts.oomOnly && (procs.size() == 1 || opts.isCheckinRequest || opts.packages)) {
opts.dumpDetails = true;
}
// numProcs = 1
// collectNative = false
final int numProcs = procs.size();
final boolean collectNative = !opts.isCheckinRequest && numProcs > 1 && !opts.packages;
if (collectNative) {
// If we are showing aggregations, also look for native processes to
// include so that our aggregations are more accurate.
updateCpuStatsNow();
}
// 打印头部
// Applications Memory Usage (in Kilobytes):
// Uptime: 1283027 Realtime: 1283027
dumpApplicationMemoryUsageHeader(pw, uptime, realtime, opts.isCheckinRequest, opts.isCompact);
ArrayList<MemItem> procMems = new ArrayList<MemItem>();
final SparseArray<MemItem> procMemsMap = new SparseArray<MemItem>();
final long[] ss = new long[INDEX_LAST];
long[] dalvikSubitemPss = opts.dumpDalvik ? new long[Debug.MemoryInfo.NUM_DVK_STATS] :
EmptyArray.LONG;
long[] dalvikSubitemSwapPss = opts.dumpDalvik ? new long[Debug.MemoryInfo.NUM_DVK_STATS] :
EmptyArray.LONG;
long[] dalvikSubitemRss = opts.dumpDalvik ? new long[Debug.MemoryInfo.NUM_DVK_STATS] :
EmptyArray.LONG;
long[] miscPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
long[] miscSwapPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
long[] miscRss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
long[] memtrackTmp = new long[4];
long oomPss[] = new long[DUMP_MEM_OOM_LABEL.length];
long oomSwapPss[] = new long[DUMP_MEM_OOM_LABEL.length];
long[] oomRss = new long[DUMP_MEM_OOM_LABEL.length];
ArrayList<MemItem>[] oomProcs = (ArrayList<MemItem>[])
new ArrayList[DUMP_MEM_OOM_LABEL.length];
long totalSwapPss = 0;
long totalRss = 0;
long cachedPss = 0;
long cachedSwapPss = 0;
boolean hasSwapPss = false;
Debug.MemoryInfo mi = null;
for (int i = numProcs - 1; i >= 0; i--) {
final ProcessRecord r = procs.get(i);
final IApplicationThread thread;
final int pid;
final int oomAdj;
final boolean hasActivities;
synchronized (mProcLock) {
thread = r.getThread();
pid = r.getPid();
oomAdj = r.mState.getSetAdjWithServices();
hasActivities = r.hasActivities();
}
if (thread != null) {
if (mi == null) {
mi = new Debug.MemoryInfo();
}
final int reportType;
final long startTime;
final long endTime;
long memtrackGraphics = 0;
long memtrackGl = 0;
if (opts.dumpDetails || (!brief && !opts.oomOnly)) {
reportType = ProcessStats.ADD_PSS_EXTERNAL_SLOW;
startTime = SystemClock.currentThreadTimeMillis();
// 填充MemoryInfo,这里设置进去的
if (!Debug.getMemoryInfo(pid, mi)) {
continue;
}
endTime = SystemClock.currentThreadTimeMillis();
hasSwapPss = mi.hasSwappedOutPss;
memtrackGraphics = mi.getOtherPrivate(Debug.MemoryInfo.OTHER_GRAPHICS);
memtrackGl = mi.getOtherPrivate(Debug.MemoryInfo.OTHER_GL);
} else {
reportType = ProcessStats.ADD_PSS_EXTERNAL;
startTime = SystemClock.currentThreadTimeMillis();
long pss = Debug.getPss(pid, tmpLong, memtrackTmp);
if (pss == 0) {
continue;
}
mi.dalvikPss = (int) pss;
endTime = SystemClock.currentThreadTimeMillis();
mi.dalvikPrivateDirty = (int) tmpLong[0];
mi.dalvikRss = (int) tmpLong[2];
memtrackGraphics = memtrackTmp[1];
memtrackGl = memtrackTmp[2];
}
if (!opts.isCheckinRequest && opts.dumpDetails) {
// 打印** MEMINFO in pid 2932 [com.android.settings] **
pw.println("\n** MEMINFO in pid " + pid + " [" + r.processName + "] **");
}
if (opts.dumpDetails) {
if (opts.localOnly) {
ActivityThread.dumpMemInfoTable(pw, mi, opts.isCheckinRequest, opts.dumpFullDetails,
opts.dumpDalvik, opts.dumpSummaryOnly, pid, r.processName, 0, 0, 0, 0, 0, 0);
if (opts.isCheckinRequest) {
pw.println();
}
} else {
pw.flush();
try {
TransferPipe tp = new TransferPipe();
try {
// 调用到ActivityThread.java中,调用到com.android.settings进程中
thread.dumpMemInfo(tp.getWriteFd(),
mi, opts.isCheckinRequest, opts.dumpFullDetails,
opts.dumpDalvik, opts.dumpSummaryOnly, opts.dumpUnreachable, innerArgs);
tp.go(fd, opts.dumpUnreachable ? 30000 : 5000);
} finally {
tp.kill();
}
} catch (IOException e) {
if (!opts.isCheckinRequest) {
pw.println("Got IoException! " + e);
pw.flush();
}
} catch (RemoteException e) {
if (!opts.isCheckinRequest) {
pw.println("Got RemoteException! " + e);
pw.flush();
}
}
}
}
final long myTotalPss = mi.getTotalPss();
final long myTotalUss = mi.getTotalUss();
final long myTotalRss = mi.getTotalRss();
final long myTotalSwapPss = mi.getTotalSwappedOutPss();
synchronized (mProcLock) {
if (r.getThread() != null && oomAdj == r.mState.getSetAdjWithServices()) {
// Record this for posterity if the process has been stable.
r.mProfile.addPss(myTotalPss, myTotalUss, myTotalRss, true,
reportType, endTime - startTime);
r.getPkgList().forEachPackageProcessStats(holder -> {
FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_MEMORY_STAT_REPORTED,
r.info.uid,
holder.state.getName(),
holder.state.getPackage(),
myTotalPss, myTotalUss, myTotalRss, reportType,
endTime-startTime,
holder.appVersion);
});
}
}
if (!opts.isCheckinRequest && mi != null) {
ss[INDEX_TOTAL_PSS] += myTotalPss;
ss[INDEX_TOTAL_SWAP_PSS] += myTotalSwapPss;
ss[INDEX_TOTAL_RSS] += myTotalRss;
ss[INDEX_TOTAL_MEMTRACK_GRAPHICS] += memtrackGraphics;
ss[INDEX_TOTAL_MEMTRACK_GL] += memtrackGl;
MemItem pssItem = new MemItem(r.processName + " (pid " + pid +
(hasActivities ? " / activities)" : ")"), r.processName, myTotalPss,
myTotalSwapPss, myTotalRss, pid, hasActivities);
procMems.add(pssItem);
procMemsMap.put(pid, pssItem);
ss[INDEX_NATIVE_PSS] += mi.nativePss;
ss[INDEX_NATIVE_SWAP_PSS] += mi.nativeSwappedOutPss;
ss[INDEX_NATIVE_RSS] += mi.nativeRss;
ss[INDEX_DALVIK_PSS] += mi.dalvikPss;
ss[INDEX_DALVIK_SWAP_PSS] += mi.dalvikSwappedOutPss;
ss[INDEX_DALVIK_RSS] += mi.dalvikRss;
for (int j=0; j<dalvikSubitemPss.length; j++) {
dalvikSubitemPss[j] += mi.getOtherPss(Debug.MemoryInfo.NUM_OTHER_STATS + j);
dalvikSubitemSwapPss[j] +=
mi.getOtherSwappedOutPss(Debug.MemoryInfo.NUM_OTHER_STATS + j);
dalvikSubitemRss[j] += mi.getOtherRss(Debug.MemoryInfo.NUM_OTHER_STATS + j);
}
ss[INDEX_OTHER_PSS] += mi.otherPss;
ss[INDEX_OTHER_RSS] += mi.otherRss;
ss[INDEX_OTHER_SWAP_PSS] += mi.otherSwappedOutPss;
for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
long mem = mi.getOtherPss(j);
miscPss[j] += mem;
ss[INDEX_OTHER_PSS] -= mem;
mem = mi.getOtherSwappedOutPss(j);
miscSwapPss[j] += mem;
ss[INDEX_OTHER_SWAP_PSS] -= mem;
mem = mi.getOtherRss(j);
miscRss[j] += mem;
ss[INDEX_OTHER_RSS] -= mem;
}
if (oomAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
cachedPss += myTotalPss;
cachedSwapPss += myTotalSwapPss;
}
for (int oomIndex=0; oomIndex<oomPss.length; oomIndex++) {
if (oomIndex == (oomPss.length - 1)
|| (oomAdj >= DUMP_MEM_OOM_ADJ[oomIndex]
&& oomAdj < DUMP_MEM_OOM_ADJ[oomIndex + 1])) {
oomPss[oomIndex] += myTotalPss;
oomSwapPss[oomIndex] += myTotalSwapPss;
if (oomProcs[oomIndex] == null) {
oomProcs[oomIndex] = new ArrayList<MemItem>();
}
oomProcs[oomIndex].add(pssItem);
oomRss[oomIndex] += myTotalRss;
break;
}
}
}
}
}
long nativeProcTotalPss = 0;
// dump单个进程不会走这里
if (collectNative) {
。。。。。。。
}
}
1.5 thread.dumpMemInfo
public void dumpMemInfo(ParcelFileDescriptor pfd, Debug.MemoryInfo mem, boolean checkin,
boolean dumpFullInfo, boolean dumpDalvik, boolean dumpSummaryOnly,
boolean dumpUnreachable, String[] args) {
FileOutputStream fout = new FileOutputStream(pfd.getFileDescriptor());
PrintWriter pw = new FastPrintWriter(fout);
try {
// 走这里
dumpMemInfo(pw, mem, checkin, dumpFullInfo, dumpDalvik, dumpSummaryOnly, dumpUnreachable);
} finally {
pw.flush();
IoUtils.closeQuietly(pfd);
}
}
1.6 dumpMemInfo
private void dumpMemInfo(PrintWriter pw, Debug.MemoryInfo memInfo, boolean checkin,
boolean dumpFullInfo, boolean dumpDalvik, boolean dumpSummaryOnly, boolean dumpUnreachable) {
long nativeMax = Debug.getNativeHeapSize() / 1024;
long nativeAllocated = Debug.getNativeHeapAllocatedSize() / 1024;
long nativeFree = Debug.getNativeHeapFreeSize() / 1024;
Runtime runtime = Runtime.getRuntime();
runtime.gc(); // Do GC since countInstancesOfClass counts unreachable objects.
long dalvikMax = runtime.totalMemory() / 1024;
long dalvikFree = runtime.freeMemory() / 1024;
long dalvikAllocated = dalvikMax - dalvikFree;
Class[] classesToCount = new Class[] {
ContextImpl.class,
Activity.class,
WebView.class,
OpenSSLSocketImpl.class
};
long[] instanceCounts = VMDebug.countInstancesOfClasses(classesToCount, true);
long appContextInstanceCount = instanceCounts[0];
long activityInstanceCount = instanceCounts[1];
long webviewInstanceCount = instanceCounts[2];
long openSslSocketCount = instanceCounts[3];
long viewInstanceCount = ViewDebug.getViewInstanceCount();
long viewRootInstanceCount = ViewDebug.getViewRootImplCount();
int globalAssetCount = AssetManager.getGlobalAssetCount();
int globalAssetManagerCount = AssetManager.getGlobalAssetManagerCount();
int binderLocalObjectCount = Debug.getBinderLocalObjectCount();
int binderProxyObjectCount = Debug.getBinderProxyObjectCount();
int binderDeathObjectCount = Debug.getBinderDeathObjectCount();
long parcelSize = Parcel.getGlobalAllocSize();
long parcelCount = Parcel.getGlobalAllocCount();
SQLiteDebug.PagerStats stats = SQLiteDebug.getDatabaseInfo();
// 把表格打印出来
dumpMemInfoTable(pw, memInfo, checkin, dumpFullInfo, dumpDalvik, dumpSummaryOnly,
Process.myPid(),
(mBoundApplication != null) ? mBoundApplication.processName : "unknown",
nativeMax, nativeAllocated, nativeFree,
dalvikMax, dalvikAllocated, dalvikFree);
if (checkin) {
// NOTE: if you change anything significant below, also consider changing
// ACTIVITY_THREAD_CHECKIN_VERSION.
// Object counts
pw.print(viewInstanceCount); pw.print(',');
pw.print(viewRootInstanceCount); pw.print(',');
pw.print(appContextInstanceCount); pw.print(',');
pw.print(activityInstanceCount); pw.print(',');
pw.print(globalAssetCount); pw.print(',');
pw.print(globalAssetManagerCount); pw.print(',');
pw.print(binderLocalObjectCount); pw.print(',');
pw.print(binderProxyObjectCount); pw.print(',');
pw.print(binderDeathObjectCount); pw.print(',');
pw.print(openSslSocketCount); pw.print(',');
// SQL
pw.print(stats.memoryUsed / 1024); pw.print(',');
pw.print(stats.memoryUsed / 1024); pw.print(',');
pw.print(stats.pageCacheOverflow / 1024); pw.print(',');
pw.print(stats.largestMemAlloc / 1024);
for (int i = 0; i < stats.dbStats.size(); i++) {
DbStats dbStats = stats.dbStats.get(i);
pw.print(','); pw.print(dbStats.dbName);
pw.print(','); pw.print(dbStats.pageSize);
pw.print(','); pw.print(dbStats.dbSize);
pw.print(','); pw.print(dbStats.lookaside);
pw.print(','); pw.print(dbStats.cache);
pw.print(','); pw.print(dbStats.cache);
}
pw.println();
return;
}
pw.println(" ");
pw.println(" Objects");
printRow(pw, TWO_COUNT_COLUMNS, "Views:", viewInstanceCount, "ViewRootImpl:",
viewRootInstanceCount);
printRow(pw, TWO_COUNT_COLUMNS, "AppContexts:", appContextInstanceCount,
"Activities:", activityInstanceCount);
printRow(pw, TWO_COUNT_COLUMNS, "Assets:", globalAssetCount,
"AssetManagers:", globalAssetManagerCount);
printRow(pw, TWO_COUNT_COLUMNS, "Local Binders:", binderLocalObjectCount,
"Proxy Binders:", binderProxyObjectCount);
printRow(pw, TWO_COUNT_COLUMNS, "Parcel memory:", parcelSize/1024,
"Parcel count:", parcelCount);
printRow(pw, TWO_COUNT_COLUMNS, "Death Recipients:", binderDeathObjectCount,
"OpenSSL Sockets:", openSslSocketCount);
printRow(pw, ONE_COUNT_COLUMN, "WebViews:", webviewInstanceCount);
// SQLite mem info
pw.println(" ");
pw.println(" SQL");
printRow(pw, ONE_COUNT_COLUMN, "MEMORY_USED:", stats.memoryUsed / 1024);
printRow(pw, TWO_COUNT_COLUMNS, "PAGECACHE_OVERFLOW:",
stats.pageCacheOverflow / 1024, "MALLOC_SIZE:", stats.largestMemAlloc / 1024);
pw.println(" ");
int N = stats.dbStats.size();
if (N > 0) {
pw.println(" DATABASES");
printRow(pw, DB_INFO_FORMAT, "pgsz", "dbsz", "Lookaside(b)", "cache",
"Dbname");
for (int i = 0; i < N; i++) {
DbStats dbStats = stats.dbStats.get(i);
printRow(pw, DB_INFO_FORMAT,
(dbStats.pageSize > 0) ? String.valueOf(dbStats.pageSize) : " ",
(dbStats.dbSize > 0) ? String.valueOf(dbStats.dbSize) : " ",
(dbStats.lookaside > 0) ? String.valueOf(dbStats.lookaside) : " ",
dbStats.cache, dbStats.dbName);
}
}
// Asset details.
String assetAlloc = AssetManager.getAssetAllocations();
if (assetAlloc != null) {
pw.println(" ");
pw.println(" Asset Allocations");
pw.print(assetAlloc);
}
// Unreachable native memory
if (dumpUnreachable) {
boolean showContents = ((mBoundApplication != null)
&& ((mBoundApplication.appInfo.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0))
|| android.os.Build.IS_DEBUGGABLE;
pw.println(" ");
pw.println(" Unreachable memory");
pw.print(Debug.getUnreachableMemory(100, showContents));
}
}
1.7 dumpMemInfoTable -- 打印meminfo信息
public static void dumpMemInfoTable(PrintWriter pw, Debug.MemoryInfo memInfo, boolean checkin,
boolean dumpFullInfo, boolean dumpDalvik, boolean dumpSummaryOnly,
int pid, String processName,
long nativeMax, long nativeAllocated, long nativeFree,
long dalvikMax, long dalvikAllocated, long dalvikFree) {
// For checkin, we print one long comma-separated list of values
if (checkin) {
// NOTE: if you change anything significant below, also consider changing
// ACTIVITY_THREAD_CHECKIN_VERSION.
。。。。。。
}
if (!dumpSummaryOnly) {
if (dumpFullInfo) {
printRow(pw, HEAP_FULL_COLUMN, "", "Pss", "Pss", "Shared", "Private",
"Shared", "Private", memInfo.hasSwappedOutPss ? "SwapPss" : "Swap",
"Rss", "Heap", "Heap", "Heap");
printRow(pw, HEAP_FULL_COLUMN, "", "Total", "Clean", "Dirty", "Dirty",
"Clean", "Clean", "Dirty", "Total",
"Size", "Alloc", "Free");
printRow(pw, HEAP_FULL_COLUMN, "", "------", "------", "------", "------",
"------", "------", "------", "------", "------", "------", "------");
printRow(pw, HEAP_FULL_COLUMN, "Native Heap", memInfo.nativePss,
memInfo.nativeSwappablePss, memInfo.nativeSharedDirty,
memInfo.nativePrivateDirty, memInfo.nativeSharedClean,
memInfo.nativePrivateClean, memInfo.hasSwappedOutPss ?
memInfo.nativeSwappedOutPss : memInfo.nativeSwappedOut,
memInfo.nativeRss, nativeMax, nativeAllocated, nativeFree);
printRow(pw, HEAP_FULL_COLUMN, "Dalvik Heap", memInfo.dalvikPss,
memInfo.dalvikSwappablePss, memInfo.dalvikSharedDirty,
memInfo.dalvikPrivateDirty, memInfo.dalvikSharedClean,
memInfo.dalvikPrivateClean, memInfo.hasSwappedOutPss ?
memInfo.dalvikSwappedOutPss : memInfo.dalvikSwappedOut,
memInfo.dalvikRss, dalvikMax, dalvikAllocated, dalvikFree);
} else {
// 走这里,打印Pss Total头部信息
printRow(pw, HEAP_COLUMN, "", "Pss", "Private",
"Private", memInfo.hasSwappedOutPss ? "SwapPss" : "Swap",
"Rss", "Heap", "Heap", "Heap");
printRow(pw, HEAP_COLUMN, "", "Total", "Dirty",
"Clean", "Dirty", "Total", "Size", "Alloc", "Free");
printRow(pw, HEAP_COLUMN, "", "------", "------", "------",
"------", "------", "------", "------", "------", "------");
// 这里打印Native Heap
printRow(pw, HEAP_COLUMN, "Native Heap", memInfo.nativePss,
memInfo.nativePrivateDirty,
memInfo.nativePrivateClean,
memInfo.hasSwappedOutPss ? memInfo.nativeSwappedOutPss :
memInfo.nativeSwappedOut, memInfo.nativeRss,
nativeMax, nativeAllocated, nativeFree);
// 这里打印Dalvik Heap
printRow(pw, HEAP_COLUMN, "Dalvik Heap", memInfo.dalvikPss,
memInfo.dalvikPrivateDirty,
memInfo.dalvikPrivateClean,
memInfo.hasSwappedOutPss ? memInfo.dalvikSwappedOutPss :
memInfo.dalvikSwappedOut, memInfo.dalvikRss,
dalvikMax, dalvikAllocated, dalvikFree);
}
int otherPss = memInfo.otherPss;
int otherSwappablePss = memInfo.otherSwappablePss;
int otherSharedDirty = memInfo.otherSharedDirty;
int otherPrivateDirty = memInfo.otherPrivateDirty;
int otherSharedClean = memInfo.otherSharedClean;
int otherPrivateClean = memInfo.otherPrivateClean;
int otherSwappedOut = memInfo.otherSwappedOut;
int otherSwappedOutPss = memInfo.otherSwappedOutPss;
int otherRss = memInfo.otherRss;
for (int i=0; i<Debug.MemoryInfo.NUM_OTHER_STATS; i++) {
// 在这里打印EGL和GL相关的内存信息
final int myPss = memInfo.getOtherPss(i);
final int mySwappablePss = memInfo.getOtherSwappablePss(i);
final int mySharedDirty = memInfo.getOtherSharedDirty(i);
final int myPrivateDirty = memInfo.getOtherPrivateDirty(i);
final int mySharedClean = memInfo.getOtherSharedClean(i);
final int myPrivateClean = memInfo.getOtherPrivateClean(i);
final int mySwappedOut = memInfo.getOtherSwappedOut(i);
final int mySwappedOutPss = memInfo.getOtherSwappedOutPss(i);
final int myRss = memInfo.getOtherRss(i);
if (myPss != 0 || mySharedDirty != 0 || myPrivateDirty != 0
|| mySharedClean != 0 || myPrivateClean != 0 || myRss != 0
|| (memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut) != 0) {
if (dumpFullInfo) {
printRow(pw, HEAP_FULL_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
myPss, mySwappablePss, mySharedDirty, myPrivateDirty,
mySharedClean, myPrivateClean,
memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut,
myRss, "", "", "");
} else {
printRow(pw, HEAP_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
myPss, myPrivateDirty,
myPrivateClean,
memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut,
myRss, "", "", "");
}
otherPss -= myPss;
otherSwappablePss -= mySwappablePss;
otherSharedDirty -= mySharedDirty;
otherPrivateDirty -= myPrivateDirty;
otherSharedClean -= mySharedClean;
otherPrivateClean -= myPrivateClean;
otherSwappedOut -= mySwappedOut;
otherSwappedOutPss -= mySwappedOutPss;
otherRss -= myRss;
}
}
if (dumpFullInfo) {
printRow(pw, HEAP_FULL_COLUMN, "Unknown", otherPss, otherSwappablePss,
otherSharedDirty, otherPrivateDirty, otherSharedClean, otherPrivateClean,
memInfo.hasSwappedOutPss ? otherSwappedOutPss : otherSwappedOut,
otherRss, "", "", "");
printRow(pw, HEAP_FULL_COLUMN, "TOTAL", memInfo.getTotalPss(),
memInfo.getTotalSwappablePss(),
memInfo.getTotalSharedDirty(), memInfo.getTotalPrivateDirty(),
memInfo.getTotalSharedClean(), memInfo.getTotalPrivateClean(),
memInfo.hasSwappedOutPss ? memInfo.getTotalSwappedOutPss() :
memInfo.getTotalSwappedOut(), memInfo.getTotalRss(),
nativeMax+dalvikMax, nativeAllocated+dalvikAllocated,
nativeFree+dalvikFree);
} else {
printRow(pw, HEAP_COLUMN, "Unknown", otherPss,
otherPrivateDirty, otherPrivateClean,
memInfo.hasSwappedOutPss ? otherSwappedOutPss : otherSwappedOut,
otherRss, "", "", "");
printRow(pw, HEAP_COLUMN, "TOTAL", memInfo.getTotalPss(),
memInfo.getTotalPrivateDirty(),
memInfo.getTotalPrivateClean(),
memInfo.hasSwappedOutPss ? memInfo.getTotalSwappedOutPss() :
memInfo.getTotalSwappedOut(), memInfo.getTotalPss(),
nativeMax+dalvikMax,
nativeAllocated+dalvikAllocated, nativeFree+dalvikFree);
}
if (dumpDalvik) {
pw.println(" ");
pw.println(" Dalvik Details");
for (int i=Debug.MemoryInfo.NUM_OTHER_STATS;
i<Debug.MemoryInfo.NUM_OTHER_STATS + Debug.MemoryInfo.NUM_DVK_STATS; i++) {
final int myPss = memInfo.getOtherPss(i);
final int mySwappablePss = memInfo.getOtherSwappablePss(i);
final int mySharedDirty = memInfo.getOtherSharedDirty(i);
final int myPrivateDirty = memInfo.getOtherPrivateDirty(i);
final int mySharedClean = memInfo.getOtherSharedClean(i);
final int myPrivateClean = memInfo.getOtherPrivateClean(i);
final int mySwappedOut = memInfo.getOtherSwappedOut(i);
final int mySwappedOutPss = memInfo.getOtherSwappedOutPss(i);
final int myRss = memInfo.getOtherRss(i);
if (myPss != 0 || mySharedDirty != 0 || myPrivateDirty != 0
|| mySharedClean != 0 || myPrivateClean != 0
|| (memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut) != 0) {
if (dumpFullInfo) {
printRow(pw, HEAP_FULL_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
myPss, mySwappablePss, mySharedDirty, myPrivateDirty,
mySharedClean, myPrivateClean,
memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut,
myRss, "", "", "");
} else {
printRow(pw, HEAP_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
myPss, myPrivateDirty,
myPrivateClean,
memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut,
myRss, "", "", "");
}
}
}
}
}
pw.println(" ");
pw.println(" App Summary");
printRow(pw, TWO_COUNT_COLUMN_HEADER, "", "Pss(KB)", "", "Rss(KB)");
printRow(pw, TWO_COUNT_COLUMN_HEADER, "", "------", "", "------");
printRow(pw, TWO_COUNT_COLUMNS,
"Java Heap:", memInfo.getSummaryJavaHeap(), "", memInfo.getSummaryJavaHeapRss());
printRow(pw, TWO_COUNT_COLUMNS,
"Native Heap:", memInfo.getSummaryNativeHeap(), "",
memInfo.getSummaryNativeHeapRss());
printRow(pw, TWO_COUNT_COLUMNS,
"Code:", memInfo.getSummaryCode(), "", memInfo.getSummaryCodeRss());
printRow(pw, TWO_COUNT_COLUMNS,
"Stack:", memInfo.getSummaryStack(), "", memInfo.getSummaryStackRss());
printRow(pw, TWO_COUNT_COLUMNS,
"Graphics:", memInfo.getSummaryGraphics(), "", memInfo.getSummaryGraphicsRss());
printRow(pw, ONE_COUNT_COLUMN,
"Private Other:", memInfo.getSummaryPrivateOther());
printRow(pw, ONE_COUNT_COLUMN,
"System:", memInfo.getSummarySystem());
printRow(pw, ONE_ALT_COUNT_COLUMN,
"Unknown:", "", "", memInfo.getSummaryUnknownRss());
pw.println(" ");
if (memInfo.hasSwappedOutPss) {
printRow(pw, THREE_COUNT_COLUMNS,
"TOTAL PSS:", memInfo.getSummaryTotalPss(),
"TOTAL RSS:", memInfo.getTotalRss(),
"TOTAL SWAP PSS:", memInfo.getSummaryTotalSwapPss());
} else {
printRow(pw, THREE_COUNT_COLUMNS,
"TOTAL PSS:", memInfo.getSummaryTotalPss(),
"TOTAL RSS:", memInfo.getTotalRss(),
"TOTAL SWAP (KB):", memInfo.getSummaryTotalSwap());
}
}
2. Debug jni实现
android/frameworks/base/core/jni/android_os_Debug.cpp
2.1 Debug.getMemoryInfo
frameworks/base/core/java/android/os/Debug.java
// 是一个native类型的函数
public static native boolean getMemoryInfo(int pid, MemoryInfo memoryInfo);
2.2 android_os_Debug_getDirtyPagesPid -- 获取meminfo的信息
static jboolean android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz,
jint pid, jobject object)
{
bool foundSwapPss;
stats_t stats[_NUM_HEAP];
memset(&stats, 0, sizeof(stats));
if (!load_maps(pid, stats, &foundSwapPss)) {
return JNI_FALSE;
}
struct graphics_memory_pss graphics_mem;
// 1. 读取EGL mtrack和"GL mtrack"的内存大小
if (read_memtrack_memory(pid, &graphics_mem) == 0) {
stats[HEAP_GRAPHICS].pss = graphics_mem.graphics; // "EGL mtrack"
stats[HEAP_GRAPHICS].privateDirty = graphics_mem.graphics;
stats[HEAP_GRAPHICS].rss = graphics_mem.graphics;
stats[HEAP_GL].pss = graphics_mem.gl; // "GL mtrack"
stats[HEAP_GL].privateDirty = graphics_mem.gl;
stats[HEAP_GL].rss = graphics_mem.gl;
stats[HEAP_OTHER_MEMTRACK].pss = graphics_mem.other;
stats[HEAP_OTHER_MEMTRACK].privateDirty = graphics_mem.other;
stats[HEAP_OTHER_MEMTRACK].rss = graphics_mem.other;
}
for (int i=_NUM_CORE_HEAP; i<_NUM_EXCLUSIVE_HEAP; i++) {
stats[HEAP_UNKNOWN].pss += stats[i].pss;
stats[HEAP_UNKNOWN].swappablePss += stats[i].swappablePss;
stats[HEAP_UNKNOWN].rss += stats[i].rss;
stats[HEAP_UNKNOWN].privateDirty += stats[i].privateDirty;
stats[HEAP_UNKNOWN].sharedDirty += stats[i].sharedDirty;
stats[HEAP_UNKNOWN].privateClean += stats[i].privateClean;
stats[HEAP_UNKNOWN].sharedClean += stats[i].sharedClean;
stats[HEAP_UNKNOWN].swappedOut += stats[i].swappedOut;
stats[HEAP_UNKNOWN].swappedOutPss += stats[i].swappedOutPss;
}
for (int i=0; i<_NUM_CORE_HEAP; i++) {
env->SetIntField(object, stat_fields[i].pss_field, stats[i].pss);
env->SetIntField(object, stat_fields[i].pssSwappable_field, stats[i].swappablePss);
env->SetIntField(object, stat_fields[i].rss_field, stats[i].rss);
env->SetIntField(object, stat_fields[i].privateDirty_field, stats[i].privateDirty);
env->SetIntField(object, stat_fields[i].sharedDirty_field, stats[i].sharedDirty);
env->SetIntField(object, stat_fields[i].privateClean_field, stats[i].privateClean);
env->SetIntField(object, stat_fields[i].sharedClean_field, stats[i].sharedClean);
env->SetIntField(object, stat_fields[i].swappedOut_field, stats[i].swappedOut);
env->SetIntField(object, stat_fields[i].swappedOutPss_field, stats[i].swappedOutPss);
}
env->SetBooleanField(object, hasSwappedOutPss_field, foundSwapPss);
jintArray otherIntArray = (jintArray)env->GetObjectField(object, otherStats_field);
jint* otherArray = (jint*)env->GetPrimitiveArrayCritical(otherIntArray, 0);
if (otherArray == NULL) {
return JNI_FALSE;
}
int j=0;
// otherarray从3开始,所以HEAP_GRAPHICS为17 -> "EGL mtrack" 14
for (int i=_NUM_CORE_HEAP; i<_NUM_HEAP; i++) {
otherArray[j++] = stats[i].pss;
otherArray[j++] = stats[i].swappablePss;
otherArray[j++] = stats[i].rss;
otherArray[j++] = stats[i].privateDirty;
otherArray[j++] = stats[i].sharedDirty;
otherArray[j++] = stats[i].privateClean;
otherArray[j++] = stats[i].sharedClean;
otherArray[j++] = stats[i].swappedOut;
otherArray[j++] = stats[i].swappedOutPss;
}
env->ReleasePrimitiveArrayCritical(otherIntArray, otherArray, 0);
return JNI_TRUE;
}
2.3 read_memtrack_memory
/*
* Retrieves the graphics memory that is unaccounted for in /proc/pid/smaps.
*/
static int read_memtrack_memory(int pid, struct graphics_memory_pss* graphics_mem)
{
// memtrack_proc_new为libmemtrack的接口,创建memtrack_proc数据结构
struct memtrack_proc* p = memtrack_proc_new();
if (p == NULL) {
ALOGW("failed to create memtrack_proc");
return -1;
}
int err = read_memtrack_memory(p, pid, graphics_mem);
memtrack_proc_destroy(p);
return err;
}
/*
* Uses libmemtrack to retrieve graphics memory that the process is using.
* Any graphics memory reported in /proc/pid/smaps is not included here.
*/
static int read_memtrack_memory(struct memtrack_proc* p, int pid,
struct graphics_memory_pss* graphics_mem)
{
// 这里获取到了大小和flags
int err = memtrack_proc_get(p, pid);
if (err != 0) {
// The memtrack HAL may not be available, do not log to avoid flooding
// logcat.
return err;
}
// 这里开始分类了:MemtrackType::GRAPHICS
// 和flags无关,只需要一个大小即可
ssize_t pss = memtrack_proc_graphics_pss(p);
if (pss < 0) {
ALOGW("failed to get graphics pss: %zd", pss);
return pss;
}
graphics_mem->graphics = pss / 1024;
// MemtrackType::GL
pss = memtrack_proc_gl_pss(p);
if (pss < 0) {
ALOGW("failed to get gl pss: %zd", pss);
return pss;
}
graphics_mem->gl = pss / 1024;
// MemtrackType::OTHER
pss = memtrack_proc_other_pss(p);
if (pss < 0) {
ALOGW("failed to get other pss: %zd", pss);
return pss;
}
graphics_mem->other = pss / 1024;
return 0;
}
2.4 enum-HEAP_GRAPHICS的值
enum {
0 HEAP_UNKNOWN,
1 HEAP_DALVIK,
2 HEAP_NATIVE,
3 HEAP_DALVIK_OTHER,
4 HEAP_STACK,
5 HEAP_CURSOR,
6 HEAP_ASHMEM,
7 HEAP_GL_DEV,
8 HEAP_UNKNOWN_DEV,
9 HEAP_SO,
10 HEAP_JAR,
11 HEAP_APK,
12 HEAP_TTF,
13 HEAP_DEX,
14 HEAP_OAT,
15 HEAP_ART,
16 HEAP_UNKNOWN_MAP,
17 HEAP_GRAPHICS, // "EGL mtrack" 14
18 HEAP_GL, // "GL mtrack" 15
19 HEAP_OTHER_MEMTRACK,
// Dalvik extra sections (heap).
20 HEAP_DALVIK_NORMAL,
21 HEAP_DALVIK_LARGE,
23 HEAP_DALVIK_ZYGOTE,
24 HEAP_DALVIK_NON_MOVING,
// Dalvik other extra sections.
25 HEAP_DALVIK_OTHER_LINEARALLOC,
26 HEAP_DALVIK_OTHER_ACCOUNTING,
27 HEAP_DALVIK_OTHER_ZYGOTE_CODE_CACHE,
28 HEAP_DALVIK_OTHER_APP_CODE_CACHE,
29 HEAP_DALVIK_OTHER_COMPILER_METADATA,
30 HEAP_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE,
// Boot vdex / app dex / app vdex
31 HEAP_DEX_BOOT_VDEX,
32 HEAP_DEX_APP_DEX,
33 HEAP_DEX_APP_VDEX,
// App art, boot art.
34 HEAP_ART_APP,
35 HEAP_ART_BOOT,
36 _NUM_HEAP,
20 _NUM_EXCLUSIVE_HEAP = HEAP_OTHER_MEMTRACK+1,
3 _NUM_CORE_HEAP = HEAP_NATIVE+1
};
2.5 graphics_memory_pss
struct graphics_memory_pss
{
int graphics;
int gl;
int other;
};
3. libmemtrack实现
android/system/memory/libmemtrack
3.1 memtrack_proc_new
memtrack_proc *memtrack_proc_new(void)
{
return new memtrack_proc();
}
3.2 memtrack_proc
struct memtrack_proc {
pid_t pid;
memtrack_proc_type types[static_cast<int>(MemtrackType::NUM_TYPES)];
};
3.3 memtrack_proc_type
struct memtrack_proc_type {
MemtrackType type;
std::vector<MemtrackRecord> records;
};
3.4 memtrack_proc_get
int memtrack_proc_get(memtrack_proc *p, pid_t pid)
{
if (!p) {
return -EINVAL;
}
p->pid = pid;
for (uint32_t i = 0; i < (uint32_t)MemtrackType::NUM_TYPES; i++) {
// 遍历每一个type类型,types有type和records,records里有flags + size大小
int ret = memtrack_proc_get_type(&p->types[i], pid, (MemtrackType)i);
if (ret != 0)
return ret;
}
return memtrack_proc_sanity_check(p);
}
3.5 memtrack_proc_get_type
static int memtrack_proc_get_type(memtrack_proc_type *t,
pid_t pid, MemtrackType type)
{
int err = 0;
// 1. 获取memtrack的aidl服务
std::shared_ptr<V_aidl::IMemtrack> service= get_aidl_instance();
if (service) {
std::vector<V_aidl::MemtrackRecord> records;
// 2. 调用getMemory接口
auto status = service->getMemory(
pid, static_cast<V_aidl::MemtrackType>(static_cast<uint32_t>(type)), &records);
if (!status.isOk()) {
return -1;
}
t->records.resize(records.size());
for (size_t i = 0; i < records.size(); i++) {
// 这里将sizeInBytes和flags进行赋值
t->records[i].sizeInBytes = records[i].sizeInBytes;
t->records[i].flags = records[i].flags;
}
return err;
}
// 下面是memtrack hal hidl服务的
android::sp<V1_0::IMemtrack> memtrack = get_hidl_instance();
if (memtrack == nullptr)
return -1;
Return<void> ret = memtrack->getMemory(pid, type,
[&t, &err](MemtrackStatus status, hidl_vec<MemtrackRecord> records) {
if (status != MemtrackStatus::SUCCESS) {
err = -1;
t->records.resize(0);
}
t->records.resize(records.size());
for (size_t i = 0; i < records.size(); i++) {
t->records[i].sizeInBytes = records[i].sizeInBytes;
t->records[i].flags = records[i].flags;
}
});
return ret.isOk() ? err : -1;
}
3.6 memtrack_proc_graphics_pss
ssize_t memtrack_proc_graphics_pss(memtrack_proc *p)
{
std::vector<MemtrackType> types = { MemtrackType::GRAPHICS };
return memtrack_proc_sum(p, types,
(uint32_t)MemtrackFlag::SMAPS_UNACCOUNTED);
}
3.7 memtrack_proc_sum--最终计算大小的函数
static ssize_t memtrack_proc_sum(memtrack_proc *p,
const std::vector<MemtrackType>& types, uint32_t flags)
{
ssize_t sum = 0;
for (size_t i = 0; i < types.size(); i++) {
memtrack_proc_type type = p->types[static_cast<int>(types[i])];
std::vector<MemtrackRecord> records = type.records;
for (size_t j = 0; j < records.size(); j++) {
// 寻找MemtrackFlag::SMAPS_UNACCOUNTED flags的,然后相加,就是这个大小了
if ((records[j].flags & flags) == flags) {
sum += records[j].sizeInBytes;
}
}
}
return sum;
}
4. pixel 2 memtrack hal实现
android/hardware/qcom/display/msm8998/libmemtrack
4.1 getMemory-msm_memtrack_get_memory
int msm_memtrack_get_memory(const struct memtrack_module *module,
pid_t pid,
int type,
struct memtrack_record *records,
size_t *num_records)
{
if(!module)
return -1;
if (type == MEMTRACK_TYPE_GL || type == MEMTRACK_TYPE_GRAPHICS) {
return kgsl_memtrack_get_memory(pid, type, records, num_records);
}
return -EINVAL;
}
4.2 kgsl_memtrack_get_memory
int kgsl_memtrack_get_memory(pid_t pid, enum memtrack_type type,
struct memtrack_record *records,
size_t *num_records)
{
size_t allocated_records = min(*num_records, ARRAY_SIZE(record_templates));
FILE *fp;
char line[1024];
char tmp[128];
size_t accounted_size = 0;
size_t unaccounted_size = 0;
*num_records = ARRAY_SIZE(record_templates);
/* fastpath to return the necessary number of records */
if (allocated_records == 0) {
return 0;
}
memcpy(records, record_templates,
sizeof(struct memtrack_record) * allocated_records);
snprintf(tmp, sizeof(tmp), "/d/kgsl/proc/%d/mem", pid);
fp = fopen(tmp, "r");
if (fp == NULL) {
return -errno;
}
/* Go through each line of <pid>/mem file and for every entry of type "gpumem"
* check if the gpubuffer entry is usermapped or not. If the entry is usermapped
* count the entry as accounted else count the entry as unaccounted.
*/
while (1) {
unsigned long size, mapsize;
char line_type[7];
char flags[10];
char line_usage[19];
int ret, egl_surface_count = 0, egl_image_count = 0;
if (fgets(line, sizeof(line), fp) == NULL) {
break;
}
/* Format:
* gpuaddr useraddr size id flags type usage sglen mapsize eglsrf eglimg
* 545ba000 545ba000 4096 1 -----pY gpumem arraybuffer 1 4096 0 0
*/
ret = sscanf(line, "%*x %*x %lu %*d %9s %6s %18s %*d %lu %6d %6d\n",
&size, flags, line_type, line_usage, &mapsize,
&egl_surface_count, &egl_image_count);
if (ret != 7) {
continue;
}
if (size == 0) {
fclose(fp);
return -EINVAL;
}
if (unaccounted_size + size < size) {
fclose(fp);
return -ERANGE;
}
// GL的就是读gpumem
if (type == MEMTRACK_TYPE_GL && strcmp(line_type, "gpumem") == 0) {
if (flags[6] == 'Y') {
if (accounted_size + mapsize < accounted_size) {
fclose(fp);
return -ERANGE;
}
accounted_size += mapsize;
if (mapsize > size) {
fclose(fp);
return -EINVAL;
}
unaccounted_size += size - mapsize;
} else {
unaccounted_size += size;
}
// GRAPHICS就是ion的内存
} else if (type == MEMTRACK_TYPE_GRAPHICS && strcmp(line_type, "ion") == 0) {
if (strcmp(line_usage, "egl_surface") == 0) {
unaccounted_size += size;
}
else if (egl_surface_count == 0) {
unaccounted_size += size / (egl_image_count ? egl_image_count : 1);
}
}
}
if (allocated_records > 0) {
records[0].size_in_bytes = accounted_size;
}
if (allocated_records > 1) {
// 上面计算传下来的flag都是unaccounted类型的,所以只需要看unaccounted_size就好了
// 详情看memtrack_proc_graphics_pss函数
records[1].size_in_bytes = unaccounted_size;
}
fclose(fp);
return 0;
}
4.3 record_templates
struct memtrack_record record_templates[] = {
{
.flags = MEMTRACK_FLAG_SMAPS_ACCOUNTED |
MEMTRACK_FLAG_PRIVATE |
MEMTRACK_FLAG_NONSECURE,
},
{
// 上层要计算的flags类型都是MEMTRACK_FLAG_SMAPS_UNACCOUNTED的,只要看这个就好了
// 详情看memtrack_proc_graphics_pss函数
.flags = MEMTRACK_FLAG_SMAPS_UNACCOUNTED |
MEMTRACK_FLAG_PRIVATE |
MEMTRACK_FLAG_NONSECURE,
},
};
补充
稳定的aidl
Android 接口定义语言 (AIDL) 是一款可供用户用来抽象化 IPC 的工具。
aidl注册的服务,都是在servicemanager中的,可以通过service list命令来查看。hidl注册的服务,在hwservicemanager中,要通过lshal命令来查看
如果 HAL 使用 AIDL 在框架组件(例如 system.img
中的组件)和硬件组件(例如 vendor.img
中的组件)之间进行通信,则必须使用稳定的 AIDL。不
过,如需在分区内进行通信(例如从一个 HAL 到另一个),则对所使用的 IPC 机制没有任何限制。
1. aidl文件解析
可以通过
1. IMemtrack.aidl-interface IMemtrack
android/hardware/interfaces/memtrack/aidl/android/hardware/memtrack/IMemtrack.aidl
//要让system和vendor都可以使用某个AIDL接口,需要对该接口进行两项更改:
//每个类型定义都需要带有@VintfStability注释。
//aidl_interface声明需要包含stability: "vintf"。
@VintfStability
interface IMemtrack {
MemtrackRecord[] getMemory(in int pid, in MemtrackType type);
DeviceInfo[] getGpuDeviceInfo();
}
// 要传递的数据,则定义为parcelable类型的
@VintfStability
parcelable MemtrackRecord {
/* Memtrack Flags */
const int FLAG_SMAPS_ACCOUNTED = 1 << 1;
const int FLAG_SMAPS_UNACCOUNTED = 1 << 2;
const int FLAG_SHARED = 1 << 3;
const int FLAG_SHARED_PSS = 1 << 4;
const int FLAG_PRIVATE = 1 << 5;
const int FLAG_SYSTEM = 1 << 6;
const int FLAG_DEDICATED = 1 << 7;
const int FLAG_NONSECURE = 1 << 8;
const int FLAG_SECURE = 1 << 9;
/* Bitfield indicating all flags that are valid for this record */
int flags;
long sizeInBytes;
}
2. Android.bp-aidl_interface
aidl_interface {
name: "android.hardware.memtrack",
vendor_available: true,
srcs: ["android/hardware/memtrack/*.aidl"],
# 为了system.img和vendor.img都能访问这个接口,这里要声明stability: "vintf"
stability: "vintf",
backend: {
cpp: {
enabled: false,
},
java: {
enabled: false,
},
ndk: {
vndk: {
enabled: true,
},
},
},
}
3. aidl后端
AIDL后端是生成存根代码的目标,在使用AIDL文件时,采用的始终是某种特定语言,并始终在某种特定的运行时环境中使用这些文件。AIDL的后端有:
后端 | 语言 | API Surface | 构建系统 |
---|---|---|---|
java | java | SDK(稳定) | 全部 |
NDK | C++ | libbinder_ndk(稳定) | aidl_interface |
CPP | C++ | libbinder(不稳定) | 全部 |
NDK后端是Android 10中的新功能。而适用于HAL的AIDL,是需要稳定的AIDL,因此只能使用java后端或者NDK后端,而不能使用CPP后端。因此aidl的bp文件如上面的Android.bp所示,cpp和java端被禁止了,只是留了vndk端。
4. aidl返回值
ndk后面的返回值使用的是ndk::ScopedAStatus,cpp后端使用的是android::Status。由于我们的AIDL HAL是需要ndk后端的,因此在接口的返回值是
ndk::ScopedAStatus类型的。接口的完整声明可以在out目录下找到aidl对应的头文件,然后copy(主要是一些参数的格式)。或者可以根据aild的声明自己
写。
返回值,如果执行成功,则可以返回:ndk::ScopedAStatus::ok();
,否则可以返回对应的错误异常
ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
。
接口调用
通过service call方法调用
service call android.hardware.memtrack.IMemtrack/default 2
JNI初始化
1. Android启动的时候加载jni库
Android系统在启动过程中,先启动Kernel创建init进程,紧接着由init进程fork第一个横穿Java和C/C++的进程,即Zygote进程。Zygote启动过程中会在AndroidRuntime.cpp
文件中的startVm
创建虚拟机,VM创建完成后,紧接着调用startReg
完成虚拟机中的JNI方法注册。
2. register_jni_procs
android/frameworks/base/core/jni/AndroidRuntime.cpp
/*
* Register android native functions with the VM.
*/
/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
ATRACE_NAME("RegisterAndroidNatives");
/*
* This hook causes all future threads created in this process to be
* attached to the JavaVM. (This needs to go away in favor of JNI
* Attach calls.)
*/
//设置线程创建方法为javaCreateThreadEtc
androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
ALOGV("--- registering native functions ---\n");
/*
* Every "register" function calls one or more things that return
* a local reference (e.g. FindClass). Because we haven't really
* started the VM yet, they're all getting stored in the base frame
* and never released. Use Push/Pop to manage the storage.
*/
env->PushLocalFrame(200);
//进程JNI方法的注册
if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
env->PopLocalFrame(NULL);
return -1;
}
env->PopLocalFrame(NULL);
//createJavaThread("fubar", quickTest, (void*) "hello");
return 0;
}
3. register_jni_procs
static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
{
for (size_t i = 0; i < count; i++) {
// 执行register_android_os_Debug等register函数
if (array[i].mProc(env) < 0) {
#ifndef NDEBUG
ALOGD("----------!!! %s failed to load\n", array[i].mName);
#endif
return -1;
}
}
return 0;
}
4. gRegJNI
static const RegJNIRec gRegJNI[] = {
...
// 这个宏,就相当于创建RegJNIRec结构体并对他进行初始化了
REG_JNI(register_android_os_Debug),
...
}
#ifdef NDEBUG
#define REG_JNI(name) { name }
struct RegJNIRec {
int (*mProc)(JNIEnv*);
};
#else
#define REG_JNI(name) { name, #name }
struct RegJNIRec {
int (*mProc)(JNIEnv*);
const char* mName;
};
#endif
5. register_android_os_Debug
android/frameworks/base/core/jni/android_os_Debug.cpp
int register_android_os_Debug(JNIEnv *env)
{
// 获取java中的Debug.MemoryInfo类
jclass clazz = env->FindClass("android/os/Debug$MemoryInfo");
// Sanity check the number of other statistics expected in Java matches here.
// 获取Debug.MemoryInfo类的NUM_OTHER_STATS变量
jfieldID numOtherStats_field = env->GetStaticFieldID(clazz, "NUM_OTHER_STATS", "I");
jint numOtherStats = env->GetStaticIntField(clazz, numOtherStats_field);
jfieldID numDvkStats_field = env->GetStaticFieldID(clazz, "NUM_DVK_STATS", "I");
jint numDvkStats = env->GetStaticIntField(clazz, numDvkStats_field);
int expectedNumOtherStats = _NUM_HEAP - _NUM_CORE_HEAP;
if ((numOtherStats + numDvkStats) != expectedNumOtherStats) {
jniThrowExceptionFmt(env, "java/lang/RuntimeException",
"android.os.Debug.Meminfo.NUM_OTHER_STATS+android.os.Debug.Meminfo.NUM_DVK_STATS=%d expected %d",
numOtherStats+numDvkStats, expectedNumOtherStats);
return JNI_ERR;
}
// 获取Debug.MemoryInfo类的otherStats变量
otherStats_field = env->GetFieldID(clazz, "otherStats", "[I");
hasSwappedOutPss_field = env->GetFieldID(clazz, "hasSwappedOutPss", "Z");
for (int i=0; i<_NUM_CORE_HEAP; i++) {
stat_fields[i].pss_field =
env->GetFieldID(clazz, stat_field_names[i].pss_name, "I");
stat_fields[i].pssSwappable_field =
env->GetFieldID(clazz, stat_field_names[i].pssSwappable_name, "I");
stat_fields[i].rss_field =
env->GetFieldID(clazz, stat_field_names[i].rss_name, "I");
stat_fields[i].privateDirty_field =
env->GetFieldID(clazz, stat_field_names[i].privateDirty_name, "I");
stat_fields[i].sharedDirty_field =
env->GetFieldID(clazz, stat_field_names[i].sharedDirty_name, "I");
stat_fields[i].privateClean_field =
env->GetFieldID(clazz, stat_field_names[i].privateClean_name, "I");
stat_fields[i].sharedClean_field =
env->GetFieldID(clazz, stat_field_names[i].sharedClean_name, "I");
stat_fields[i].swappedOut_field =
env->GetFieldID(clazz, stat_field_names[i].swappedOut_name, "I");
stat_fields[i].swappedOutPss_field =
env->GetFieldID(clazz, stat_field_names[i].swappedOutPss_name, "I");
}
//这里对JNI进行注册
return jniRegisterNativeMethods(env, "android/os/Debug", gMethods, NELEM(gMethods));
}
参考
1. Android Memory Tracker原理分析
https://blog.csdn.net/msf568834002/article/details/78881341
2. 聊聊Service Call命令
https://www.jianshu.com/p/737427375091
3. dumpsys meminfo 的原理和应用
https://blog.csdn.net/feelabclihu/article/details/105534175
4. proc
https://man7.org/linux/man-pages/man5/proc.5.html
5. Android JNI原理分析
http://gityuan.com/2016/05/28/android-jni/
6. JNI规范
https://blog.caoxudong.info/blog/2017/10/11/jni_functions_note#4.5.7.1