Loading core/java/android/app/ActivityManagerInternal.java +23 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Executor; import java.util.function.BiFunction; /** Loading Loading @@ -1267,6 +1268,28 @@ public abstract class ActivityManagerInternal { */ public abstract boolean shouldDelayHomeLaunch(int userId); /** * Used to track when a process is frozen or unfrozen. */ public interface FrozenProcessListener { /** * Called when a process is frozen. */ void onProcessFrozen(int pid); /** * Called when a process is unfrozen. */ void onProcessUnfrozen(int pid); } /** * Register the frozen process event listener callback. The same listener may be reused for * multiple pids. Listeners are dropped when the process dies. */ public abstract void addFrozenProcessListener(int pid, @NonNull Executor executor, @NonNull FrozenProcessListener listener); /** * Add a startup timestamp to the most recent start of the specified process. * Loading services/core/java/com/android/server/am/ActivityManagerService.java +17 −0 Original line number Diff line number Diff line Loading @@ -18443,6 +18443,23 @@ public class ActivityManagerService extends IActivityManager.Stub public final class LocalService extends ActivityManagerInternal implements ActivityManagerLocal { @Override public void addFrozenProcessListener(int pid, @NonNull Executor executor, @NonNull FrozenProcessListener listener) { Objects.requireNonNull(executor); Objects.requireNonNull(listener); synchronized (mProcLock) { final ProcessRecord app; synchronized (mPidsSelfLocked) { app = mPidsSelfLocked.get(pid); } if (app != null) { mOomAdjuster.mCachedAppOptimizer.addFrozenProcessListener(app, executor, listener); } } } @Override public List<PendingIntentStats> getPendingIntentStats() { return mPendingIntentController.dumpPendingIntentStatsForStatsd(); services/core/java/com/android/server/am/ActivityManagerShellCommand.java +1 −2 Original line number Diff line number Diff line Loading @@ -1234,8 +1234,7 @@ final class ActivityManagerShellCommand extends ShellCommand { if (freeze) { mInternal.mOomAdjuster.mCachedAppOptimizer.forceFreezeAppAsyncLSP(proc); } else { mInternal.mOomAdjuster.mCachedAppOptimizer.unfreezeAppInternalLSP(proc, 0, true); mInternal.mOomAdjuster.mCachedAppOptimizer.unfreezeAppLSP(proc, 0, true); } } } Loading services/core/java/com/android/server/am/CachedAppOptimizer.java +40 −9 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import android.annotation.IntDef; import android.annotation.UptimeMillisLong; import android.app.ActivityManager; import android.app.ActivityManagerInternal.FrozenProcessListener; import android.app.ActivityManagerInternal.OomAdjReason; import android.app.ActivityThread; import android.app.ApplicationExitInfo; Loading Loading @@ -99,6 +100,7 @@ import java.util.LinkedList; import java.util.Map; import java.util.Random; import java.util.Set; import java.util.concurrent.Executor; public final class CachedAppOptimizer { Loading Loading @@ -1406,8 +1408,15 @@ public final class CachedAppOptimizer { } } /** * Returns true if the app was frozen and became unfrozen, otherwise false. * * Do not call this directly. It will unfreeze a process but it will not send out any * notifications. Instead call unfreezeAppLSP(). */ @GuardedBy({"mAm", "mProcLock", "mFreezerLock"}) void unfreezeAppInternalLSP(ProcessRecord app, @UnfreezeReason int reason, boolean force) { private boolean unfreezeAppInternalLSP(ProcessRecord app, @UnfreezeReason int reason, boolean force) { final int pid = app.getPid(); final ProcessCachedOptimizerRecord opt = app.mOptRecord; boolean sticky = opt.isFreezeSticky(); Loading @@ -1418,7 +1427,7 @@ public final class CachedAppOptimizer { "Skip unfreezing because frozen state is sticky pid=" + pid + " " + app.processName); } return; return false; } boolean processFreezableChangeReported = false; if (opt.isPendingFreeze()) { Loading @@ -1440,7 +1449,7 @@ public final class CachedAppOptimizer { opt.setFreezerOverride(false); if (pid == 0 || !opt.isFrozen()) { return; return false; } // Unfreeze the binder interface first, to avoid transactions triggered by timers fired Loading Loading @@ -1473,7 +1482,7 @@ public final class CachedAppOptimizer { } if (processKilled) { return; return false; } if (!processFreezableChangeReported) { reportProcessFreezableChangedLocked(app); Loading @@ -1489,7 +1498,7 @@ public final class CachedAppOptimizer { app.killLocked("Unable to unfreeze", ApplicationExitInfo.REASON_FREEZER, ApplicationExitInfo.SUBREASON_FREEZER_BINDER_IOCTL, true); return; return false; } try { Loading @@ -1512,16 +1521,27 @@ public final class CachedAppOptimizer { pid, (int) Math.min(opt.getFreezeUnfreezeTime() - freezeTime, Integer.MAX_VALUE), new Pair<ProcessRecord, Integer>(app, reason))); return true; } return false; } @GuardedBy({"mAm", "mProcLock"}) void unfreezeAppLSP(ProcessRecord app, @UnfreezeReason int reason) { void unfreezeAppLSP(ProcessRecord app, @UnfreezeReason int reason, boolean force) { final boolean shouldDispatch; synchronized (mFreezerLock) { unfreezeAppInternalLSP(app, reason, false); shouldDispatch = unfreezeAppInternalLSP(app, reason, force); } if (shouldDispatch) { app.mOptRecord.dispatchUnfrozenEvent(); } } @GuardedBy({"mAm", "mProcLock"}) void unfreezeAppLSP(ProcessRecord app, @UnfreezeReason int reason) { unfreezeAppLSP(app, reason, false); } /** * This quick function works around the race condition between WM/ATMS and AMS, allowing * the former to directly unfreeze a frozen process before the latter runs updateOomAdj. Loading @@ -1530,8 +1550,9 @@ public final class CachedAppOptimizer { * @param pid pid of the process to be unfrozen */ void unfreezeProcess(int pid, @OomAdjReason int reason) { final ProcessRecord app; synchronized (mFreezerLock) { ProcessRecord app = mFrozenProcesses.get(pid); app = mFrozenProcesses.get(pid); if (app == null) { return; } Loading @@ -1550,6 +1571,7 @@ public final class CachedAppOptimizer { Slog.e(TAG_AM, "Unable to quick unfreeze " + pid); } } app.mOptRecord.dispatchUnfrozenEvent(); } /** Loading Loading @@ -2390,6 +2412,7 @@ public final class CachedAppOptimizer { } }); } opt.dispatchFrozenEvent(); } private void reportUnfreeze(ProcessRecord app, int pid, int frozenDuration, Loading Loading @@ -2549,7 +2572,7 @@ public final class CachedAppOptimizer { if (freeze) { forceFreezeAppAsyncLSP(proc); } else { unfreezeAppInternalLSP(proc, UNFREEZE_REASON_NONE, true); unfreezeAppLSP(proc, UNFREEZE_REASON_NONE, true); } } } Loading Loading @@ -2652,4 +2675,12 @@ public final class CachedAppOptimizer { exception -> Slog.e(TAG_AM, "Unable to parse binderfs stats")); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } /** * Register a callback to notify when a process's frozen state changes. */ public void addFrozenProcessListener(ProcessRecord app, Executor executor, FrozenProcessListener listener) { app.mOptRecord.addFrozenProcessListener(executor, listener); } } services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java +30 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package com.android.server.am; import android.annotation.IntDef; import android.annotation.UptimeMillisLong; import android.app.ActivityManagerInternal.OomAdjReason; import android.app.ActivityManagerInternal.FrozenProcessListener; import android.util.Pair; import android.util.TimeUtils; import com.android.internal.annotations.GuardedBy; Loading @@ -29,6 +31,8 @@ import dalvik.annotation.optimization.NeverCompile; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; /** * The state info of app when it's cached, used by the optimizer. Loading Loading @@ -165,6 +169,12 @@ final class ProcessCachedOptimizerRecord { @GuardedBy("mProcLock") private long mLastUsedTimeout; /** * The list of callbacks for this process whenever it is frozen or unfrozen. */ final CopyOnWriteArrayList<Pair<Executor, FrozenProcessListener>> mFrozenProcessListeners = new CopyOnWriteArrayList<>(); @GuardedBy("mProcLock") long getLastCompactTime() { return mLastCompactTime; Loading Loading @@ -386,6 +396,22 @@ final class ProcessCachedOptimizerRecord { mFreezeExempt = exempt; } void addFrozenProcessListener(Executor executor, FrozenProcessListener listener) { mFrozenProcessListeners.add(new Pair<Executor, FrozenProcessListener>(executor, listener)); } void dispatchFrozenEvent() { mFrozenProcessListeners.forEach((pair) -> { pair.first.execute(() -> pair.second.onProcessFrozen(mApp.mPid)); }); } void dispatchUnfrozenEvent() { mFrozenProcessListeners.forEach((pair) -> { pair.first.execute(() -> pair.second.onProcessUnfrozen(mApp.mPid)); }); } ProcessCachedOptimizerRecord(ProcessRecord app) { mApp = app; mProcLock = app.mService.mProcLock; Loading @@ -409,6 +435,10 @@ final class ProcessCachedOptimizerRecord { pw.print(" " + IS_FROZEN + "="); pw.println(mFrozen); pw.print(prefix); pw.print("earliestFreezableTimeMs="); TimeUtils.formatDuration(mEarliestFreezableTimeMillis, nowUptime, pw); if (!mFrozenProcessListeners.isEmpty()) { pw.print(" mFrozenProcessListeners="); mFrozenProcessListeners.forEach((pair) -> pw.print(pair.second + ", ")); } pw.println(); } } Loading
core/java/android/app/ActivityManagerInternal.java +23 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Executor; import java.util.function.BiFunction; /** Loading Loading @@ -1267,6 +1268,28 @@ public abstract class ActivityManagerInternal { */ public abstract boolean shouldDelayHomeLaunch(int userId); /** * Used to track when a process is frozen or unfrozen. */ public interface FrozenProcessListener { /** * Called when a process is frozen. */ void onProcessFrozen(int pid); /** * Called when a process is unfrozen. */ void onProcessUnfrozen(int pid); } /** * Register the frozen process event listener callback. The same listener may be reused for * multiple pids. Listeners are dropped when the process dies. */ public abstract void addFrozenProcessListener(int pid, @NonNull Executor executor, @NonNull FrozenProcessListener listener); /** * Add a startup timestamp to the most recent start of the specified process. * Loading
services/core/java/com/android/server/am/ActivityManagerService.java +17 −0 Original line number Diff line number Diff line Loading @@ -18443,6 +18443,23 @@ public class ActivityManagerService extends IActivityManager.Stub public final class LocalService extends ActivityManagerInternal implements ActivityManagerLocal { @Override public void addFrozenProcessListener(int pid, @NonNull Executor executor, @NonNull FrozenProcessListener listener) { Objects.requireNonNull(executor); Objects.requireNonNull(listener); synchronized (mProcLock) { final ProcessRecord app; synchronized (mPidsSelfLocked) { app = mPidsSelfLocked.get(pid); } if (app != null) { mOomAdjuster.mCachedAppOptimizer.addFrozenProcessListener(app, executor, listener); } } } @Override public List<PendingIntentStats> getPendingIntentStats() { return mPendingIntentController.dumpPendingIntentStatsForStatsd();
services/core/java/com/android/server/am/ActivityManagerShellCommand.java +1 −2 Original line number Diff line number Diff line Loading @@ -1234,8 +1234,7 @@ final class ActivityManagerShellCommand extends ShellCommand { if (freeze) { mInternal.mOomAdjuster.mCachedAppOptimizer.forceFreezeAppAsyncLSP(proc); } else { mInternal.mOomAdjuster.mCachedAppOptimizer.unfreezeAppInternalLSP(proc, 0, true); mInternal.mOomAdjuster.mCachedAppOptimizer.unfreezeAppLSP(proc, 0, true); } } } Loading
services/core/java/com/android/server/am/CachedAppOptimizer.java +40 −9 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import android.annotation.IntDef; import android.annotation.UptimeMillisLong; import android.app.ActivityManager; import android.app.ActivityManagerInternal.FrozenProcessListener; import android.app.ActivityManagerInternal.OomAdjReason; import android.app.ActivityThread; import android.app.ApplicationExitInfo; Loading Loading @@ -99,6 +100,7 @@ import java.util.LinkedList; import java.util.Map; import java.util.Random; import java.util.Set; import java.util.concurrent.Executor; public final class CachedAppOptimizer { Loading Loading @@ -1406,8 +1408,15 @@ public final class CachedAppOptimizer { } } /** * Returns true if the app was frozen and became unfrozen, otherwise false. * * Do not call this directly. It will unfreeze a process but it will not send out any * notifications. Instead call unfreezeAppLSP(). */ @GuardedBy({"mAm", "mProcLock", "mFreezerLock"}) void unfreezeAppInternalLSP(ProcessRecord app, @UnfreezeReason int reason, boolean force) { private boolean unfreezeAppInternalLSP(ProcessRecord app, @UnfreezeReason int reason, boolean force) { final int pid = app.getPid(); final ProcessCachedOptimizerRecord opt = app.mOptRecord; boolean sticky = opt.isFreezeSticky(); Loading @@ -1418,7 +1427,7 @@ public final class CachedAppOptimizer { "Skip unfreezing because frozen state is sticky pid=" + pid + " " + app.processName); } return; return false; } boolean processFreezableChangeReported = false; if (opt.isPendingFreeze()) { Loading @@ -1440,7 +1449,7 @@ public final class CachedAppOptimizer { opt.setFreezerOverride(false); if (pid == 0 || !opt.isFrozen()) { return; return false; } // Unfreeze the binder interface first, to avoid transactions triggered by timers fired Loading Loading @@ -1473,7 +1482,7 @@ public final class CachedAppOptimizer { } if (processKilled) { return; return false; } if (!processFreezableChangeReported) { reportProcessFreezableChangedLocked(app); Loading @@ -1489,7 +1498,7 @@ public final class CachedAppOptimizer { app.killLocked("Unable to unfreeze", ApplicationExitInfo.REASON_FREEZER, ApplicationExitInfo.SUBREASON_FREEZER_BINDER_IOCTL, true); return; return false; } try { Loading @@ -1512,16 +1521,27 @@ public final class CachedAppOptimizer { pid, (int) Math.min(opt.getFreezeUnfreezeTime() - freezeTime, Integer.MAX_VALUE), new Pair<ProcessRecord, Integer>(app, reason))); return true; } return false; } @GuardedBy({"mAm", "mProcLock"}) void unfreezeAppLSP(ProcessRecord app, @UnfreezeReason int reason) { void unfreezeAppLSP(ProcessRecord app, @UnfreezeReason int reason, boolean force) { final boolean shouldDispatch; synchronized (mFreezerLock) { unfreezeAppInternalLSP(app, reason, false); shouldDispatch = unfreezeAppInternalLSP(app, reason, force); } if (shouldDispatch) { app.mOptRecord.dispatchUnfrozenEvent(); } } @GuardedBy({"mAm", "mProcLock"}) void unfreezeAppLSP(ProcessRecord app, @UnfreezeReason int reason) { unfreezeAppLSP(app, reason, false); } /** * This quick function works around the race condition between WM/ATMS and AMS, allowing * the former to directly unfreeze a frozen process before the latter runs updateOomAdj. Loading @@ -1530,8 +1550,9 @@ public final class CachedAppOptimizer { * @param pid pid of the process to be unfrozen */ void unfreezeProcess(int pid, @OomAdjReason int reason) { final ProcessRecord app; synchronized (mFreezerLock) { ProcessRecord app = mFrozenProcesses.get(pid); app = mFrozenProcesses.get(pid); if (app == null) { return; } Loading @@ -1550,6 +1571,7 @@ public final class CachedAppOptimizer { Slog.e(TAG_AM, "Unable to quick unfreeze " + pid); } } app.mOptRecord.dispatchUnfrozenEvent(); } /** Loading Loading @@ -2390,6 +2412,7 @@ public final class CachedAppOptimizer { } }); } opt.dispatchFrozenEvent(); } private void reportUnfreeze(ProcessRecord app, int pid, int frozenDuration, Loading Loading @@ -2549,7 +2572,7 @@ public final class CachedAppOptimizer { if (freeze) { forceFreezeAppAsyncLSP(proc); } else { unfreezeAppInternalLSP(proc, UNFREEZE_REASON_NONE, true); unfreezeAppLSP(proc, UNFREEZE_REASON_NONE, true); } } } Loading Loading @@ -2652,4 +2675,12 @@ public final class CachedAppOptimizer { exception -> Slog.e(TAG_AM, "Unable to parse binderfs stats")); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } /** * Register a callback to notify when a process's frozen state changes. */ public void addFrozenProcessListener(ProcessRecord app, Executor executor, FrozenProcessListener listener) { app.mOptRecord.addFrozenProcessListener(executor, listener); } }
services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java +30 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package com.android.server.am; import android.annotation.IntDef; import android.annotation.UptimeMillisLong; import android.app.ActivityManagerInternal.OomAdjReason; import android.app.ActivityManagerInternal.FrozenProcessListener; import android.util.Pair; import android.util.TimeUtils; import com.android.internal.annotations.GuardedBy; Loading @@ -29,6 +31,8 @@ import dalvik.annotation.optimization.NeverCompile; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; /** * The state info of app when it's cached, used by the optimizer. Loading Loading @@ -165,6 +169,12 @@ final class ProcessCachedOptimizerRecord { @GuardedBy("mProcLock") private long mLastUsedTimeout; /** * The list of callbacks for this process whenever it is frozen or unfrozen. */ final CopyOnWriteArrayList<Pair<Executor, FrozenProcessListener>> mFrozenProcessListeners = new CopyOnWriteArrayList<>(); @GuardedBy("mProcLock") long getLastCompactTime() { return mLastCompactTime; Loading Loading @@ -386,6 +396,22 @@ final class ProcessCachedOptimizerRecord { mFreezeExempt = exempt; } void addFrozenProcessListener(Executor executor, FrozenProcessListener listener) { mFrozenProcessListeners.add(new Pair<Executor, FrozenProcessListener>(executor, listener)); } void dispatchFrozenEvent() { mFrozenProcessListeners.forEach((pair) -> { pair.first.execute(() -> pair.second.onProcessFrozen(mApp.mPid)); }); } void dispatchUnfrozenEvent() { mFrozenProcessListeners.forEach((pair) -> { pair.first.execute(() -> pair.second.onProcessUnfrozen(mApp.mPid)); }); } ProcessCachedOptimizerRecord(ProcessRecord app) { mApp = app; mProcLock = app.mService.mProcLock; Loading @@ -409,6 +435,10 @@ final class ProcessCachedOptimizerRecord { pw.print(" " + IS_FROZEN + "="); pw.println(mFrozen); pw.print(prefix); pw.print("earliestFreezableTimeMs="); TimeUtils.formatDuration(mEarliestFreezableTimeMillis, nowUptime, pw); if (!mFrozenProcessListeners.isEmpty()) { pw.print(" mFrozenProcessListeners="); mFrozenProcessListeners.forEach((pair) -> pw.print(pair.second + ", ")); } pw.println(); } }