Loading services/core/java/com/android/server/am/ActivityManagerConstants.java +10 −0 Original line number Diff line number Diff line Loading @@ -87,6 +87,7 @@ final class ActivityManagerConstants extends ContentObserver { static final String KEY_PROCESS_START_ASYNC = "process_start_async"; static final String KEY_MEMORY_INFO_THROTTLE_TIME = "memory_info_throttle_time"; static final String KEY_TOP_TO_FGS_GRACE_DURATION = "top_to_fgs_grace_duration"; static final String KEY_PENDINGINTENT_WARNING_THRESHOLD = "pendingintent_warning_threshold"; private static final int DEFAULT_MAX_CACHED_PROCESSES = 32; private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000; Loading Loading @@ -119,6 +120,7 @@ final class ActivityManagerConstants extends ContentObserver { private static final boolean DEFAULT_PROCESS_START_ASYNC = true; private static final long DEFAULT_MEMORY_INFO_THROTTLE_TIME = 5*60*1000; private static final long DEFAULT_TOP_TO_FGS_GRACE_DURATION = 15 * 1000; private static final int DEFAULT_PENDINGINTENT_WARNING_THRESHOLD = 2000; // Flag stored in the DeviceConfig API. /** Loading Loading @@ -328,6 +330,12 @@ final class ActivityManagerConstants extends ContentObserver { */ public ArraySet<Integer> IMPERCEPTIBLE_KILL_EXEMPT_PROC_STATES = new ArraySet<Integer>(); /** * The threshold for the amount of PendingIntent for each UID, there will be * warning logs if the number goes beyond this threshold. */ public int PENDINGINTENT_WARNING_THRESHOLD = DEFAULT_PENDINGINTENT_WARNING_THRESHOLD; private List<String> mDefaultImperceptibleKillExemptPackages; private List<Integer> mDefaultImperceptibleKillExemptProcStates; Loading Loading @@ -562,6 +570,8 @@ final class ActivityManagerConstants extends ContentObserver { DEFAULT_MEMORY_INFO_THROTTLE_TIME); TOP_TO_FGS_GRACE_DURATION = mParser.getDurationMillis(KEY_TOP_TO_FGS_GRACE_DURATION, DEFAULT_TOP_TO_FGS_GRACE_DURATION); PENDINGINTENT_WARNING_THRESHOLD = mParser.getInt(KEY_PENDINGINTENT_WARNING_THRESHOLD, DEFAULT_PENDINGINTENT_WARNING_THRESHOLD); // For new flags that are intended for server-side experiments, please use the new // DeviceConfig package. Loading services/core/java/com/android/server/am/ActivityManagerService.java +3 −2 Original line number Diff line number Diff line Loading @@ -2543,7 +2543,8 @@ public class ActivityManagerService extends IActivityManager.Stub mUiHandler = injector.getUiHandler(null /* service */); mUserController = hasHandlerThread ? new UserController(this) : null; mPendingIntentController = hasHandlerThread ? new PendingIntentController(handlerThread.getLooper(), mUserController) : null; ? new PendingIntentController(handlerThread.getLooper(), mUserController, mConstants) : null; mProcStartHandlerThread = null; mProcStartHandler = null; mHiddenApiBlacklist = null; Loading Loading @@ -2640,7 +2641,7 @@ public class ActivityManagerService extends IActivityManager.Stub mUserController = new UserController(this); mPendingIntentController = new PendingIntentController( mHandlerThread.getLooper(), mUserController); mHandlerThread.getLooper(), mUserController, mConstants); if (SystemProperties.getInt("sys.use_fifo_ui", 0) != 0) { mUseFifoUiScheduling = true; Loading services/core/java/com/android/server/am/PendingIntentController.java +97 −1 Original line number Diff line number Diff line Loading @@ -41,8 +41,12 @@ import android.os.RemoteException; import android.os.UserHandle; import android.util.ArrayMap; import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.IResultReceiver; import com.android.internal.util.RingBuffer; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.AlarmManagerInternal; import com.android.server.LocalServices; Loading @@ -52,6 +56,7 @@ import com.android.server.wm.SafeActivityOptions; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; Loading @@ -66,6 +71,9 @@ public class PendingIntentController { private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentController" : TAG_AM; private static final String TAG_MU = TAG + POSTFIX_MU; /** @see {@link #mRecentIntentsPerUid}. */ private static final int RECENT_N = 10; /** Lock for internal state. */ final Object mLock = new Object(); final Handler mH; Loading @@ -77,10 +85,22 @@ public class PendingIntentController { final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords = new HashMap<>(); PendingIntentController(Looper looper, UserController userController) { /** The number of PendingIntentRecord per uid */ @GuardedBy("mLock") private final SparseIntArray mIntentsPerUid = new SparseIntArray(); /** The recent PendingIntentRecord, up to {@link #RECENT_N} per uid */ @GuardedBy("mLock") private final SparseArray<RingBuffer<String>> mRecentIntentsPerUid = new SparseArray<>(); private final ActivityManagerConstants mConstants; PendingIntentController(Looper looper, UserController userController, ActivityManagerConstants constants) { mH = new Handler(looper); mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class); mUserController = userController; mConstants = constants; } void onActivityManagerInternalAdded() { Loading Loading @@ -136,12 +156,14 @@ public class PendingIntentController { } makeIntentSenderCanceled(rec); mIntentSenderRecords.remove(key); decrementUidStatLocked(rec); } if (noCreate) { return rec; } rec = new PendingIntentRecord(this, key, callingUid); mIntentSenderRecords.put(key, rec.ref); incrementUidStatLocked(rec); return rec; } } Loading Loading @@ -198,6 +220,7 @@ public class PendingIntentController { didSomething = true; it.remove(); makeIntentSenderCanceled(pir); decrementUidStatLocked(pir); if (pir.key.activity != null) { final Message m = PooledLambda.obtainMessage( PendingIntentController::clearPendingResultForActivity, this, Loading Loading @@ -237,6 +260,7 @@ public class PendingIntentController { synchronized (mLock) { makeIntentSenderCanceled(rec); mIntentSenderRecords.remove(rec.key); decrementUidStatLocked(rec); if (cleanActivity && rec.key.activity != null) { final Message m = PooledLambda.obtainMessage( PendingIntentController::clearPendingResultForActivity, this, Loading Loading @@ -369,9 +393,81 @@ public class PendingIntentController { } } final int sizeOfIntentsPerUid = mIntentsPerUid.size(); if (sizeOfIntentsPerUid > 0) { for (int i = 0; i < sizeOfIntentsPerUid; i++) { pw.print(" * UID: "); pw.print(mIntentsPerUid.keyAt(i)); pw.print(" total: "); pw.println(mIntentsPerUid.valueAt(i)); } } if (!printed) { pw.println(" (nothing)"); } } } /** * Increment the number of the PendingIntentRecord for the given uid, log a warning * if there are too many for this uid already. */ @GuardedBy("mLock") void incrementUidStatLocked(final PendingIntentRecord pir) { final int uid = pir.uid; final int idx = mIntentsPerUid.indexOfKey(uid); int newCount = 1; if (idx >= 0) { newCount = mIntentsPerUid.valueAt(idx) + 1; mIntentsPerUid.setValueAt(idx, newCount); } else { mIntentsPerUid.put(uid, newCount); } // If the number is within the range [threshold - N + 1, threshold], log it into buffer final int lowBound = mConstants.PENDINGINTENT_WARNING_THRESHOLD - RECENT_N + 1; RingBuffer<String> recentHistory = null; if (newCount == lowBound) { recentHistory = new RingBuffer(String.class, RECENT_N); mRecentIntentsPerUid.put(uid, recentHistory); } else if (newCount > lowBound && newCount <= mConstants.PENDINGINTENT_WARNING_THRESHOLD) { recentHistory = mRecentIntentsPerUid.get(uid); } if (recentHistory == null) { return; } recentHistory.append(pir.key.toString()); // Output the log if we are hitting the threshold if (newCount == mConstants.PENDINGINTENT_WARNING_THRESHOLD) { Slog.wtf(TAG, "Too many PendingIntent created for uid " + uid + ", recent " + RECENT_N + ": " + Arrays.toString(recentHistory.toArray())); // Clear the buffer, as we don't want to spam the log when the numbers // are jumping up and down around the threshold. mRecentIntentsPerUid.remove(uid); } } /** * Decrement the number of the PendingIntentRecord for the given uid. */ @GuardedBy("mLock") void decrementUidStatLocked(final PendingIntentRecord pir) { final int uid = pir.uid; final int idx = mIntentsPerUid.indexOfKey(uid); if (idx >= 0) { final int newCount = mIntentsPerUid.valueAt(idx) - 1; // If we are going below the low threshold, no need to keep logs. if (newCount == mConstants.PENDINGINTENT_WARNING_THRESHOLD - RECENT_N) { mRecentIntentsPerUid.delete(uid); } if (newCount == 0) { mIntentsPerUid.removeAt(idx); } else { mIntentsPerUid.setValueAt(idx, newCount); } } } } services/core/java/com/android/server/am/PendingIntentRecord.java +3 −1 Original line number Diff line number Diff line Loading @@ -187,7 +187,8 @@ public final class PendingIntentRecord extends IIntentSender.Stub { + " intent=" + (requestIntent != null ? requestIntent.toShortString(false, true, false, false) : "<null>") + " flags=0x" + Integer.toHexString(flags) + " u=" + userId + "}"; + " flags=0x" + Integer.toHexString(flags) + " u=" + userId + "}" + " requestCode=" + requestCode; } String typeName() { Loading Loading @@ -499,6 +500,7 @@ public final class PendingIntentRecord extends IIntentSender.Stub { WeakReference<PendingIntentRecord> current = controller.mIntentSenderRecords.get(key); if (current == ref) { controller.mIntentSenderRecords.remove(key); controller.decrementUidStatLocked(this); } } } Loading services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java +4 −1 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.app.ActivityManager; Loading Loading @@ -81,8 +82,10 @@ public class PendingIntentControllerTest { doReturn(mIPackageManager).when(() -> AppGlobals.getPackageManager()); when(mIPackageManager.getPackageUid(eq(TEST_PACKAGE_NAME), anyInt(), anyInt())).thenReturn( TEST_CALLING_UID); ActivityManagerConstants constants = mock(ActivityManagerConstants.class); constants.PENDINGINTENT_WARNING_THRESHOLD = 2000; mPendingIntentController = new PendingIntentController(Looper.getMainLooper(), mUserController); mUserController, constants); mPendingIntentController.onActivityManagerInternalAdded(); } Loading Loading
services/core/java/com/android/server/am/ActivityManagerConstants.java +10 −0 Original line number Diff line number Diff line Loading @@ -87,6 +87,7 @@ final class ActivityManagerConstants extends ContentObserver { static final String KEY_PROCESS_START_ASYNC = "process_start_async"; static final String KEY_MEMORY_INFO_THROTTLE_TIME = "memory_info_throttle_time"; static final String KEY_TOP_TO_FGS_GRACE_DURATION = "top_to_fgs_grace_duration"; static final String KEY_PENDINGINTENT_WARNING_THRESHOLD = "pendingintent_warning_threshold"; private static final int DEFAULT_MAX_CACHED_PROCESSES = 32; private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000; Loading Loading @@ -119,6 +120,7 @@ final class ActivityManagerConstants extends ContentObserver { private static final boolean DEFAULT_PROCESS_START_ASYNC = true; private static final long DEFAULT_MEMORY_INFO_THROTTLE_TIME = 5*60*1000; private static final long DEFAULT_TOP_TO_FGS_GRACE_DURATION = 15 * 1000; private static final int DEFAULT_PENDINGINTENT_WARNING_THRESHOLD = 2000; // Flag stored in the DeviceConfig API. /** Loading Loading @@ -328,6 +330,12 @@ final class ActivityManagerConstants extends ContentObserver { */ public ArraySet<Integer> IMPERCEPTIBLE_KILL_EXEMPT_PROC_STATES = new ArraySet<Integer>(); /** * The threshold for the amount of PendingIntent for each UID, there will be * warning logs if the number goes beyond this threshold. */ public int PENDINGINTENT_WARNING_THRESHOLD = DEFAULT_PENDINGINTENT_WARNING_THRESHOLD; private List<String> mDefaultImperceptibleKillExemptPackages; private List<Integer> mDefaultImperceptibleKillExemptProcStates; Loading Loading @@ -562,6 +570,8 @@ final class ActivityManagerConstants extends ContentObserver { DEFAULT_MEMORY_INFO_THROTTLE_TIME); TOP_TO_FGS_GRACE_DURATION = mParser.getDurationMillis(KEY_TOP_TO_FGS_GRACE_DURATION, DEFAULT_TOP_TO_FGS_GRACE_DURATION); PENDINGINTENT_WARNING_THRESHOLD = mParser.getInt(KEY_PENDINGINTENT_WARNING_THRESHOLD, DEFAULT_PENDINGINTENT_WARNING_THRESHOLD); // For new flags that are intended for server-side experiments, please use the new // DeviceConfig package. Loading
services/core/java/com/android/server/am/ActivityManagerService.java +3 −2 Original line number Diff line number Diff line Loading @@ -2543,7 +2543,8 @@ public class ActivityManagerService extends IActivityManager.Stub mUiHandler = injector.getUiHandler(null /* service */); mUserController = hasHandlerThread ? new UserController(this) : null; mPendingIntentController = hasHandlerThread ? new PendingIntentController(handlerThread.getLooper(), mUserController) : null; ? new PendingIntentController(handlerThread.getLooper(), mUserController, mConstants) : null; mProcStartHandlerThread = null; mProcStartHandler = null; mHiddenApiBlacklist = null; Loading Loading @@ -2640,7 +2641,7 @@ public class ActivityManagerService extends IActivityManager.Stub mUserController = new UserController(this); mPendingIntentController = new PendingIntentController( mHandlerThread.getLooper(), mUserController); mHandlerThread.getLooper(), mUserController, mConstants); if (SystemProperties.getInt("sys.use_fifo_ui", 0) != 0) { mUseFifoUiScheduling = true; Loading
services/core/java/com/android/server/am/PendingIntentController.java +97 −1 Original line number Diff line number Diff line Loading @@ -41,8 +41,12 @@ import android.os.RemoteException; import android.os.UserHandle; import android.util.ArrayMap; import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.IResultReceiver; import com.android.internal.util.RingBuffer; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.AlarmManagerInternal; import com.android.server.LocalServices; Loading @@ -52,6 +56,7 @@ import com.android.server.wm.SafeActivityOptions; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; Loading @@ -66,6 +71,9 @@ public class PendingIntentController { private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentController" : TAG_AM; private static final String TAG_MU = TAG + POSTFIX_MU; /** @see {@link #mRecentIntentsPerUid}. */ private static final int RECENT_N = 10; /** Lock for internal state. */ final Object mLock = new Object(); final Handler mH; Loading @@ -77,10 +85,22 @@ public class PendingIntentController { final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords = new HashMap<>(); PendingIntentController(Looper looper, UserController userController) { /** The number of PendingIntentRecord per uid */ @GuardedBy("mLock") private final SparseIntArray mIntentsPerUid = new SparseIntArray(); /** The recent PendingIntentRecord, up to {@link #RECENT_N} per uid */ @GuardedBy("mLock") private final SparseArray<RingBuffer<String>> mRecentIntentsPerUid = new SparseArray<>(); private final ActivityManagerConstants mConstants; PendingIntentController(Looper looper, UserController userController, ActivityManagerConstants constants) { mH = new Handler(looper); mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class); mUserController = userController; mConstants = constants; } void onActivityManagerInternalAdded() { Loading Loading @@ -136,12 +156,14 @@ public class PendingIntentController { } makeIntentSenderCanceled(rec); mIntentSenderRecords.remove(key); decrementUidStatLocked(rec); } if (noCreate) { return rec; } rec = new PendingIntentRecord(this, key, callingUid); mIntentSenderRecords.put(key, rec.ref); incrementUidStatLocked(rec); return rec; } } Loading Loading @@ -198,6 +220,7 @@ public class PendingIntentController { didSomething = true; it.remove(); makeIntentSenderCanceled(pir); decrementUidStatLocked(pir); if (pir.key.activity != null) { final Message m = PooledLambda.obtainMessage( PendingIntentController::clearPendingResultForActivity, this, Loading Loading @@ -237,6 +260,7 @@ public class PendingIntentController { synchronized (mLock) { makeIntentSenderCanceled(rec); mIntentSenderRecords.remove(rec.key); decrementUidStatLocked(rec); if (cleanActivity && rec.key.activity != null) { final Message m = PooledLambda.obtainMessage( PendingIntentController::clearPendingResultForActivity, this, Loading Loading @@ -369,9 +393,81 @@ public class PendingIntentController { } } final int sizeOfIntentsPerUid = mIntentsPerUid.size(); if (sizeOfIntentsPerUid > 0) { for (int i = 0; i < sizeOfIntentsPerUid; i++) { pw.print(" * UID: "); pw.print(mIntentsPerUid.keyAt(i)); pw.print(" total: "); pw.println(mIntentsPerUid.valueAt(i)); } } if (!printed) { pw.println(" (nothing)"); } } } /** * Increment the number of the PendingIntentRecord for the given uid, log a warning * if there are too many for this uid already. */ @GuardedBy("mLock") void incrementUidStatLocked(final PendingIntentRecord pir) { final int uid = pir.uid; final int idx = mIntentsPerUid.indexOfKey(uid); int newCount = 1; if (idx >= 0) { newCount = mIntentsPerUid.valueAt(idx) + 1; mIntentsPerUid.setValueAt(idx, newCount); } else { mIntentsPerUid.put(uid, newCount); } // If the number is within the range [threshold - N + 1, threshold], log it into buffer final int lowBound = mConstants.PENDINGINTENT_WARNING_THRESHOLD - RECENT_N + 1; RingBuffer<String> recentHistory = null; if (newCount == lowBound) { recentHistory = new RingBuffer(String.class, RECENT_N); mRecentIntentsPerUid.put(uid, recentHistory); } else if (newCount > lowBound && newCount <= mConstants.PENDINGINTENT_WARNING_THRESHOLD) { recentHistory = mRecentIntentsPerUid.get(uid); } if (recentHistory == null) { return; } recentHistory.append(pir.key.toString()); // Output the log if we are hitting the threshold if (newCount == mConstants.PENDINGINTENT_WARNING_THRESHOLD) { Slog.wtf(TAG, "Too many PendingIntent created for uid " + uid + ", recent " + RECENT_N + ": " + Arrays.toString(recentHistory.toArray())); // Clear the buffer, as we don't want to spam the log when the numbers // are jumping up and down around the threshold. mRecentIntentsPerUid.remove(uid); } } /** * Decrement the number of the PendingIntentRecord for the given uid. */ @GuardedBy("mLock") void decrementUidStatLocked(final PendingIntentRecord pir) { final int uid = pir.uid; final int idx = mIntentsPerUid.indexOfKey(uid); if (idx >= 0) { final int newCount = mIntentsPerUid.valueAt(idx) - 1; // If we are going below the low threshold, no need to keep logs. if (newCount == mConstants.PENDINGINTENT_WARNING_THRESHOLD - RECENT_N) { mRecentIntentsPerUid.delete(uid); } if (newCount == 0) { mIntentsPerUid.removeAt(idx); } else { mIntentsPerUid.setValueAt(idx, newCount); } } } }
services/core/java/com/android/server/am/PendingIntentRecord.java +3 −1 Original line number Diff line number Diff line Loading @@ -187,7 +187,8 @@ public final class PendingIntentRecord extends IIntentSender.Stub { + " intent=" + (requestIntent != null ? requestIntent.toShortString(false, true, false, false) : "<null>") + " flags=0x" + Integer.toHexString(flags) + " u=" + userId + "}"; + " flags=0x" + Integer.toHexString(flags) + " u=" + userId + "}" + " requestCode=" + requestCode; } String typeName() { Loading Loading @@ -499,6 +500,7 @@ public final class PendingIntentRecord extends IIntentSender.Stub { WeakReference<PendingIntentRecord> current = controller.mIntentSenderRecords.get(key); if (current == ref) { controller.mIntentSenderRecords.remove(key); controller.decrementUidStatLocked(this); } } } Loading
services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java +4 −1 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.app.ActivityManager; Loading Loading @@ -81,8 +82,10 @@ public class PendingIntentControllerTest { doReturn(mIPackageManager).when(() -> AppGlobals.getPackageManager()); when(mIPackageManager.getPackageUid(eq(TEST_PACKAGE_NAME), anyInt(), anyInt())).thenReturn( TEST_CALLING_UID); ActivityManagerConstants constants = mock(ActivityManagerConstants.class); constants.PENDINGINTENT_WARNING_THRESHOLD = 2000; mPendingIntentController = new PendingIntentController(Looper.getMainLooper(), mUserController); mUserController, constants); mPendingIntentController.onActivityManagerInternalAdded(); } Loading