Merge "Track the number of PendingIntent per UID" into rvc-dev
This commit is contained in:
@@ -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;
|
||||
@@ -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.
|
||||
/**
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
@@ -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() {
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
@@ -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,
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user