From 4e82054566c51ab7bc4a87d1a89d1db3e790c7e6 Mon Sep 17 00:00:00 2001 From: Amith Yamasani Date: Wed, 9 May 2018 13:37:20 -0700 Subject: [PATCH] Avoid calling updateOomAdj an extra time When handling a finishReceiver, don't call updateOomAdj inside processNextBroadcast() since we're doing it in trimApplications() immediately after. Bug: 78894563 Test: AM perf tests Change-Id: I77d4ce853b0f0079c5909d8a3c4dd5332bcfe5db --- .../server/am/ActivityManagerService.java | 70 +- .../com/android/server/am/BroadcastQueue.java | 1090 +++++++++-------- 2 files changed, 585 insertions(+), 575 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 58b40b1a5f6bd..1f1485e3825b1 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -22006,12 +22006,13 @@ public class ActivityManagerService extends IActivityManager.Stub doNext = r.queue.finishReceiverLocked(r, resultCode, resultData, resultExtras, resultAbort, true); } + if (doNext) { + r.queue.processNextBroadcastLocked(/*fromMsg=*/ false, /*skipOomAdj=*/ true); + } + // updateOomAdjLocked() will be done here + trimApplicationsLocked(); } - if (doNext) { - r.queue.processNextBroadcast(false); - } - trimApplications(); } finally { Binder.restoreCallingIdentity(origId); } @@ -25665,40 +25666,43 @@ public class ActivityManagerService extends IActivityManager.Stub final void trimApplications() { synchronized (this) { - int i; + trimApplicationsLocked(); + } + } - // First remove any unused application processes whose package - // has been removed. - for (i=mRemovedProcesses.size()-1; i>=0; i--) { - final ProcessRecord app = mRemovedProcesses.get(i); - if (app.activities.size() == 0 && app.recentTasks.size() == 0 - && app.curReceivers.isEmpty() && app.services.size() == 0) { - Slog.i( - TAG, "Exiting empty application process " - + app.toShortString() + " (" - + (app.thread != null ? app.thread.asBinder() : null) - + ")\n"); - if (app.pid > 0 && app.pid != MY_PID) { - app.kill("empty", false); - } else if (app.thread != null) { - try { - app.thread.scheduleExit(); - } catch (Exception e) { - // Ignore exceptions. - } - } - cleanUpApplicationRecordLocked(app, false, true, -1, false /*replacingPid*/); - mRemovedProcesses.remove(i); - - if (app.persistent) { - addAppLocked(app.info, null, false, null /* ABI override */); + final void trimApplicationsLocked() { + // First remove any unused application processes whose package + // has been removed. + for (int i=mRemovedProcesses.size()-1; i>=0; i--) { + final ProcessRecord app = mRemovedProcesses.get(i); + if (app.activities.size() == 0 && app.recentTasks.size() == 0 + && app.curReceivers.isEmpty() && app.services.size() == 0) { + Slog.i( + TAG, "Exiting empty application process " + + app.toShortString() + " (" + + (app.thread != null ? app.thread.asBinder() : null) + + ")\n"); + if (app.pid > 0 && app.pid != MY_PID) { + app.kill("empty", false); + } else if (app.thread != null) { + try { + app.thread.scheduleExit(); + } catch (Exception e) { + // Ignore exceptions. } } - } + cleanUpApplicationRecordLocked(app, false, true, -1, false /*replacingPid*/); + mRemovedProcesses.remove(i); - // Now update the oom adj for all processes. - updateOomAdjLocked(); + if (app.persistent) { + addAppLocked(app.info, null, false, null /* ABI override */); + } + } } + + // Now update the oom adj for all processes. Don't skip this, since other callers + // might be depending on it. + updateOomAdjLocked(); } /** This method sends the specified signal to each of the persistent apps */ diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index cc3a8875c4d1e..c9a26cbb3287d 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -271,7 +271,7 @@ public final class BroadcastQueue { } private final void processCurBroadcastLocked(BroadcastRecord r, - ProcessRecord app) throws RemoteException { + ProcessRecord app, boolean skipOomAdj) throws RemoteException { if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Process cur broadcast " + r + " for app " + app); if (app.thread == null) { @@ -287,7 +287,9 @@ public final class BroadcastQueue { app.curReceivers.add(r); app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER); mService.updateLruProcessLocked(app, false, null); - mService.updateOomAdjLocked(); + if (!skipOomAdj) { + mService.updateOomAdjLocked(); + } // Tell the application to launch this receiver. r.intent.setComponent(r.curComponent); @@ -328,7 +330,7 @@ public final class BroadcastQueue { } try { mPendingBroadcast = null; - processCurBroadcastLocked(br, app); + processCurBroadcastLocked(br, app, false); didSomething = true; } catch (Exception e) { Slog.w(TAG, "Exception in new application when starting receiver " @@ -819,577 +821,581 @@ public final class BroadcastQueue { } final void processNextBroadcast(boolean fromMsg) { - synchronized(mService) { - BroadcastRecord r; + synchronized (mService) { + processNextBroadcastLocked(fromMsg, false); + } + } - if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast [" - + mQueueName + "]: " - + mParallelBroadcasts.size() + " parallel broadcasts, " - + mOrderedBroadcasts.size() + " ordered broadcasts"); + final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) { + BroadcastRecord r; - mService.updateCpuStats(); + if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast [" + + mQueueName + "]: " + + mParallelBroadcasts.size() + " parallel broadcasts, " + + mOrderedBroadcasts.size() + " ordered broadcasts"); - if (fromMsg) { - mBroadcastsScheduled = false; + mService.updateCpuStats(); + + if (fromMsg) { + mBroadcastsScheduled = false; + } + + // First, deliver any non-serialized broadcasts right away. + while (mParallelBroadcasts.size() > 0) { + r = mParallelBroadcasts.remove(0); + r.dispatchTime = SystemClock.uptimeMillis(); + r.dispatchClockTime = System.currentTimeMillis(); + + if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) { + Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, + createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING), + System.identityHashCode(r)); + Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, + createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_DELIVERED), + System.identityHashCode(r)); } - // First, deliver any non-serialized broadcasts right away. - while (mParallelBroadcasts.size() > 0) { - r = mParallelBroadcasts.remove(0); - r.dispatchTime = SystemClock.uptimeMillis(); - r.dispatchClockTime = System.currentTimeMillis(); - - if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) { - Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, - createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING), - System.identityHashCode(r)); - Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, - createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_DELIVERED), - System.identityHashCode(r)); - } - - final int N = r.receivers.size(); - if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast [" - + mQueueName + "] " + r); - for (int i=0; i 0) { - synchronized (mService.mPidsSelfLocked) { - ProcessRecord proc = mService.mPidsSelfLocked.get( - mPendingBroadcast.curApp.pid); - isDead = proc == null || proc.crashing; - } - } else { - final ProcessRecord proc = mService.mProcessNames.get( - mPendingBroadcast.curApp.processName, mPendingBroadcast.curApp.uid); - isDead = proc == null || !proc.pendingStart; - } - if (!isDead) { - // It's still alive, so keep waiting - return; - } else { - Slog.w(TAG, "pending app [" - + mQueueName + "]" + mPendingBroadcast.curApp - + " died before responding to broadcast"); - mPendingBroadcast.state = BroadcastRecord.IDLE; - mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex; - mPendingBroadcast = null; - } - } - - boolean looped = false; - - do { - if (mOrderedBroadcasts.size() == 0) { - // No more broadcasts pending, so all done! - mService.scheduleAppGcsLocked(); - if (looped) { - // If we had finished the last ordered broadcast, then - // make sure all processes have correct oom and sched - // adjustments. - mService.updateOomAdjLocked(); - } - return; - } - r = mOrderedBroadcasts.get(0); - boolean forceReceive = false; - - // Ensure that even if something goes awry with the timeout - // detection, we catch "hung" broadcasts here, discard them, - // and continue to make progress. - // - // This is only done if the system is ready so that PRE_BOOT_COMPLETED - // receivers don't get executed with timeouts. They're intended for - // one time heavy lifting after system upgrades and can take - // significant amounts of time. - int numReceivers = (r.receivers != null) ? r.receivers.size() : 0; - if (mService.mProcessesReady && r.dispatchTime > 0) { - long now = SystemClock.uptimeMillis(); - if ((numReceivers > 0) && - (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) { - Slog.w(TAG, "Hung broadcast [" - + mQueueName + "] discarded after timeout failure:" - + " now=" + now - + " dispatchTime=" + r.dispatchTime - + " startTime=" + r.receiverTime - + " intent=" + r.intent - + " numReceivers=" + numReceivers - + " nextReceiver=" + r.nextReceiver - + " state=" + r.state); - broadcastTimeoutLocked(false); // forcibly finish this broadcast - forceReceive = true; - r.state = BroadcastRecord.IDLE; - } - } - - if (r.state != BroadcastRecord.IDLE) { - if (DEBUG_BROADCAST) Slog.d(TAG_BROADCAST, - "processNextBroadcast(" - + mQueueName + ") called when not idle (state=" - + r.state + ")"); - return; - } - - if (r.receivers == null || r.nextReceiver >= numReceivers - || r.resultAbort || forceReceive) { - // No more receivers for this broadcast! Send the final - // result if requested... - if (r.resultTo != null) { - try { - if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST, - "Finishing broadcast [" + mQueueName + "] " - + r.intent.getAction() + " app=" + r.callerApp); - performReceiveLocked(r.callerApp, r.resultTo, - new Intent(r.intent), r.resultCode, - r.resultData, r.resultExtras, false, false, r.userId); - // Set this to null so that the reference - // (local and remote) isn't kept in the mBroadcastHistory. - r.resultTo = null; - } catch (RemoteException e) { - r.resultTo = null; - Slog.w(TAG, "Failure [" - + mQueueName + "] sending broadcast result of " - + r.intent, e); - - } - } - - if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Cancelling BROADCAST_TIMEOUT_MSG"); - cancelBroadcastTimeoutLocked(); - - if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, - "Finished with ordered broadcast " + r); - - // ... and on to the next... - addBroadcastToHistoryLocked(r); - if (r.intent.getComponent() == null && r.intent.getPackage() == null - && (r.intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { - // This was an implicit broadcast... let's record it for posterity. - mService.addBroadcastStatLocked(r.intent.getAction(), r.callerPackage, - r.manifestCount, r.manifestSkipCount, r.finishTime-r.dispatchTime); - } - mOrderedBroadcasts.remove(0); - r = null; - looped = true; - continue; - } - } while (r == null); - - // Get the next receiver... - int recIdx = r.nextReceiver++; - - // Keep track of when this receiver started, and make sure there - // is a timeout message pending to kill it if need be. - r.receiverTime = SystemClock.uptimeMillis(); - if (recIdx == 0) { - r.dispatchTime = r.receiverTime; - r.dispatchClockTime = System.currentTimeMillis(); - if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) { - Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, - createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING), - System.identityHashCode(r)); - Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, - createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_DELIVERED), - System.identityHashCode(r)); - } - if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing ordered broadcast [" - + mQueueName + "] " + r); - } - if (! mPendingBroadcastTimeoutMessage) { - long timeoutTime = r.receiverTime + mTimeoutPeriod; - if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, - "Submitting BROADCAST_TIMEOUT_MSG [" - + mQueueName + "] for " + r + " at " + timeoutTime); - setBroadcastTimeoutLocked(timeoutTime); - } - - final BroadcastOptions brOptions = r.options; - final Object nextReceiver = r.receivers.get(recIdx); - - if (nextReceiver instanceof BroadcastFilter) { - // Simple case: this is a registered receiver who gets - // a direct call. - BroadcastFilter filter = (BroadcastFilter)nextReceiver; + final int N = r.receivers.size(); + if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast [" + + mQueueName + "] " + r); + for (int i=0; i 0) { + synchronized (mService.mPidsSelfLocked) { + ProcessRecord proc = mService.mPidsSelfLocked.get( + mPendingBroadcast.curApp.pid); + isDead = proc == null || proc.crashing; + } + } else { + final ProcessRecord proc = mService.mProcessNames.get( + mPendingBroadcast.curApp.processName, mPendingBroadcast.curApp.uid); + isDead = proc == null || !proc.pendingStart; + } + if (!isDead) { + // It's still alive, so keep waiting + return; + } else { + Slog.w(TAG, "pending app [" + + mQueueName + "]" + mPendingBroadcast.curApp + + " died before responding to broadcast"); + mPendingBroadcast.state = BroadcastRecord.IDLE; + mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex; + mPendingBroadcast = null; + } + } + + boolean looped = false; + + do { + if (mOrderedBroadcasts.size() == 0) { + // No more broadcasts pending, so all done! + mService.scheduleAppGcsLocked(); + if (looped) { + // If we had finished the last ordered broadcast, then + // make sure all processes have correct oom and sched + // adjustments. + mService.updateOomAdjLocked(); } return; } + r = mOrderedBroadcasts.get(0); + boolean forceReceive = false; - // Hard case: need to instantiate the receiver, possibly - // starting its application process to host it. + // Ensure that even if something goes awry with the timeout + // detection, we catch "hung" broadcasts here, discard them, + // and continue to make progress. + // + // This is only done if the system is ready so that PRE_BOOT_COMPLETED + // receivers don't get executed with timeouts. They're intended for + // one time heavy lifting after system upgrades and can take + // significant amounts of time. + int numReceivers = (r.receivers != null) ? r.receivers.size() : 0; + if (mService.mProcessesReady && r.dispatchTime > 0) { + long now = SystemClock.uptimeMillis(); + if ((numReceivers > 0) && + (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) { + Slog.w(TAG, "Hung broadcast [" + + mQueueName + "] discarded after timeout failure:" + + " now=" + now + + " dispatchTime=" + r.dispatchTime + + " startTime=" + r.receiverTime + + " intent=" + r.intent + + " numReceivers=" + numReceivers + + " nextReceiver=" + r.nextReceiver + + " state=" + r.state); + broadcastTimeoutLocked(false); // forcibly finish this broadcast + forceReceive = true; + r.state = BroadcastRecord.IDLE; + } + } - ResolveInfo info = - (ResolveInfo)nextReceiver; - ComponentName component = new ComponentName( - info.activityInfo.applicationInfo.packageName, - info.activityInfo.name); + if (r.state != BroadcastRecord.IDLE) { + if (DEBUG_BROADCAST) Slog.d(TAG_BROADCAST, + "processNextBroadcast(" + + mQueueName + ") called when not idle (state=" + + r.state + ")"); + return; + } - boolean skip = false; - if (brOptions != null && - (info.activityInfo.applicationInfo.targetSdkVersion - < brOptions.getMinManifestReceiverApiLevel() || - info.activityInfo.applicationInfo.targetSdkVersion - > brOptions.getMaxManifestReceiverApiLevel())) { + if (r.receivers == null || r.nextReceiver >= numReceivers + || r.resultAbort || forceReceive) { + // No more receivers for this broadcast! Send the final + // result if requested... + if (r.resultTo != null) { + try { + if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST, + "Finishing broadcast [" + mQueueName + "] " + + r.intent.getAction() + " app=" + r.callerApp); + performReceiveLocked(r.callerApp, r.resultTo, + new Intent(r.intent), r.resultCode, + r.resultData, r.resultExtras, false, false, r.userId); + // Set this to null so that the reference + // (local and remote) isn't kept in the mBroadcastHistory. + r.resultTo = null; + } catch (RemoteException e) { + r.resultTo = null; + Slog.w(TAG, "Failure [" + + mQueueName + "] sending broadcast result of " + + r.intent, e); + + } + } + + if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Cancelling BROADCAST_TIMEOUT_MSG"); + cancelBroadcastTimeoutLocked(); + + if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, + "Finished with ordered broadcast " + r); + + // ... and on to the next... + addBroadcastToHistoryLocked(r); + if (r.intent.getComponent() == null && r.intent.getPackage() == null + && (r.intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { + // This was an implicit broadcast... let's record it for posterity. + mService.addBroadcastStatLocked(r.intent.getAction(), r.callerPackage, + r.manifestCount, r.manifestSkipCount, r.finishTime-r.dispatchTime); + } + mOrderedBroadcasts.remove(0); + r = null; + looped = true; + continue; + } + } while (r == null); + + // Get the next receiver... + int recIdx = r.nextReceiver++; + + // Keep track of when this receiver started, and make sure there + // is a timeout message pending to kill it if need be. + r.receiverTime = SystemClock.uptimeMillis(); + if (recIdx == 0) { + r.dispatchTime = r.receiverTime; + r.dispatchClockTime = System.currentTimeMillis(); + if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) { + Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, + createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING), + System.identityHashCode(r)); + Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, + createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_DELIVERED), + System.identityHashCode(r)); + } + if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing ordered broadcast [" + + mQueueName + "] " + r); + } + if (! mPendingBroadcastTimeoutMessage) { + long timeoutTime = r.receiverTime + mTimeoutPeriod; + if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, + "Submitting BROADCAST_TIMEOUT_MSG [" + + mQueueName + "] for " + r + " at " + timeoutTime); + setBroadcastTimeoutLocked(timeoutTime); + } + + final BroadcastOptions brOptions = r.options; + final Object nextReceiver = r.receivers.get(recIdx); + + if (nextReceiver instanceof BroadcastFilter) { + // Simple case: this is a registered receiver who gets + // a direct call. + BroadcastFilter filter = (BroadcastFilter)nextReceiver; + if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, + "Delivering ordered [" + + mQueueName + "] to registered " + + filter + ": " + r); + deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx); + if (r.receiver == null || !r.ordered) { + // The receiver has already finished, so schedule to + // process the next one. + if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Quick finishing [" + + mQueueName + "]: ordered=" + + r.ordered + " receiver=" + r.receiver); + r.state = BroadcastRecord.IDLE; + scheduleBroadcastsLocked(); + } else { + if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) { + scheduleTempWhitelistLocked(filter.owningUid, + brOptions.getTemporaryAppWhitelistDuration(), r); + } + } + return; + } + + // Hard case: need to instantiate the receiver, possibly + // starting its application process to host it. + + ResolveInfo info = + (ResolveInfo)nextReceiver; + ComponentName component = new ComponentName( + info.activityInfo.applicationInfo.packageName, + info.activityInfo.name); + + boolean skip = false; + if (brOptions != null && + (info.activityInfo.applicationInfo.targetSdkVersion + < brOptions.getMinManifestReceiverApiLevel() || + info.activityInfo.applicationInfo.targetSdkVersion + > brOptions.getMaxManifestReceiverApiLevel())) { + skip = true; + } + int perm = mService.checkComponentPermission(info.activityInfo.permission, + r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid, + info.activityInfo.exported); + if (!skip && perm != PackageManager.PERMISSION_GRANTED) { + if (!info.activityInfo.exported) { + Slog.w(TAG, "Permission Denial: broadcasting " + + r.intent.toString() + + " from " + r.callerPackage + " (pid=" + r.callingPid + + ", uid=" + r.callingUid + ")" + + " is not exported from uid " + info.activityInfo.applicationInfo.uid + + " due to receiver " + component.flattenToShortString()); + } else { + Slog.w(TAG, "Permission Denial: broadcasting " + + r.intent.toString() + + " from " + r.callerPackage + " (pid=" + r.callingPid + + ", uid=" + r.callingUid + ")" + + " requires " + info.activityInfo.permission + + " due to receiver " + component.flattenToShortString()); + } + skip = true; + } else if (!skip && info.activityInfo.permission != null) { + final int opCode = AppOpsManager.permissionToOpCode(info.activityInfo.permission); + if (opCode != AppOpsManager.OP_NONE + && mService.mAppOpsService.noteOperation(opCode, r.callingUid, + r.callerPackage) != AppOpsManager.MODE_ALLOWED) { + Slog.w(TAG, "Appop Denial: broadcasting " + + r.intent.toString() + + " from " + r.callerPackage + " (pid=" + + r.callingPid + ", uid=" + r.callingUid + ")" + + " requires appop " + AppOpsManager.permissionToOp( + info.activityInfo.permission) + + " due to registered receiver " + + component.flattenToShortString()); skip = true; } - int perm = mService.checkComponentPermission(info.activityInfo.permission, - r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid, - info.activityInfo.exported); - if (!skip && perm != PackageManager.PERMISSION_GRANTED) { - if (!info.activityInfo.exported) { - Slog.w(TAG, "Permission Denial: broadcasting " - + r.intent.toString() - + " from " + r.callerPackage + " (pid=" + r.callingPid - + ", uid=" + r.callingUid + ")" - + " is not exported from uid " + info.activityInfo.applicationInfo.uid - + " due to receiver " + component.flattenToShortString()); - } else { - Slog.w(TAG, "Permission Denial: broadcasting " - + r.intent.toString() - + " from " + r.callerPackage + " (pid=" + r.callingPid - + ", uid=" + r.callingUid + ")" - + " requires " + info.activityInfo.permission - + " due to receiver " + component.flattenToShortString()); + } + if (!skip && info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID && + r.requiredPermissions != null && r.requiredPermissions.length > 0) { + for (int i = 0; i < r.requiredPermissions.length; i++) { + String requiredPermission = r.requiredPermissions[i]; + try { + perm = AppGlobals.getPackageManager(). + checkPermission(requiredPermission, + info.activityInfo.applicationInfo.packageName, + UserHandle + .getUserId(info.activityInfo.applicationInfo.uid)); + } catch (RemoteException e) { + perm = PackageManager.PERMISSION_DENIED; } - skip = true; - } else if (!skip && info.activityInfo.permission != null) { - final int opCode = AppOpsManager.permissionToOpCode(info.activityInfo.permission); - if (opCode != AppOpsManager.OP_NONE - && mService.mAppOpsService.noteOperation(opCode, r.callingUid, - r.callerPackage) != AppOpsManager.MODE_ALLOWED) { - Slog.w(TAG, "Appop Denial: broadcasting " - + r.intent.toString() - + " from " + r.callerPackage + " (pid=" - + r.callingPid + ", uid=" + r.callingUid + ")" + if (perm != PackageManager.PERMISSION_GRANTED) { + Slog.w(TAG, "Permission Denial: receiving " + + r.intent + " to " + + component.flattenToShortString() + + " requires " + requiredPermission + + " due to sender " + r.callerPackage + + " (uid " + r.callingUid + ")"); + skip = true; + break; + } + int appOp = AppOpsManager.permissionToOpCode(requiredPermission); + if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp + && mService.mAppOpsService.noteOperation(appOp, + info.activityInfo.applicationInfo.uid, info.activityInfo.packageName) + != AppOpsManager.MODE_ALLOWED) { + Slog.w(TAG, "Appop Denial: receiving " + + r.intent + " to " + + component.flattenToShortString() + " requires appop " + AppOpsManager.permissionToOp( - info.activityInfo.permission) - + " due to registered receiver " + requiredPermission) + + " due to sender " + r.callerPackage + + " (uid " + r.callingUid + ")"); + skip = true; + break; + } + } + } + if (!skip && r.appOp != AppOpsManager.OP_NONE + && mService.mAppOpsService.noteOperation(r.appOp, + info.activityInfo.applicationInfo.uid, info.activityInfo.packageName) + != AppOpsManager.MODE_ALLOWED) { + Slog.w(TAG, "Appop Denial: receiving " + + r.intent + " to " + + component.flattenToShortString() + + " requires appop " + AppOpsManager.opToName(r.appOp) + + " due to sender " + r.callerPackage + + " (uid " + r.callingUid + ")"); + skip = true; + } + if (!skip) { + skip = !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid, + r.callingPid, r.resolvedType, info.activityInfo.applicationInfo.uid); + } + boolean isSingleton = false; + try { + isSingleton = mService.isSingleton(info.activityInfo.processName, + info.activityInfo.applicationInfo, + info.activityInfo.name, info.activityInfo.flags); + } catch (SecurityException e) { + Slog.w(TAG, e.getMessage()); + skip = true; + } + if ((info.activityInfo.flags&ActivityInfo.FLAG_SINGLE_USER) != 0) { + if (ActivityManager.checkUidPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS, + info.activityInfo.applicationInfo.uid) + != PackageManager.PERMISSION_GRANTED) { + Slog.w(TAG, "Permission Denial: Receiver " + component.flattenToShortString() + + " requests FLAG_SINGLE_USER, but app does not hold " + + android.Manifest.permission.INTERACT_ACROSS_USERS); + skip = true; + } + } + if (!skip && info.activityInfo.applicationInfo.isInstantApp() + && r.callingUid != info.activityInfo.applicationInfo.uid) { + Slog.w(TAG, "Instant App Denial: receiving " + + r.intent + + " to " + component.flattenToShortString() + + " due to sender " + r.callerPackage + + " (uid " + r.callingUid + ")" + + " Instant Apps do not support manifest receivers"); + skip = true; + } + if (!skip && r.callerInstantApp + && (info.activityInfo.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) == 0 + && r.callingUid != info.activityInfo.applicationInfo.uid) { + Slog.w(TAG, "Instant App Denial: receiving " + + r.intent + + " to " + component.flattenToShortString() + + " requires receiver have visibleToInstantApps set" + + " due to sender " + r.callerPackage + + " (uid " + r.callingUid + ")"); + skip = true; + } + if (r.curApp != null && r.curApp.crashing) { + // If the target process is crashing, just skip it. + Slog.w(TAG, "Skipping deliver ordered [" + mQueueName + "] " + r + + " to " + r.curApp + ": process crashing"); + skip = true; + } + if (!skip) { + boolean isAvailable = false; + try { + isAvailable = AppGlobals.getPackageManager().isPackageAvailable( + info.activityInfo.packageName, + UserHandle.getUserId(info.activityInfo.applicationInfo.uid)); + } catch (Exception e) { + // all such failures mean we skip this receiver + Slog.w(TAG, "Exception getting recipient info for " + + info.activityInfo.packageName, e); + } + if (!isAvailable) { + if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, + "Skipping delivery to " + info.activityInfo.packageName + " / " + + info.activityInfo.applicationInfo.uid + + " : package no longer available"); + skip = true; + } + } + + // If permissions need a review before any of the app components can run, we drop + // the broadcast and if the calling app is in the foreground and the broadcast is + // explicit we launch the review UI passing it a pending intent to send the skipped + // broadcast. + if (mService.mPermissionReviewRequired && !skip) { + if (!requestStartTargetPermissionsReviewIfNeededLocked(r, + info.activityInfo.packageName, UserHandle.getUserId( + info.activityInfo.applicationInfo.uid))) { + skip = true; + } + } + + // This is safe to do even if we are skipping the broadcast, and we need + // this information now to evaluate whether it is going to be allowed to run. + final int receiverUid = info.activityInfo.applicationInfo.uid; + // If it's a singleton, it needs to be the same app or a special app + if (r.callingUid != Process.SYSTEM_UID && isSingleton + && mService.isValidSingletonCall(r.callingUid, receiverUid)) { + info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, 0); + } + String targetProcess = info.activityInfo.processName; + ProcessRecord app = mService.getProcessRecordLocked(targetProcess, + info.activityInfo.applicationInfo.uid, false); + + if (!skip) { + final int allowed = mService.getAppStartModeLocked( + info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, + info.activityInfo.applicationInfo.targetSdkVersion, -1, true, false, false); + if (allowed != ActivityManager.APP_START_MODE_NORMAL) { + // We won't allow this receiver to be launched if the app has been + // completely disabled from launches, or it was not explicitly sent + // to it and the app is in a state that should not receive it + // (depending on how getAppStartModeLocked has determined that). + if (allowed == ActivityManager.APP_START_MODE_DISABLED) { + Slog.w(TAG, "Background execution disabled: receiving " + + r.intent + " to " + + component.flattenToShortString()); + skip = true; + } else if (((r.intent.getFlags()&Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND) != 0) + || (r.intent.getComponent() == null + && r.intent.getPackage() == null + && ((r.intent.getFlags() + & Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) == 0) + && !isSignaturePerm(r.requiredPermissions))) { + mService.addBackgroundCheckViolationLocked(r.intent.getAction(), + component.getPackageName()); + Slog.w(TAG, "Background execution not allowed: receiving " + + r.intent + " to " + component.flattenToShortString()); skip = true; } } - if (!skip && info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID && - r.requiredPermissions != null && r.requiredPermissions.length > 0) { - for (int i = 0; i < r.requiredPermissions.length; i++) { - String requiredPermission = r.requiredPermissions[i]; - try { - perm = AppGlobals.getPackageManager(). - checkPermission(requiredPermission, - info.activityInfo.applicationInfo.packageName, - UserHandle - .getUserId(info.activityInfo.applicationInfo.uid)); - } catch (RemoteException e) { - perm = PackageManager.PERMISSION_DENIED; - } - if (perm != PackageManager.PERMISSION_GRANTED) { - Slog.w(TAG, "Permission Denial: receiving " - + r.intent + " to " - + component.flattenToShortString() - + " requires " + requiredPermission - + " due to sender " + r.callerPackage - + " (uid " + r.callingUid + ")"); - skip = true; - break; - } - int appOp = AppOpsManager.permissionToOpCode(requiredPermission); - if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp - && mService.mAppOpsService.noteOperation(appOp, - info.activityInfo.applicationInfo.uid, info.activityInfo.packageName) - != AppOpsManager.MODE_ALLOWED) { - Slog.w(TAG, "Appop Denial: receiving " - + r.intent + " to " - + component.flattenToShortString() - + " requires appop " + AppOpsManager.permissionToOp( - requiredPermission) - + " due to sender " + r.callerPackage - + " (uid " + r.callingUid + ")"); - skip = true; - break; - } - } - } - if (!skip && r.appOp != AppOpsManager.OP_NONE - && mService.mAppOpsService.noteOperation(r.appOp, - info.activityInfo.applicationInfo.uid, info.activityInfo.packageName) - != AppOpsManager.MODE_ALLOWED) { - Slog.w(TAG, "Appop Denial: receiving " - + r.intent + " to " - + component.flattenToShortString() - + " requires appop " + AppOpsManager.opToName(r.appOp) - + " due to sender " + r.callerPackage - + " (uid " + r.callingUid + ")"); - skip = true; - } - if (!skip) { - skip = !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid, - r.callingPid, r.resolvedType, info.activityInfo.applicationInfo.uid); - } - boolean isSingleton = false; - try { - isSingleton = mService.isSingleton(info.activityInfo.processName, - info.activityInfo.applicationInfo, - info.activityInfo.name, info.activityInfo.flags); - } catch (SecurityException e) { - Slog.w(TAG, e.getMessage()); - skip = true; - } - if ((info.activityInfo.flags&ActivityInfo.FLAG_SINGLE_USER) != 0) { - if (ActivityManager.checkUidPermission( - android.Manifest.permission.INTERACT_ACROSS_USERS, - info.activityInfo.applicationInfo.uid) - != PackageManager.PERMISSION_GRANTED) { - Slog.w(TAG, "Permission Denial: Receiver " + component.flattenToShortString() - + " requests FLAG_SINGLE_USER, but app does not hold " - + android.Manifest.permission.INTERACT_ACROSS_USERS); - skip = true; - } - } - if (!skip && info.activityInfo.applicationInfo.isInstantApp() - && r.callingUid != info.activityInfo.applicationInfo.uid) { - Slog.w(TAG, "Instant App Denial: receiving " - + r.intent - + " to " + component.flattenToShortString() - + " due to sender " + r.callerPackage - + " (uid " + r.callingUid + ")" - + " Instant Apps do not support manifest receivers"); - skip = true; - } - if (!skip && r.callerInstantApp - && (info.activityInfo.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) == 0 - && r.callingUid != info.activityInfo.applicationInfo.uid) { - Slog.w(TAG, "Instant App Denial: receiving " - + r.intent - + " to " + component.flattenToShortString() - + " requires receiver have visibleToInstantApps set" - + " due to sender " + r.callerPackage - + " (uid " + r.callingUid + ")"); - skip = true; - } - if (r.curApp != null && r.curApp.crashing) { - // If the target process is crashing, just skip it. - Slog.w(TAG, "Skipping deliver ordered [" + mQueueName + "] " + r - + " to " + r.curApp + ": process crashing"); - skip = true; - } - if (!skip) { - boolean isAvailable = false; - try { - isAvailable = AppGlobals.getPackageManager().isPackageAvailable( - info.activityInfo.packageName, - UserHandle.getUserId(info.activityInfo.applicationInfo.uid)); - } catch (Exception e) { - // all such failures mean we skip this receiver - Slog.w(TAG, "Exception getting recipient info for " - + info.activityInfo.packageName, e); - } - if (!isAvailable) { - if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, - "Skipping delivery to " + info.activityInfo.packageName + " / " - + info.activityInfo.applicationInfo.uid - + " : package no longer available"); - skip = true; - } - } + } - // If permissions need a review before any of the app components can run, we drop - // the broadcast and if the calling app is in the foreground and the broadcast is - // explicit we launch the review UI passing it a pending intent to send the skipped - // broadcast. - if (mService.mPermissionReviewRequired && !skip) { - if (!requestStartTargetPermissionsReviewIfNeededLocked(r, - info.activityInfo.packageName, UserHandle.getUserId( - info.activityInfo.applicationInfo.uid))) { - skip = true; - } - } + if (!skip && !Intent.ACTION_SHUTDOWN.equals(r.intent.getAction()) + && !mService.mUserController + .isUserRunning(UserHandle.getUserId(info.activityInfo.applicationInfo.uid), + 0 /* flags */)) { + skip = true; + Slog.w(TAG, + "Skipping delivery to " + info.activityInfo.packageName + " / " + + info.activityInfo.applicationInfo.uid + " : user is not running"); + } - // This is safe to do even if we are skipping the broadcast, and we need - // this information now to evaluate whether it is going to be allowed to run. - final int receiverUid = info.activityInfo.applicationInfo.uid; - // If it's a singleton, it needs to be the same app or a special app - if (r.callingUid != Process.SYSTEM_UID && isSingleton - && mService.isValidSingletonCall(r.callingUid, receiverUid)) { - info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, 0); - } - String targetProcess = info.activityInfo.processName; - ProcessRecord app = mService.getProcessRecordLocked(targetProcess, - info.activityInfo.applicationInfo.uid, false); - - if (!skip) { - final int allowed = mService.getAppStartModeLocked( - info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, - info.activityInfo.applicationInfo.targetSdkVersion, -1, true, false, false); - if (allowed != ActivityManager.APP_START_MODE_NORMAL) { - // We won't allow this receiver to be launched if the app has been - // completely disabled from launches, or it was not explicitly sent - // to it and the app is in a state that should not receive it - // (depending on how getAppStartModeLocked has determined that). - if (allowed == ActivityManager.APP_START_MODE_DISABLED) { - Slog.w(TAG, "Background execution disabled: receiving " - + r.intent + " to " - + component.flattenToShortString()); - skip = true; - } else if (((r.intent.getFlags()&Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND) != 0) - || (r.intent.getComponent() == null - && r.intent.getPackage() == null - && ((r.intent.getFlags() - & Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) == 0) - && !isSignaturePerm(r.requiredPermissions))) { - mService.addBackgroundCheckViolationLocked(r.intent.getAction(), - component.getPackageName()); - Slog.w(TAG, "Background execution not allowed: receiving " - + r.intent + " to " - + component.flattenToShortString()); - skip = true; - } - } - } - - if (!skip && !Intent.ACTION_SHUTDOWN.equals(r.intent.getAction()) - && !mService.mUserController - .isUserRunning(UserHandle.getUserId(info.activityInfo.applicationInfo.uid), - 0 /* flags */)) { - skip = true; - Slog.w(TAG, - "Skipping delivery to " + info.activityInfo.packageName + " / " - + info.activityInfo.applicationInfo.uid + " : user is not running"); - } - - if (skip) { - if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, - "Skipping delivery of ordered [" + mQueueName + "] " - + r + " for whatever reason"); - r.delivery[recIdx] = BroadcastRecord.DELIVERY_SKIPPED; - r.receiver = null; - r.curFilter = null; - r.state = BroadcastRecord.IDLE; - r.manifestSkipCount++; - scheduleBroadcastsLocked(); - return; - } - r.manifestCount++; - - r.delivery[recIdx] = BroadcastRecord.DELIVERY_DELIVERED; - r.state = BroadcastRecord.APP_RECEIVE; - r.curComponent = component; - r.curReceiver = info.activityInfo; - if (DEBUG_MU && r.callingUid > UserHandle.PER_USER_RANGE) { - Slog.v(TAG_MU, "Updated broadcast record activity info for secondary user, " - + info.activityInfo + ", callingUid = " + r.callingUid + ", uid = " - + receiverUid); - } - - if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) { - scheduleTempWhitelistLocked(receiverUid, - brOptions.getTemporaryAppWhitelistDuration(), r); - } - - // Broadcast is being executed, its package can't be stopped. - try { - AppGlobals.getPackageManager().setPackageStoppedState( - r.curComponent.getPackageName(), false, UserHandle.getUserId(r.callingUid)); - } catch (RemoteException e) { - } catch (IllegalArgumentException e) { - Slog.w(TAG, "Failed trying to unstop package " - + r.curComponent.getPackageName() + ": " + e); - } - - // Is this receiver's application already running? - if (app != null && app.thread != null && !app.killed) { - try { - app.addPackage(info.activityInfo.packageName, - info.activityInfo.applicationInfo.versionCode, mService.mProcessStats); - processCurBroadcastLocked(r, app); - return; - } catch (RemoteException e) { - Slog.w(TAG, "Exception when sending broadcast to " - + r.curComponent, e); - } catch (RuntimeException e) { - Slog.wtf(TAG, "Failed sending broadcast to " - + r.curComponent + " with " + r.intent, e); - // If some unexpected exception happened, just skip - // this broadcast. At this point we are not in the call - // from a client, so throwing an exception out from here - // will crash the entire system instead of just whoever - // sent the broadcast. - logBroadcastReceiverDiscardLocked(r); - finishReceiverLocked(r, r.resultCode, r.resultData, - r.resultExtras, r.resultAbort, false); - scheduleBroadcastsLocked(); - // We need to reset the state if we failed to start the receiver. - r.state = BroadcastRecord.IDLE; - return; - } - - // If a dead object exception was thrown -- fall through to - // restart the application. - } - - // Not running -- get it started, to be executed when the app comes up. + if (skip) { if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, - "Need to start app [" - + mQueueName + "] " + targetProcess + " for broadcast " + r); - if ((r.curApp=mService.startProcessLocked(targetProcess, - info.activityInfo.applicationInfo, true, - r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND, - "broadcast", r.curComponent, - (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false)) - == null) { - // Ah, this recipient is unavailable. Finish it if necessary, - // and mark the broadcast record as ready for the next. - Slog.w(TAG, "Unable to launch app " - + info.activityInfo.applicationInfo.packageName + "/" - + receiverUid + " for broadcast " - + r.intent + ": process is bad"); + "Skipping delivery of ordered [" + mQueueName + "] " + + r + " for whatever reason"); + r.delivery[recIdx] = BroadcastRecord.DELIVERY_SKIPPED; + r.receiver = null; + r.curFilter = null; + r.state = BroadcastRecord.IDLE; + r.manifestSkipCount++; + scheduleBroadcastsLocked(); + return; + } + r.manifestCount++; + + r.delivery[recIdx] = BroadcastRecord.DELIVERY_DELIVERED; + r.state = BroadcastRecord.APP_RECEIVE; + r.curComponent = component; + r.curReceiver = info.activityInfo; + if (DEBUG_MU && r.callingUid > UserHandle.PER_USER_RANGE) { + Slog.v(TAG_MU, "Updated broadcast record activity info for secondary user, " + + info.activityInfo + ", callingUid = " + r.callingUid + ", uid = " + + receiverUid); + } + + if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) { + scheduleTempWhitelistLocked(receiverUid, + brOptions.getTemporaryAppWhitelistDuration(), r); + } + + // Broadcast is being executed, its package can't be stopped. + try { + AppGlobals.getPackageManager().setPackageStoppedState( + r.curComponent.getPackageName(), false, UserHandle.getUserId(r.callingUid)); + } catch (RemoteException e) { + } catch (IllegalArgumentException e) { + Slog.w(TAG, "Failed trying to unstop package " + + r.curComponent.getPackageName() + ": " + e); + } + + // Is this receiver's application already running? + if (app != null && app.thread != null && !app.killed) { + try { + app.addPackage(info.activityInfo.packageName, + info.activityInfo.applicationInfo.versionCode, mService.mProcessStats); + processCurBroadcastLocked(r, app, skipOomAdj); + return; + } catch (RemoteException e) { + Slog.w(TAG, "Exception when sending broadcast to " + + r.curComponent, e); + } catch (RuntimeException e) { + Slog.wtf(TAG, "Failed sending broadcast to " + + r.curComponent + " with " + r.intent, e); + // If some unexpected exception happened, just skip + // this broadcast. At this point we are not in the call + // from a client, so throwing an exception out from here + // will crash the entire system instead of just whoever + // sent the broadcast. logBroadcastReceiverDiscardLocked(r); finishReceiverLocked(r, r.resultCode, r.resultData, r.resultExtras, r.resultAbort, false); scheduleBroadcastsLocked(); + // We need to reset the state if we failed to start the receiver. r.state = BroadcastRecord.IDLE; return; } - mPendingBroadcast = r; - mPendingBroadcastRecvIndex = recIdx; + // If a dead object exception was thrown -- fall through to + // restart the application. } + + // Not running -- get it started, to be executed when the app comes up. + if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, + "Need to start app [" + + mQueueName + "] " + targetProcess + " for broadcast " + r); + if ((r.curApp=mService.startProcessLocked(targetProcess, + info.activityInfo.applicationInfo, true, + r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND, + "broadcast", r.curComponent, + (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false)) + == null) { + // Ah, this recipient is unavailable. Finish it if necessary, + // and mark the broadcast record as ready for the next. + Slog.w(TAG, "Unable to launch app " + + info.activityInfo.applicationInfo.packageName + "/" + + receiverUid + " for broadcast " + + r.intent + ": process is bad"); + logBroadcastReceiverDiscardLocked(r); + finishReceiverLocked(r, r.resultCode, r.resultData, + r.resultExtras, r.resultAbort, false); + scheduleBroadcastsLocked(); + r.state = BroadcastRecord.IDLE; + return; + } + + mPendingBroadcast = r; + mPendingBroadcastRecvIndex = recIdx; } final void setBroadcastTimeoutLocked(long timeoutTime) {