Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2179a522 authored by Dianne Hackborn's avatar Dianne Hackborn Committed by Android (Google) Code Review
Browse files

Merge "Start really collecting PSS data for process stats."

parents afb292a2 cfc837f7
Loading
Loading
Loading
Loading
+19 −14
Original line number Diff line number Diff line
@@ -552,7 +552,7 @@ public final class ActivityThread {
        private static final String DB_INFO_FORMAT = "  %8s %8s %14s %14s  %s";

        // Formatting for checkin service - update version if row format changes
        private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 2;
        private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 3;

        private void updatePendingConfiguration(Configuration config) {
            synchronized (mPackages) {
@@ -972,43 +972,48 @@ public final class ActivityThread {
                pw.print(memInfo.nativePss); pw.print(',');
                pw.print(memInfo.dalvikPss); pw.print(',');
                pw.print(memInfo.otherPss); pw.print(',');
                pw.print(memInfo.nativePss + memInfo.dalvikPss + memInfo.otherPss); pw.print(',');
                pw.print(memInfo.getTotalPss()); pw.print(',');

                // Heap info - proportional set size
                // Heap info - swappable set size
                pw.print(memInfo.nativeSwappablePss); pw.print(',');
                pw.print(memInfo.dalvikSwappablePss); pw.print(',');
                pw.print(memInfo.otherSwappablePss); pw.print(',');
                pw.print(memInfo.nativeSwappablePss + memInfo.dalvikSwappablePss + memInfo.otherSwappablePss); pw.print(',');
                pw.print(memInfo.getTotalSwappablePss()); pw.print(',');

                // Heap info - shared dirty
                pw.print(memInfo.nativeSharedDirty); pw.print(',');
                pw.print(memInfo.dalvikSharedDirty); pw.print(',');
                pw.print(memInfo.otherSharedDirty); pw.print(',');
                pw.print(memInfo.nativeSharedDirty + memInfo.dalvikSharedDirty
                        + memInfo.otherSharedDirty); pw.print(',');
                pw.print(memInfo.getTotalSharedDirty()); pw.print(',');

                // Heap info - shared clean
                pw.print(memInfo.nativeSharedClean); pw.print(',');
                pw.print(memInfo.dalvikSharedClean); pw.print(',');
                pw.print(memInfo.otherSharedClean); pw.print(',');
                pw.print(memInfo.nativeSharedClean + memInfo.dalvikSharedClean
                        + memInfo.otherSharedClean); pw.print(',');
                pw.print(memInfo.getTotalSharedClean()); pw.print(',');

                // Heap info - private Dirty
                pw.print(memInfo.nativePrivateDirty); pw.print(',');
                pw.print(memInfo.dalvikPrivateDirty); pw.print(',');
                pw.print(memInfo.otherPrivateDirty); pw.print(',');
                pw.print(memInfo.nativePrivateDirty + memInfo.dalvikPrivateDirty
                        + memInfo.otherPrivateDirty); pw.print(',');

                pw.print(memInfo.getTotalPrivateDirty()); pw.print(',');

                // Heap info - private Clean
                pw.print(memInfo.nativePrivateClean); pw.print(',');
                pw.print(memInfo.dalvikPrivateClean); pw.print(',');
                pw.print(memInfo.otherPrivateClean); pw.print(',');
                pw.print(memInfo.nativePrivateClean + memInfo.dalvikPrivateClean
                        + memInfo.otherPrivateClean); pw.print(',');
                pw.print(memInfo.getTotalPrivateClean()); pw.print(',');

                // Heap info - other areas
                for (int i=0; i<Debug.MemoryInfo.NUM_OTHER_STATS; i++) {
                    pw.print(Debug.MemoryInfo.getOtherLabel(i)); pw.print(',');
                    pw.print(memInfo.getOtherPss(i)); pw.print(',');
                    pw.print(memInfo.getOtherSwappablePss(i)); pw.print(',');
                    pw.print(memInfo.getOtherSharedDirty(i)); pw.print(',');
                    pw.print(memInfo.getOtherSharedClean(i)); pw.print(',');
                    pw.print(memInfo.getOtherPrivateDirty(i)); pw.print(',');
                    pw.print(memInfo.getOtherPrivateClean(i)); pw.print(',');
                }

                // Object counts
                pw.print(viewInstanceCount); pw.print(',');
+7 −3
Original line number Diff line number Diff line
@@ -394,12 +394,16 @@ static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid)
    if (fp == 0) return 0;

    while (true) {
        if (fgets(line, 1024, fp) == 0) {
        if (fgets(line, 1024, fp) == NULL) {
            break;
        }

        if (sscanf(line, "Pss: %d kB", &temp) == 1) {
            pss += temp;
        if (strncmp(line, "Pss: ", 5) == 0) {
            char* c = line + 5;
            while (*c != 0 && (*c < '0' || *c > '9')) {
                c++;
            }
            pss += atoi(c);
        }
    }

+229 −45
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.util.ArrayMap;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IAppOpsService;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.ProcessStats;
import com.android.internal.os.TransferPipe;
@@ -266,6 +267,20 @@ public final class ActivityManagerService extends ActivityManagerNative
    // The minimum amount of time between successive GC requests for a process.
    static final int GC_MIN_INTERVAL = 60*1000;
    // The minimum amount of time between successive PSS requests for a process.
    static final int PSS_MIN_INTERVAL = 2*60*1000;
    // The amount of time we will sample PSS of the current top process while the
    // screen is on.
    static final int PSS_TOP_INTERVAL = 5*60*1000;
    // The maximum amount of time for a process to be around until we will take
    // a PSS snapshot on its next oom change.
    static final int PSS_MAX_INTERVAL = 30*60*1000;
    // The minimum amount of time between successive PSS requests for a process.
    static final int FULL_PSS_MIN_INTERVAL = 10*60*1000;
    // The rate at which we check for apps using excessive power -- 15 mins.
    static final int POWER_CHECK_DELAY = (DEBUG_POWER_QUICK ? 2 : 15) * 60*1000;
@@ -495,8 +510,17 @@ public final class ActivityManagerService extends ActivityManagerNative
    /**
     * List of processes that should gc as soon as things are idle.
     */
    final ArrayList<ProcessRecord> mProcessesToGc
            = new ArrayList<ProcessRecord>();
    final ArrayList<ProcessRecord> mProcessesToGc = new ArrayList<ProcessRecord>();
    /**
     * Processes we want to collect PSS data from.
     */
    final ArrayList<ProcessRecord> mPendingPssProcesses = new ArrayList<ProcessRecord>();
    /**
     * Last time we requested PSS data of all processes.
     */
    long mLastFullPssTime = SystemClock.uptimeMillis();
    /**
     * This is the process holding what we currently consider to be
@@ -1480,6 +1504,51 @@ public final class ActivityManagerService extends ActivityManagerNative
        }
    };
    static final int COLLECT_PSS_BG_MSG = 1;
    final Handler mBgHandler = new Handler(BackgroundThread.getHandler().getLooper()) {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case COLLECT_PSS_BG_MSG: {
                int i=0;
                long start = SystemClock.uptimeMillis();
                do {
                    ProcessRecord proc;
                    int oomAdj;
                    int pid;
                    synchronized (ActivityManagerService.this) {
                        if (i >= mPendingPssProcesses.size()) {
                            Slog.i(TAG, "Collected PSS of " + i + " processes in "
                                    + (SystemClock.uptimeMillis()-start) + "ms");
                            mPendingPssProcesses.clear();
                            return;
                        }
                        proc = mPendingPssProcesses.get(i);
                        if (proc.thread != null) {
                            oomAdj = proc.setAdj;
                            pid = proc.pid;
                            i++;
                        } else {
                            proc = null;
                            oomAdj = 0;
                            pid = 0;
                        }
                    }
                    if (proc != null) {
                        long pss = Debug.getPss(pid);
                        synchronized (ActivityManagerService.this) {
                            if (proc.thread != null && proc.setAdj == oomAdj && proc.pid == pid) {
                                proc.baseProcessTracker.addPss(pss, true);
                            }
                        }
                    }
                } while (true);
            }
            }
        }
    };
    public static void setSystemProcess() {
        try {
            ActivityManagerService m = mSelf;
@@ -3906,8 +3975,24 @@ public final class ActivityManagerService extends ActivityManagerNative
        enforceNotIsolatedCaller("getProcessMemoryInfo");
        Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
        for (int i=pids.length-1; i>=0; i--) {
            ProcessRecord proc;
            int oomAdj;
            synchronized (this) {
                synchronized (mPidsSelfLocked) {
                    proc = mPidsSelfLocked.get(pids[i]);
                    oomAdj = proc != null ? proc.setAdj : 0;
                }
            }
            infos[i] = new Debug.MemoryInfo();
            Debug.getMemoryInfo(pids[i], infos[i]);
            if (proc != null) {
                synchronized (this) {
                    if (proc.thread != null && proc.setAdj == oomAdj) {
                        // Record this for posterity if the process has been stable.
                        proc.baseProcessTracker.addPss(infos[i].getTotalPss(), false);
                    }
                }
            }
        }
        return infos;
    }
@@ -3917,7 +4002,23 @@ public final class ActivityManagerService extends ActivityManagerNative
        enforceNotIsolatedCaller("getProcessPss");
        long[] pss = new long[pids.length];
        for (int i=pids.length-1; i>=0; i--) {
            ProcessRecord proc;
            int oomAdj;
            synchronized (this) {
                synchronized (mPidsSelfLocked) {
                    proc = mPidsSelfLocked.get(pids[i]);
                    oomAdj = proc != null ? proc.setAdj : 0;
                }
            }
            pss[i] = Debug.getPss(pids[i]);
            if (proc != null) {
                synchronized (this) {
                    if (proc.thread != null && proc.setAdj == oomAdj) {
                        // Record this for posterity if the process has been stable.
                        proc.baseProcessTracker.addPss(pss[i], false);
                    }
                }
            }
        }
        return pss;
    }
@@ -4350,7 +4451,7 @@ public final class ActivityManagerService extends ActivityManagerNative
            thread.asBinder().linkToDeath(adr, 0);
            app.deathRecipient = adr;
        } catch (RemoteException e) {
            app.resetPackageList();
            app.resetPackageList(mProcessTracker);
            startProcessLocked(app, "link fail", processName);
            return false;
        }
@@ -4442,7 +4543,7 @@ public final class ActivityManagerService extends ActivityManagerNative
            // an infinite loop of restarting processes...
            Slog.w(TAG, "Exception thrown during bind!", e);
            app.resetPackageList();
            app.resetPackageList(mProcessTracker);
            app.unlinkDeathRecipient();
            startProcessLocked(app, "bind fail", processName);
            return false;
@@ -4630,8 +4731,19 @@ public final class ActivityManagerService extends ActivityManagerNative
                        final int userId = mStartedUsers.keyAt(i);
                        Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
                        intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
                        broadcastIntentLocked(null, null, intent,
                                null, null, 0, null, null,
                        broadcastIntentLocked(null, null, intent, null,
                                new IIntentReceiver.Stub() {
                                    @Override
                                    public void performReceive(Intent intent, int resultCode,
                                            String data, Bundle extras, boolean ordered,
                                            boolean sticky, int sendingUser) {
                                        synchronized (ActivityManagerService.this) {
                                            requestPssAllProcsLocked(SystemClock.uptimeMillis(),
                                                    true);
                                        }
                                    }
                                },
                                0, null, null,
                                android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
                                AppOpsManager.OP_NONE, false, false, MY_PID, Process.SYSTEM_UID,
                                userId);
@@ -10956,7 +11068,7 @@ public final class ActivityManagerService extends ActivityManagerNative
        long uptime = SystemClock.uptimeMillis();
        long realtime = SystemClock.elapsedRealtime();
        if (procs.size() == 1 || isCheckinRequest) {
        if (!brief && !oomOnly && (procs.size() == 1 || isCheckinRequest)) {
            dumpDetails = true;
        }
@@ -10982,17 +11094,24 @@ public final class ActivityManagerService extends ActivityManagerNative
        long totalPss = 0;
        Debug.MemoryInfo mi = null;
        for (int i = procs.size() - 1 ; i >= 0 ; i--) {
            ProcessRecord r = procs.get(i);
            if (r.thread != null) {
            IApplicationThread thread;
            int oomAdj;
            synchronized (this) {
                thread = r.thread;
                oomAdj = r.setAdj;
            }
            if (thread != null) {
                if (!isCheckinRequest && dumpDetails) {
                    pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
                    pw.flush();
                }
                Debug.MemoryInfo mi = null;
                if (dumpDetails) {
                    try {
                        mi = r.thread.dumpMemInfo(fd, isCheckinRequest, true, dumpDalvik, innerArgs);
                        mi = null;
                        mi = thread.dumpMemInfo(fd, isCheckinRequest, true, dumpDalvik, innerArgs);
                    } catch (RemoteException e) {
                        if (!isCheckinRequest) {
                            pw.println("Got RemoteException!");
@@ -11000,21 +11119,31 @@ public final class ActivityManagerService extends ActivityManagerNative
                        }
                    }
                } else {
                    if (mi == null) {
                        mi = new Debug.MemoryInfo();
                    }
                    if (!brief && !oomOnly) {
                        Debug.getMemoryInfo(r.pid, mi);
                    } else {
                        mi.dalvikPss = (int)Debug.getPss(r.pid);
                    }
                }
                final long myTotalPss = mi.getTotalPss();
                synchronized (this) {
                    if (r.thread != null && oomAdj == r.setAdj) {
                        // Record this for posterity if the process has been stable.
                        r.baseProcessTracker.addPss(myTotalPss, true);
                    }
                }
                if (!isCheckinRequest && mi != null) {
                    long myTotalPss = mi.getTotalPss();
                    totalPss += myTotalPss;
                    MemItem pssItem = new MemItem(r.processName + " (pid " + r.pid + ")",
                            r.processName, myTotalPss, 0);
                    procMems.add(pssItem);
                    synchronized (this) {
                        r.baseProcessTracker.addPss(myTotalPss);
                    }
                    nativePss += mi.nativePss;
                    dalvikPss += mi.dalvikPss;
                    otherPss += mi.otherPss;
@@ -11092,7 +11221,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                            }
                        }
                        for (int j=0; j<miCat.subitems.size(); j++) {
                            MemItem mi = miCat.subitems.get(j);
                            MemItem memi = miCat.subitems.get(j);
                            if (j > 0) {
                                if (outTag != null) {
                                    outTag.append(" ");
@@ -11102,10 +11231,10 @@ public final class ActivityManagerService extends ActivityManagerNative
                                }
                            }
                            if (outTag != null && miCat.id <= ProcessList.FOREGROUND_APP_ADJ) {
                                appendMemBucket(outTag, mi.pss, mi.shortLabel, false);
                                appendMemBucket(outTag, memi.pss, memi.shortLabel, false);
                            }
                            if (outStack != null) {
                                appendMemBucket(outStack, mi.pss, mi.shortLabel, true);
                                appendMemBucket(outStack, memi.pss, memi.shortLabel, true);
                            }
                        }
                        if (outStack != null && miCat.id >= ProcessList.FOREGROUND_APP_ADJ) {
@@ -11131,7 +11260,7 @@ public final class ActivityManagerService extends ActivityManagerNative
            }
            pw.println("Total PSS by OOM adjustment:");
            dumpMemItems(pw, "  ", oomMems, false);
            if (!oomOnly) {
            if (!brief && !oomOnly) {
                PrintWriter out = categoryPw != null ? categoryPw : pw;
                out.println();
                out.println("Total PSS by category:");
@@ -11139,6 +11268,7 @@ public final class ActivityManagerService extends ActivityManagerNative
            }
            pw.println();
            pw.print("Total PSS: "); pw.print(totalPss); pw.println(" kB");
            if (!brief) {
                final int[] SINGLE_LONG_FORMAT = new int[] {
                    Process.PROC_SPACE_TERM|Process.PROC_OUT_LONG
                };
@@ -11164,6 +11294,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                        pw.print(voltile); pw.println(" kB volatile");
            }
        }
    }
    /**
     * Searches array of arguments for the specified string
@@ -11258,6 +11389,7 @@ public final class ActivityManagerService extends ActivityManagerNative
        }
        mProcessesToGc.remove(app);
        mPendingPssProcesses.remove(app);
        
        // Dismiss any open dialogs.
        if (app.crashDialog != null && !app.forceCrashReport) {
@@ -11276,7 +11408,7 @@ public final class ActivityManagerService extends ActivityManagerNative
        app.crashing = false;
        app.notResponding = false;
        
        app.resetPackageList();
        app.resetPackageList(mProcessTracker);
        app.unlinkDeathRecipient();
        app.thread = null;
        app.forcingToForeground = null;
@@ -13770,6 +13902,41 @@ public final class ActivityManagerService extends ActivityManagerNative
        return app.curRawAdj;
    }
    /**
     * Schedule PSS collection of a process.
     */
    void requestPssLocked(ProcessRecord proc, long now, boolean always) {
        if (!always && now < (proc.lastPssTime+PSS_MIN_INTERVAL)) {
            return;
        }
        if (mPendingPssProcesses.contains(proc)) {
            return;
        }
        proc.lastPssTime = now;
        if (mPendingPssProcesses.size() == 0) {
            mBgHandler.sendEmptyMessage(COLLECT_PSS_BG_MSG);
        }
        mPendingPssProcesses.add(proc);
    }
    /**
     * Schedule PSS collection of all processes.
     */
    void requestPssAllProcsLocked(long now, boolean always) {
        if (!always && now < (mLastFullPssTime+FULL_PSS_MIN_INTERVAL)) {
            return;
        }
        mLastFullPssTime = now;
        mPendingPssProcesses.ensureCapacity(mLruProcesses.size());
        mPendingPssProcesses.clear();
        for (int i=mLruProcesses.size()-1; i>=0; i--) {
            ProcessRecord app = mLruProcesses.get(i);
            app.lastPssTime = now;
            mPendingPssProcesses.add(app);
        }
        mBgHandler.sendEmptyMessage(COLLECT_PSS_BG_MSG);
    }
    /**
     * Ask a given process to GC right now.
     */
@@ -13981,6 +14148,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                            + " during " + realtimeSince);
                    EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
                            app.processName, app.setAdj, "excessive wake lock");
                    app.baseProcessTracker.reportExcessiveWake(app.pkgList);
                    Process.killProcessQuiet(app.pid);
                } else if (doCpuKills && uptimeSince > 0
                        && ((cputimeUsed*100)/uptimeSince) >= 50) {
@@ -13993,6 +14161,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                            + " during " + uptimeSince);
                    EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
                            app.processName, app.setAdj, "excessive cpu");
                    app.baseProcessTracker.reportExcessiveCpu(app.pkgList);
                    Process.killProcessQuiet(app.pid);
                } else {
                    app.lastWakeTime = wtime;
@@ -14034,11 +14203,23 @@ public final class ActivityManagerService extends ActivityManagerNative
            app.setRawAdj = app.curRawAdj;
        }
        if (app == TOP_APP && now > (app.lastPssTime+PSS_TOP_INTERVAL)) {
            requestPssLocked(app, now, true);
        }
        if (app.curAdj != app.setAdj) {
            if (Process.setOomAdj(app.pid, app.curAdj)) {
                if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
                    TAG, "Set " + app.pid + " " + app.processName +
                    " adj " + app.curAdj + ": " + app.adjType);
                if (app.setAdj == ProcessList.SERVICE_ADJ
                        && app.curAdj == ProcessList.SERVICE_B_ADJ) {
                    // If a service is dropping to the B list, it has been running for
                    // a while, take a PSS snapshot.
                    requestPssLocked(app, now, false);
                } else if (now > (app.lastPssTime+PSS_MAX_INTERVAL)) {
                    requestPssLocked(app, now, true);
                }
                app.setAdj = app.curAdj;
                app.setAdjChanged = true;
                if (!doingAll) {
@@ -14428,6 +14609,9 @@ public final class ActivityManagerService extends ActivityManagerNative
                }
            }
        }
        if (allChanged) {
            requestPssAllProcsLocked(now, false);
        }
        if (DEBUG_OOM_ADJ) {
            Slog.d(TAG, "Did OOM ADJ in " + (SystemClock.uptimeMillis()-now) + "ms");
+1 −0
Original line number Diff line number Diff line
@@ -1707,6 +1707,7 @@ public final class ActivityStackSupervisor {
                r.idle = true;
                if (allResumedActivitiesIdle()) {
                    mService.scheduleAppGcsLocked();
                    mService.requestPssLocked(r.app, SystemClock.uptimeMillis(), false);
                }
                if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
                    sendThumbnail = r.app.thread;
+18 −12

File changed.

Preview size limit exceeded, changes collapsed.

Loading