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

Commit e4bcf758 authored by Jeff Sharkey's avatar Jeff Sharkey Committed by Android (Google) Code Review
Browse files

Merge changes from topic "sep2"

* changes:
  [8/?] Reduce BroadcastQueue interface complexity.
  BroadcastQueue: factor out historical broadcasts.
  [7/?] Reduce BroadcastQueue interface complexity.
  BroadcastQueue: offer to wait for a barrier.
parents 52467f6e 88fe1a30
Loading
Loading
Loading
Loading
+13 −9
Original line number Diff line number Diff line
@@ -1390,8 +1390,9 @@ class ContextImpl extends Context {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                rd = new LoadedApk.ReceiverDispatcher(
                        resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();
                rd = new LoadedApk.ReceiverDispatcher(mMainThread.getApplicationThread(),
                        resultReceiver, getOuterContext(), scheduler, null, false)
                                .getIIntentReceiver();
            }
        }
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
@@ -1497,8 +1498,9 @@ class ContextImpl extends Context {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                rd = new LoadedApk.ReceiverDispatcher(resultReceiver, getOuterContext(),
                        scheduler, null, false).getIIntentReceiver();
                rd = new LoadedApk.ReceiverDispatcher(mMainThread.getApplicationThread(),
                        resultReceiver, getOuterContext(), scheduler, null, false)
                                .getIIntentReceiver();
            }
        }
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
@@ -1616,8 +1618,9 @@ class ContextImpl extends Context {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                rd = new LoadedApk.ReceiverDispatcher(
                        resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();
                rd = new LoadedApk.ReceiverDispatcher(mMainThread.getApplicationThread(),
                        resultReceiver, getOuterContext(), scheduler, null, false)
                                .getIIntentReceiver();
            }
        }
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
@@ -1699,8 +1702,9 @@ class ContextImpl extends Context {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                rd = new LoadedApk.ReceiverDispatcher(
                        resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();
                rd = new LoadedApk.ReceiverDispatcher(mMainThread.getApplicationThread(),
                        resultReceiver, getOuterContext(), scheduler, null, false)
                                .getIIntentReceiver();
            }
        }
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
@@ -1802,7 +1806,7 @@ class ContextImpl extends Context {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                rd = new LoadedApk.ReceiverDispatcher(
                rd = new LoadedApk.ReceiverDispatcher(mMainThread.getApplicationThread(),
                        receiver, context, scheduler, null, true).getIIntentReceiver();
            }
        }
+7 −5
Original line number Diff line number Diff line
@@ -1598,8 +1598,8 @@ public final class LoadedApk {
                }
            }
            if (rd == null) {
                rd = new ReceiverDispatcher(r, context, handler,
                        instrumentation, registered);
                rd = new ReceiverDispatcher(mActivityThread.getApplicationThread(), r, context,
                        handler, instrumentation, registered);
                if (registered) {
                    if (map == null) {
                        map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
@@ -1714,6 +1714,7 @@ public final class LoadedApk {
            }
        }

        final IApplicationThread mAppThread;
        final IIntentReceiver.Stub mIIntentReceiver;
        @UnsupportedAppUsage
        final BroadcastReceiver mReceiver;
@@ -1736,7 +1737,7 @@ public final class LoadedApk {
                    boolean ordered, boolean sticky, int sendingUser) {
                super(resultCode, resultData, resultExtras,
                        mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered,
                        sticky, mIIntentReceiver.asBinder(), sendingUser, intent.getFlags());
                        sticky, mAppThread.asBinder(), sendingUser, intent.getFlags());
                mCurIntent = intent;
                mOrdered = ordered;
            }
@@ -1811,13 +1812,14 @@ public final class LoadedApk {
            }
        }

        ReceiverDispatcher(BroadcastReceiver receiver, Context context,
                Handler activityThread, Instrumentation instrumentation,
        ReceiverDispatcher(IApplicationThread appThread, BroadcastReceiver receiver,
                Context context, Handler activityThread, Instrumentation instrumentation,
                boolean registered) {
            if (activityThread == null) {
                throw new NullPointerException("Handler must not be null");
            }

            mAppThread = appThread;
            mIIntentReceiver = new InnerReceiver(this, !registered);
            mReceiver = receiver;
            mContext = context;
+39 −66
Original line number Diff line number Diff line
@@ -2412,13 +2412,13 @@ public class ActivityManagerService extends IActivityManager.Stub
        mBroadcastQueues = new BroadcastQueue[4];
        mFgBroadcastQueue = new BroadcastQueueImpl(this, mHandler,
                "foreground", foreConstants, false);
                "foreground", foreConstants, false, ProcessList.SCHED_GROUP_DEFAULT);
        mBgBroadcastQueue = new BroadcastQueueImpl(this, mHandler,
                "background", backConstants, true);
                "background", backConstants, true, ProcessList.SCHED_GROUP_BACKGROUND);
        mBgOffloadBroadcastQueue = new BroadcastQueueImpl(this, mHandler,
                "offload_bg", offloadConstants, true);
                "offload_bg", offloadConstants, true, ProcessList.SCHED_GROUP_BACKGROUND);
        mFgOffloadBroadcastQueue = new BroadcastQueueImpl(this, mHandler,
                "offload_fg", foreConstants, true);
                "offload_fg", foreConstants, true, ProcessList.SCHED_GROUP_BACKGROUND);
        mBroadcastQueues[0] = mFgBroadcastQueue;
        mBroadcastQueues[1] = mBgBroadcastQueue;
        mBroadcastQueues[2] = mBgOffloadBroadcastQueue;
