Memtrack hal


概述

1. memtrack hal層的作用

memtrack HAL(Memory Tracker HAL)是用來返回特定於設備的內存使用情況的信息。主要目標是能夠跟蹤無法以任何其他方式跟蹤的內存,例如,由進程分配但未映射到該進程的地址空間的紋理內存。第二個目標是能夠將進程使用的內存分類為GL,圖形等。所有內存大小都必須是實際內存使用情況,統計計算的時候要考慮跨度,位深度,然后四舍五入到頁面大小。
圖片來自(侵刪):https://blog.csdn.net/feelabclihu/article/details/105534175

image

2. dumpsys meminfo字段解析

執行dumpsys meminfo com.android.settings命令:
圖片來自(侵刪):https://blog.csdn.net/feelabclihu/article/details/105534175

image

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM