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

Commit d509bc93 authored by yangzhenyu's avatar yangzhenyu
Browse files

[ActivityManager] Fix the inconsistence between ProcessRecord and BroadcastQueues

Symptom:
Even though one process is executing one BroadcastReceiver,
it may be killed as one EMPTY process occasionally

Detail and sample:
https://code.google.com/p/android/issues/detail?id=221524



Root cause:
app.curReceiver can only remember the last running.
If an application is both receiving FG and BG broadcast,
when one is finished, app.curReceiver becomes null,
the state of application becomes EMPTY.

Solution:
save all running receivers at ProcessRecord

Change-Id: I01b8813af652a8c434be7de0678dc06f99831ae0
Signed-off-by: default avataryangzhenyu <yangzhenyu@xiaomi.com>
parent 2fbf30d3
Loading
Loading
Loading
Loading
+22 −20
Original line number Diff line number Diff line
@@ -9522,7 +9522,7 @@ public final class ActivityManagerService extends ActivityManagerNative
        for (int i = 0; i < procsToKill.size(); i++) {
            ProcessRecord pr = procsToKill.get(i);
            if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                    && pr.curReceiver == null) {
                    && pr.curReceivers.isEmpty()) {
                pr.kill("remove task", true);
            } else {
                // We delay killing processes that are not in the background or running a receiver.
@@ -18903,26 +18903,28 @@ public final class ActivityManagerService extends ActivityManagerNative
    // LIFETIME MANAGEMENT
    // =========================================================
    // Returns which broadcast queue the app is the current [or imminent] receiver
    // on, or 'null' if the app is not an active broadcast recipient.
    private BroadcastQueue isReceivingBroadcast(ProcessRecord app) {
        BroadcastRecord r = app.curReceiver;
        if (r != null) {
            return r.queue;
    // Returns whether the app is receiving broadcast.
    // If receiving, fetch all broadcast queues which the app is
    // the current [or imminent] receiver on.
    private boolean isReceivingBroadcastLocked(ProcessRecord app,
            ArraySet<BroadcastQueue> receivingQueues) {
        if (!app.curReceivers.isEmpty()) {
            for (BroadcastRecord r : app.curReceivers) {
                receivingQueues.add(r.queue);
            }
            return true;
        }
        // It's not the current receiver, but it might be starting up to become one
        synchronized (this) {
        for (BroadcastQueue queue : mBroadcastQueues) {
                r = queue.mPendingBroadcast;
            final BroadcastRecord r = queue.mPendingBroadcast;
            if (r != null && r.curApp == app) {
                // found it; report which queue it's in
                    return queue;
                }
                receivingQueues.add(queue);
            }
        }
        return null;
        return !receivingQueues.isEmpty();
    }
    Association startAssociationLocked(int sourceUid, String sourceProcess, int sourceState,
@@ -19085,7 +19087,7 @@ public final class ActivityManagerService extends ActivityManagerNative
        int schedGroup;
        int procState;
        boolean foregroundActivities = false;
        BroadcastQueue queue;
        final ArraySet<BroadcastQueue> queues = new ArraySet<BroadcastQueue>();
        if (app == TOP_APP) {
            // The last app on the list is the foreground app.
            adj = ProcessList.FOREGROUND_APP_ADJ;
@@ -19099,13 +19101,13 @@ public final class ActivityManagerService extends ActivityManagerNative
            schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
            app.adjType = "instrumentation";
            procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
        } else if ((queue = isReceivingBroadcast(app)) != null) {
        } else if (isReceivingBroadcastLocked(app, queues)) {
            // An app that is currently receiving a broadcast also
            // counts as being in the foreground for OOM killer purposes.
            // It's placed in a sched group based on the nature of the
            // broadcast as reflected by which queue it's active in.
            adj = ProcessList.FOREGROUND_APP_ADJ;
            schedGroup = (queue == mFgBroadcastQueue)
            schedGroup = (queues.contains(mFgBroadcastQueue))
                    ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
            app.adjType = "broadcast";
            procState = ActivityManager.PROCESS_STATE_RECEIVER;
@@ -20115,7 +20117,7 @@ public final class ActivityManagerService extends ActivityManagerNative
            if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
                    "Setting sched group of " + app.processName
                    + " to " + app.curSchedGroup);
            if (app.waitingToKill != null && app.curReceiver == null
            if (app.waitingToKill != null && app.curReceivers.isEmpty()
                    && app.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND) {
                app.kill(app.waitingToKill, true);
                success = false;
@@ -20985,7 +20987,7 @@ public final class ActivityManagerService extends ActivityManagerNative
            for (i=mRemovedProcesses.size()-1; i>=0; i--) {
                final ProcessRecord app = mRemovedProcesses.get(i);
                if (app.activities.size() == 0
                        && app.curReceiver == null && app.services.size() == 0) {
                        && app.curReceivers.isEmpty() && app.services.size() == 0) {
                    Slog.i(
                        TAG, "Exiting empty application process "
                        + app.toShortString() + " ("
+6 −6
Original line number Diff line number Diff line
@@ -265,7 +265,7 @@ public final class BroadcastQueue {

        r.receiver = app.thread.asBinder();
        r.curApp = app;
        app.curReceiver = r;
        app.curReceivers.add(r);
        app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
        mService.updateLruProcessLocked(app, false, null);
        mService.updateOomAdjLocked();
@@ -293,7 +293,7 @@ public final class BroadcastQueue {
                        "Process cur broadcast " + r + ": NOT STARTED!");
                r.receiver = null;
                r.curApp = null;
                app.curReceiver = null;
                app.curReceivers.remove(r);
            }
        }
    }
@@ -389,8 +389,8 @@ public final class BroadcastQueue {
        }
        r.receiver = null;
        r.intent.setComponent(null);
        if (r.curApp != null && r.curApp.curReceiver == r) {
            r.curApp.curReceiver = null;
        if (r.curApp != null && r.curApp.curReceivers.contains(r)) {
            r.curApp.curReceivers.remove(r);
        }
        if (r.curFilter != null) {
            r.curFilter.receiverList.curBroadcast = null;
@@ -643,7 +643,7 @@ public final class BroadcastQueue {
                // things that directly call the IActivityManager API, which
                // are already core system stuff so don't matter for this.
                r.curApp = filter.receiverList.app;
                filter.receiverList.app.curReceiver = r;
                filter.receiverList.app.curReceivers.add(r);
                mService.updateOomAdjLocked(r.curApp);
            }
        }
@@ -671,7 +671,7 @@ public final class BroadcastQueue {
                r.curFilter = null;
                filter.receiverList.curBroadcast = null;
                if (filter.receiverList.app != null) {
                    filter.receiverList.app.curReceiver = null;
                    filter.receiverList.app.curReceivers.remove(r);
                }
            }
        }
+6 −3
Original line number Diff line number Diff line
@@ -138,7 +138,7 @@ final class ProcessRecord {
    Bundle instrumentationArguments;// as given to us
    ComponentName instrumentationResultClass;// copy of instrumentationClass
    boolean usingWrapper;       // Set to true when process was launched with a wrapper attached
    BroadcastRecord curReceiver;// receiver currently running in the app
    final ArraySet<BroadcastRecord> curReceivers = new ArraySet<BroadcastRecord>();// receivers currently running in the app
    long lastWakeTime;          // How long proc held wake lock at last check
    long lastCpuTime;           // How long proc has run CPU at last check
    long curCpuTime;            // How long proc has run CPU most recently
@@ -421,8 +421,11 @@ final class ProcessRecord {
                pw.print(prefix); pw.print("  - "); pw.println(conProviders.get(i).toShortString());
            }
        }
        if (curReceiver != null) {
            pw.print(prefix); pw.print("curReceiver="); pw.println(curReceiver);
        if (!curReceivers.isEmpty()) {
            pw.print(prefix); pw.println("Current Receivers:");
            for (int i=0; i < curReceivers.size(); i++) {
                pw.print(prefix); pw.print("  - "); pw.println(curReceivers.valueAt(i));
            }
        }
        if (receivers.size() > 0) {
            pw.print(prefix); pw.println("Receivers:");