@@ -3263,13 +3263,20 @@ public class ActivityManagerService extends IActivityManager.Stub
        if (thread == null) {
            return null;
        }
        return getRecordForAppLOSP(thread.asBinder());
    }
        ProcessRecord record = mProcessList.getLRURecordForAppLOSP(thread);
    @GuardedBy(anyOf = {"this", "mProcLock"})
    ProcessRecord getRecordForAppLOSP(IBinder threadBinder) {
        if (threadBinder == null) {
            return null;
        }
        ProcessRecord record = mProcessList.getLRURecordForAppLOSP(threadBinder);
        if (record != null) return record;
        // Validation: if it isn't in the LRU list, it shouldn't exist, but let's
        // double-check that.
        final IBinder threadBinder = thread.asBinder();
        final ArrayMap<String, SparseArray<ProcessRecord>> pmap =
                mProcessList.getProcessNamesLOSP().getMap();
        for (int i = pmap.size()-1; i >= 0; i--) {
@@ -10649,7 +10656,7 @@ public class ActivityManagerService extends IActivityManager.Stub
        if (!onlyHistory && !onlyReceivers && dumpAll) {
            pw.println();
            for (BroadcastQueue queue : mBroadcastQueues) {
                pw.println("  Queue " + queue.toString() + ": " + queue.describeState());
                pw.println("  Queue " + queue.toString() + ": " + queue.describeStateLocked());
            }
            pw.println("  mHandler:");
            mHandler.dump(new PrintWriterPrinter(pw), "    ");
@@ -13370,7 +13377,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                    final BroadcastRecord r = rl.curBroadcast;
                    if (r != null) {
                        final boolean doNext = r.queue.finishReceiverLocked(
                                receiver.asBinder(), r.resultCode, r.resultData, r.resultExtras,
                                rl.app, r.resultCode, r.resultData, r.resultExtras,
                                r.resultAbort, false);
                        if (doNext) {
                            doTrim = true;
@@ -14538,9 +14545,9 @@ public class ActivityManagerService extends IActivityManager.Stub
        }
    }
    public void finishReceiver(IBinder who, int resultCode, String resultData,
    public void finishReceiver(IBinder caller, int resultCode, String resultData,
            Bundle resultExtras, boolean resultAbort, int flags) {
        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Finish receiver: " + who);
        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Finish receiver: " + caller);
        // Refuse possible leaked file descriptors
        if (resultExtras != null && resultExtras.hasFileDescriptors()) {
@@ -14549,12 +14556,15 @@ public class ActivityManagerService extends IActivityManager.Stub
        final long origId = Binder.clearCallingIdentity();
        try {
            boolean doNext = false;
            BroadcastRecord r;
            BroadcastQueue queue;
            synchronized(this) {
                queue = broadcastQueueForFlags(flags);
                doNext = queue.finishReceiverLocked(who, resultCode,
                final ProcessRecord callerApp = getRecordForAppLOSP(caller);
                if (callerApp == null) {
                    Slog.w(TAG, "finishReceiver: no app for " + caller);
                    return;
                }
                final BroadcastQueue queue = broadcastQueueForFlags(flags);
                queue.finishReceiverLocked(callerApp, resultCode,
                        resultData, resultExtras, resultAbort, true);
                // updateOomAdjLocked() will be done here
                trimApplicationsLocked(false, OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER);
@@ -15106,30 +15116,13 @@ public class ActivityManagerService extends IActivityManager.Stub
    // LIFETIME MANAGEMENT
    // =========================================================
    // Returns whether the app is receiving broadcast.
    // If receiving, fetch all broadcast queues which the app is
    // the current [or imminent] receiver on.
    boolean isReceivingBroadcastLocked(ProcessRecord app,
            ArraySet<BroadcastQueue> receivingQueues) {
        final ProcessReceiverRecord prr = app.mReceivers;
        final int numOfReceivers = prr.numberOfCurReceivers();
        if (numOfReceivers > 0) {
            for (int i = 0; i < numOfReceivers; i++) {
                receivingQueues.add(prr.getCurReceiverAt(i).queue);
            }
            return true;
        }
        // It's not the current receiver, but it might be starting up to become one
    boolean isReceivingBroadcastLocked(ProcessRecord app, int[] outSchedGroup) {
        int res = ProcessList.SCHED_GROUP_UNDEFINED;
        for (BroadcastQueue queue : mBroadcastQueues) {
            final BroadcastRecord r = queue.getPendingBroadcastLocked();
            if (r != null && r.curApp == app) {
                // found it; report which queue it's in
                receivingQueues.add(queue);
            }
            res = Math.max(res, queue.getPreferredSchedulingGroupLocked(app));
        }
        return !receivingQueues.isEmpty();
        outSchedGroup[0] = res;
        return res != ProcessList.SCHED_GROUP_UNDEFINED;
    }
    Association startAssociationLocked(int sourceUid, String sourceProcess, int sourceState,
@@ -15237,7 +15230,7 @@ public class ActivityManagerService extends IActivityManager.Stub
    @GuardedBy("this")
    final boolean canGcNowLocked() {
        for (BroadcastQueue q : mBroadcastQueues) {
            if (!q.isIdle()) {
            if (!q.isIdleLocked()) {
                return false;
            }
        }
@@ -17814,35 +17807,15 @@ public class ActivityManagerService extends IActivityManager.Stub
    public void waitForBroadcastIdle(@Nullable PrintWriter pw) {
        enforceCallingPermission(permission.DUMP, "waitForBroadcastIdle()");
        while (true) {
            boolean idle = true;
            synchronized (this) {
        for (BroadcastQueue queue : mBroadcastQueues) {
                    if (!queue.isIdle()) {
                        final String msg = "Waiting for queue " + queue + " to become idle...";
                        if (pw != null) {
                            pw.println(msg);
                            pw.println(queue.describeState());
                            pw.flush();
                        }
                        Slog.v(TAG, msg);
                        queue.flush();
                        idle = false;
                    }
            queue.waitForIdle(pw);
        }
    }
            if (idle) {
                final String msg = "All broadcast queues are idle!";
                if (pw != null) {
                    pw.println(msg);
                    pw.flush();
                }
                Slog.v(TAG, msg);
                return;
            } else {
                SystemClock.sleep(1000);
            }
    public void waitForBroadcastBarrier(@Nullable PrintWriter pw) {
        enforceCallingPermission(permission.DUMP, "waitForBroadcastBarrier()");
        for (BroadcastQueue queue : mBroadcastQueues) {
            queue.waitForBarrier(pw);
        }
    }
+7 −0
Original line number Diff line number Diff line
@@ -341,6 +341,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
                    return runNoHomeScreen(pw);
                case "wait-for-broadcast-idle":
                    return runWaitForBroadcastIdle(pw);
                case "wait-for-broadcast-barrier":
                    return runWaitForBroadcastBarrier(pw);
                case "compat":
                    return runCompat(pw);
                case "refresh-settings-cache":
@@ -3112,6 +3114,11 @@ final class ActivityManagerShellCommand extends ShellCommand {
        return 0;
    }

    int runWaitForBroadcastBarrier(PrintWriter pw) throws RemoteException {
        mInternal.waitForBroadcastBarrier(pw);
        return 0;
    }

    int runRefreshSettingsCache() throws RemoteException {
        mInternal.refreshSettingsCache();
        return 0;
+224 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.am;

import android.app.ActivityManager;
import android.content.Intent;
import android.os.Bundle;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;

import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Collection of recent historical broadcasts that are available to be dumped
 * for debugging purposes. Automatically trims itself over time.
 */
public class BroadcastHistory {
    static final int MAX_BROADCAST_HISTORY = ActivityManager.isLowRamDeviceStatic() ? 10 : 50;
    static final int MAX_BROADCAST_SUMMARY_HISTORY
            = ActivityManager.isLowRamDeviceStatic() ? 25 : 300;

    /**
     * Historical data of past broadcasts, for debugging.  This is a ring buffer
     * whose last element is at mHistoryNext.
     */
    final BroadcastRecord[] mBroadcastHistory = new BroadcastRecord[MAX_BROADCAST_HISTORY];
    int mHistoryNext = 0;

    /**
     * Summary of historical data of past broadcasts, for debugging.  This is a
     * ring buffer whose last element is at mSummaryHistoryNext.
     */
    final Intent[] mBroadcastSummaryHistory = new Intent[MAX_BROADCAST_SUMMARY_HISTORY];
    int mSummaryHistoryNext = 0;

    /**
     * Various milestone timestamps of entries in the mBroadcastSummaryHistory ring
     * buffer, also tracked via the mSummaryHistoryNext index.  These are all in wall
     * clock time, not elapsed.
     */
    final long[] mSummaryHistoryEnqueueTime = new long[MAX_BROADCAST_SUMMARY_HISTORY];
    final long[] mSummaryHistoryDispatchTime = new long[MAX_BROADCAST_SUMMARY_HISTORY];
    final long[] mSummaryHistoryFinishTime = new long[MAX_BROADCAST_SUMMARY_HISTORY];

    public void addBroadcastToHistoryLocked(BroadcastRecord original) {
        // Note sometimes (only for sticky broadcasts?) we reuse BroadcastRecords,
        // So don't change the incoming record directly.
        final BroadcastRecord historyRecord = original.maybeStripForHistory();

        mBroadcastHistory[mHistoryNext] = historyRecord;
        mHistoryNext = ringAdvance(mHistoryNext, 1, MAX_BROADCAST_HISTORY);

        mBroadcastSummaryHistory[mSummaryHistoryNext] = historyRecord.intent;
        mSummaryHistoryEnqueueTime[mSummaryHistoryNext] = historyRecord.enqueueClockTime;
        mSummaryHistoryDispatchTime[mSummaryHistoryNext] = historyRecord.dispatchClockTime;
        mSummaryHistoryFinishTime[mSummaryHistoryNext] = System.currentTimeMillis();
        mSummaryHistoryNext = ringAdvance(mSummaryHistoryNext, 1, MAX_BROADCAST_SUMMARY_HISTORY);
    }

    private final int ringAdvance(int x, final int increment, final int ringSize) {
        x += increment;
        if (x < 0) return (ringSize - 1);
        else if (x >= ringSize) return 0;
        else return x;
    }

    public void dumpDebug(ProtoOutputStream proto) {
        int lastIndex = mHistoryNext;
        int ringIndex = lastIndex;
        do {
            // increasing index = more recent entry, and we want to print the most
            // recent first and work backwards, so we roll through the ring backwards.
            ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_HISTORY);
            BroadcastRecord r = mBroadcastHistory[ringIndex];
            if (r != null) {
                r.dumpDebug(proto, BroadcastQueueProto.HISTORICAL_BROADCASTS);
            }
        } while (ringIndex != lastIndex);

        lastIndex = ringIndex = mSummaryHistoryNext;
        do {
            ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_SUMMARY_HISTORY);
            Intent intent = mBroadcastSummaryHistory[ringIndex];
            if (intent == null) {
                continue;
            }
            long summaryToken = proto.start(BroadcastQueueProto.HISTORICAL_BROADCASTS_SUMMARY);
            intent.dumpDebug(proto, BroadcastQueueProto.BroadcastSummary.INTENT,
                    false, true, true, false);
            proto.write(BroadcastQueueProto.BroadcastSummary.ENQUEUE_CLOCK_TIME_MS,
                    mSummaryHistoryEnqueueTime[ringIndex]);
            proto.write(BroadcastQueueProto.BroadcastSummary.DISPATCH_CLOCK_TIME_MS,
                    mSummaryHistoryDispatchTime[ringIndex]);
            proto.write(BroadcastQueueProto.BroadcastSummary.FINISH_CLOCK_TIME_MS,
                    mSummaryHistoryFinishTime[ringIndex]);
            proto.end(summaryToken);
        } while (ringIndex != lastIndex);
    }

    public boolean dumpLocked(PrintWriter pw, String dumpPackage, String queueName,
            SimpleDateFormat sdf, boolean dumpAll, boolean needSep) {
        int i;
        boolean printed = false;

        i = -1;
        int lastIndex = mHistoryNext;
        int ringIndex = lastIndex;
        do {
            // increasing index = more recent entry, and we want to print the most
            // recent first and work backwards, so we roll through the ring backwards.
            ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_HISTORY);
            BroadcastRecord r = mBroadcastHistory[ringIndex];
            if (r == null) {
                continue;
            }

            i++; // genuine record of some sort even if we're filtering it out
            if (dumpPackage != null && !dumpPackage.equals(r.callerPackage)) {
                continue;
            }
            if (!printed) {
                if (needSep) {
                    pw.println();
                }
                needSep = true;
                pw.println("  Historical broadcasts [" + queueName + "]:");
                printed = true;
            }
            if (dumpAll) {
                pw.print("  Historical Broadcast " + queueName + " #");
                        pw.print(i); pw.println(":");
                r.dump(pw, "    ", sdf);
            } else {
                pw.print("  #"); pw.print(i); pw.print(": "); pw.println(r);
                pw.print("    ");
                pw.println(r.intent.toShortString(false, true, true, false));
                if (r.targetComp != null && r.targetComp != r.intent.getComponent()) {
                    pw.print("    targetComp: "); pw.println(r.targetComp.toShortString());
                }
                Bundle bundle = r.intent.getExtras();
                if (bundle != null) {
                    pw.print("    extras: "); pw.println(bundle.toString());
                }
            }
        } while (ringIndex != lastIndex);

        if (dumpPackage == null) {
            lastIndex = ringIndex = mSummaryHistoryNext;
            if (dumpAll) {
                printed = false;
                i = -1;
            } else {
                // roll over the 'i' full dumps that have already been issued
                for (int j = i;
                        j > 0 && ringIndex != lastIndex;) {
                    ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_SUMMARY_HISTORY);
                    BroadcastRecord r = mBroadcastHistory[ringIndex];
                    if (r == null) {
                        continue;
                    }
                    j--;
                }
            }
            // done skipping; dump the remainder of the ring. 'i' is still the ordinal within
            // the overall broadcast history.
            do {
                ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_SUMMARY_HISTORY);
                Intent intent = mBroadcastSummaryHistory[ringIndex];
                if (intent == null) {
                    continue;
                }
                if (!printed) {
                    if (needSep) {
                        pw.println();
                    }
                    needSep = true;
                    pw.println("  Historical broadcasts summary [" + queueName + "]:");
                    printed = true;
                }
                if (!dumpAll && i >= 50) {
                    pw.println("  ...");
                    break;
                }
                i++;
                pw.print("  #"); pw.print(i); pw.print(": ");
                pw.println(intent.toShortString(false, true, true, false));
                pw.print("    ");
                TimeUtils.formatDuration(mSummaryHistoryDispatchTime[ringIndex]
                        - mSummaryHistoryEnqueueTime[ringIndex], pw);
                pw.print(" dispatch ");
                TimeUtils.formatDuration(mSummaryHistoryFinishTime[ringIndex]
                        - mSummaryHistoryDispatchTime[ringIndex], pw);
                pw.println(" finish");
                pw.print("    enq=");
                pw.print(sdf.format(new Date(mSummaryHistoryEnqueueTime[ringIndex])));
                pw.print(" disp=");
                pw.print(sdf.format(new Date(mSummaryHistoryDispatchTime[ringIndex])));
                pw.print(" fin=");
                pw.println(sdf.format(new Date(mSummaryHistoryFinishTime[ringIndex])));
                Bundle bundle = intent.getExtras();
                if (bundle != null) {
                    pw.print("    extras: "); pw.println(bundle.toString());
                }
            } while (ringIndex != lastIndex);
        }
        return needSep;
    }
}
Loading