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

Commit cf084d5a authored by Jing Ji's avatar Jing Ji Committed by Android (Google) Code Review
Browse files

Merge "Track the number of PendingIntent per UID" into rvc-dev

parents 7852107b 7b82cbec
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -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.
+3 −2
Original line number Diff line number Diff line
@@ -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;
+97 −1
Original line number Diff line number Diff line
@@ -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);
            }
        }
    }
}
+3 −1
Original line number Diff line number Diff line
@@ -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);
            }
        }
    }
+4 −1
Original line number Diff line number Diff line
@@ -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();
    }