diff options
author | Dianne Hackborn <hackbod@google.com> | 2013-09-18 20:34:11 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2013-09-18 20:34:11 +0000 |
commit | b9466db4a56564101a26865962dda87aaeab56ff (patch) | |
tree | 7a36c64edcba8c55988f074f799826e4a497cef9 /services/java/com/android/server/am | |
parent | bd49a1dadfbd7803642066a5bdc74305a1b2340b (diff) | |
parent | 6285a32f74890b761579b4f67afde1b08763fd0a (diff) | |
download | frameworks_base-b9466db4a56564101a26865962dda87aaeab56ff.zip frameworks_base-b9466db4a56564101a26865962dda87aaeab56ff.tar.gz frameworks_base-b9466db4a56564101a26865962dda87aaeab56ff.tar.bz2 |
Merge "Finish issue #10779747: Calendar Storage crash observed..." into klp-dev
Diffstat (limited to 'services/java/com/android/server/am')
4 files changed, 109 insertions, 44 deletions
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java index 37fbb13..fea7623 100644 --- a/services/java/com/android/server/am/ActiveServices.java +++ b/services/java/com/android/server/am/ActiveServices.java @@ -143,6 +143,7 @@ public final class ActiveServices { * Information about services for a single user. */ class ServiceMap extends Handler { + final int mUserId; final ArrayMap<ComponentName, ServiceRecord> mServicesByName = new ArrayMap<ComponentName, ServiceRecord>(); final ArrayMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent @@ -165,6 +166,10 @@ public final class ActiveServices { static final int MSG_BG_START_TIMEOUT = 1; + ServiceMap(int userId) { + mUserId = userId; + } + @Override public void handleMessage(Message msg) { switch (msg.what) { @@ -224,6 +229,9 @@ public final class ActiveServices { Message msg = obtainMessage(MSG_BG_START_TIMEOUT); sendMessageAtTime(msg, when); } + if (mStartingBackground.size() < mMaxStartingBackground) { + mAm.backgroundServicesFinishedLocked(mUserId); + } } } @@ -239,10 +247,15 @@ public final class ActiveServices { return getServiceMap(callingUser).mServicesByName.get(name); } + boolean hasBackgroundServices(int callingUser) { + ServiceMap smap = mServiceMap.get(callingUser); + return smap != null ? smap.mStartingBackground.size() >= mMaxStartingBackground : false; + } + private ServiceMap getServiceMap(int callingUser) { ServiceMap smap = mServiceMap.get(callingUser); if (smap == null) { - smap = new ServiceMap(); + smap = new ServiceMap(callingUser); mServiceMap.put(callingUser, smap); } return smap; diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 80f4b00..676b330 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -1903,8 +1903,8 @@ public final class ActivityManagerService extends ActivityManagerNative private ActivityManagerService() { Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass()); - mFgBroadcastQueue = new BroadcastQueue(this, "foreground", BROADCAST_FG_TIMEOUT); - mBgBroadcastQueue = new BroadcastQueue(this, "background", BROADCAST_BG_TIMEOUT); + mFgBroadcastQueue = new BroadcastQueue(this, "foreground", BROADCAST_FG_TIMEOUT, false); + mBgBroadcastQueue = new BroadcastQueue(this, "background", BROADCAST_BG_TIMEOUT, true); mBroadcastQueues[0] = mFgBroadcastQueue; mBroadcastQueues[1] = mBgBroadcastQueue; @@ -4910,6 +4910,7 @@ public final class ActivityManagerService extends ActivityManagerNative final int userId = mStartedUsers.keyAt(i); Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED, null); intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); + intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT); broadcastIntentLocked(null, null, intent, null, new IIntentReceiver.Stub() { @Override @@ -4924,7 +4925,7 @@ public final class ActivityManagerService extends ActivityManagerNative }, 0, null, null, android.Manifest.permission.RECEIVE_BOOT_COMPLETED, - AppOpsManager.OP_NONE, false, false, MY_PID, Process.SYSTEM_UID, + AppOpsManager.OP_NONE, true, false, MY_PID, Process.SYSTEM_UID, userId); } } @@ -12578,14 +12579,13 @@ public final class ActivityManagerService extends ActivityManagerNative boolean doTrim = false; synchronized(this) { - ReceiverList rl - = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder()); + ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder()); if (rl != null) { if (rl.curBroadcast != null) { BroadcastRecord r = rl.curBroadcast; final boolean doNext = finishReceiverLocked( receiver.asBinder(), r.resultCode, r.resultData, - r.resultExtras, r.resultAbort, true); + r.resultExtras, r.resultAbort); if (doNext) { doTrim = true; r.queue.processNextBroadcast(false); @@ -13212,16 +13212,20 @@ public final class ActivityManagerService extends ActivityManagerNative } private final boolean finishReceiverLocked(IBinder receiver, int resultCode, - String resultData, Bundle resultExtras, boolean resultAbort, - boolean explicit) { + String resultData, Bundle resultExtras, boolean resultAbort) { final BroadcastRecord r = broadcastRecordForReceiverLocked(receiver); if (r == null) { Slog.w(TAG, "finishReceiver called but not found on queue"); return false; } - return r.queue.finishReceiverLocked(r, resultCode, resultData, resultExtras, resultAbort, - explicit); + return r.queue.finishReceiverLocked(r, resultCode, resultData, resultExtras, resultAbort, false); + } + + void backgroundServicesFinishedLocked(int userId) { + for (BroadcastQueue queue : mBroadcastQueues) { + queue.backgroundServicesFinishedLocked(userId); + } } public void finishReceiver(IBinder who, int resultCode, String resultData, @@ -13236,7 +13240,7 @@ public final class ActivityManagerService extends ActivityManagerNative final long origId = Binder.clearCallingIdentity(); try { boolean doNext = false; - BroadcastRecord r = null; + BroadcastRecord r; synchronized(this) { r = broadcastRecordForReceiverLocked(who); @@ -15704,10 +15708,11 @@ public final class ActivityManagerService extends ActivityManagerNative final int userId = uss.mHandle.getIdentifier(); Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED, null); intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); + intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT); broadcastIntentLocked(null, null, intent, null, null, 0, null, null, android.Manifest.permission.RECEIVE_BOOT_COMPLETED, AppOpsManager.OP_NONE, - false, false, MY_PID, Process.SYSTEM_UID, userId); + true, false, MY_PID, Process.SYSTEM_UID, userId); } int num = mUserLru.size(); int i = 0; diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java index 254a219..b35ca79 100644 --- a/services/java/com/android/server/am/BroadcastQueue.java +++ b/services/java/com/android/server/am/BroadcastQueue.java @@ -54,8 +54,9 @@ public final class BroadcastQueue { static final boolean DEBUG_BROADCAST_LIGHT = ActivityManagerService.DEBUG_BROADCAST_LIGHT; static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU; - static final int MAX_BROADCAST_HISTORY = 25; - static final int MAX_BROADCAST_SUMMARY_HISTORY = 100; + static final int MAX_BROADCAST_HISTORY = ActivityManager.isLowRamDeviceStatic() ? 10 : 25; + static final int MAX_BROADCAST_SUMMARY_HISTORY + = ActivityManager.isLowRamDeviceStatic() ? 25 : 100; final ActivityManagerService mService; @@ -70,14 +71,20 @@ public final class BroadcastQueue { final long mTimeoutPeriod; /** + * If true, we can delay broadcasts while waiting services to finish in the previous + * receiver's process. + */ + final boolean mDelayBehindServices; + + /** * Lists of all active broadcasts that are to be executed immediately * (without waiting for another broadcast to finish). Currently this only * contains broadcasts to registered receivers, to avoid spinning up * a bunch of processes to execute IntentReceiver components. Background- * and foreground-priority broadcasts are queued separately. */ - final ArrayList<BroadcastRecord> mParallelBroadcasts - = new ArrayList<BroadcastRecord>(); + final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<BroadcastRecord>(); + /** * List of all active broadcasts that are to be executed one at a time. * The object at the top of the list is the currently activity broadcasts; @@ -85,20 +92,17 @@ public final class BroadcastQueue { * broadcasts, separate background- and foreground-priority queues are * maintained. */ - final ArrayList<BroadcastRecord> mOrderedBroadcasts - = new ArrayList<BroadcastRecord>(); + final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<BroadcastRecord>(); /** * Historical data of past broadcasts, for debugging. */ - final BroadcastRecord[] mBroadcastHistory - = new BroadcastRecord[MAX_BROADCAST_HISTORY]; + final BroadcastRecord[] mBroadcastHistory = new BroadcastRecord[MAX_BROADCAST_HISTORY]; /** * Summary of historical data of past broadcasts, for debugging. */ - final Intent[] mBroadcastSummaryHistory - = new Intent[MAX_BROADCAST_SUMMARY_HISTORY]; + final Intent[] mBroadcastSummaryHistory = new Intent[MAX_BROADCAST_SUMMARY_HISTORY]; /** * Set when we current have a BROADCAST_INTENT_MSG in flight. @@ -128,10 +132,6 @@ public final class BroadcastQueue { static final int BROADCAST_TIMEOUT_MSG = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG + 1; final Handler mHandler = new Handler() { - //public Handler() { - // if (localLOGV) Slog.v(TAG, "Handler started!"); - //} - public void handleMessage(Message msg) { switch (msg.what) { case BROADCAST_INTENT_MSG: { @@ -163,10 +163,12 @@ public final class BroadcastQueue { } } - BroadcastQueue(ActivityManagerService service, String name, long timeoutPeriod) { + BroadcastQueue(ActivityManagerService service, String name, long timeoutPeriod, + boolean allowDelayBehindServices) { mService = service; mQueueName = name; mTimeoutPeriod = timeoutPeriod; + mDelayBehindServices = allowDelayBehindServices; } public boolean isPendingBroadcastProcessLocked(int pid) { @@ -260,7 +262,7 @@ public final class BroadcastQueue { + br.curComponent.flattenToShortString(), e); logBroadcastReceiverDiscardLocked(br); finishReceiverLocked(br, br.resultCode, br.resultData, - br.resultExtras, br.resultAbort, true); + br.resultExtras, br.resultAbort, false); scheduleBroadcastsLocked(); // We need to reset the state if we failed to start the receiver. br.state = BroadcastRecord.IDLE; @@ -289,7 +291,7 @@ public final class BroadcastQueue { // let the broadcast continue. logBroadcastReceiverDiscardLocked(r); finishReceiverLocked(r, r.resultCode, r.resultData, - r.resultExtras, r.resultAbort, true); + r.resultExtras, r.resultAbort, false); reschedule = true; } @@ -299,7 +301,7 @@ public final class BroadcastQueue { "[" + mQueueName + "] skip & discard pending app " + r); logBroadcastReceiverDiscardLocked(r); finishReceiverLocked(r, r.resultCode, r.resultData, - r.resultExtras, r.resultAbort, true); + r.resultExtras, r.resultAbort, false); reschedule = true; } if (reschedule) { @@ -330,14 +332,11 @@ public final class BroadcastQueue { } public boolean finishReceiverLocked(BroadcastRecord r, int resultCode, - String resultData, Bundle resultExtras, boolean resultAbort, - boolean explicit) { - int state = r.state; + String resultData, Bundle resultExtras, boolean resultAbort, boolean waitForServices) { + final int state = r.state; r.state = BroadcastRecord.IDLE; if (state == BroadcastRecord.IDLE) { - if (explicit) { - Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE"); - } + Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE"); } r.receiver = null; r.intent.setComponent(null); @@ -348,15 +347,35 @@ public final class BroadcastQueue { r.curFilter.receiverList.curBroadcast = null; } r.curFilter = null; - r.curApp = null; - r.curComponent = null; r.curReceiver = null; + r.curApp = null; mPendingBroadcast = null; r.resultCode = resultCode; r.resultData = resultData; r.resultExtras = resultExtras; - r.resultAbort = resultAbort; + if (resultAbort && (r.intent.getFlags()&Intent.FLAG_RECEIVER_NO_ABORT) == 0) { + r.resultAbort = resultAbort; + } else { + r.resultAbort = false; + } + + if (waitForServices && r.curComponent != null && r.queue.mDelayBehindServices + && r.queue.mOrderedBroadcasts.size() > 0 + && r.queue.mOrderedBroadcasts.get(0) == r) { + // In this case, we are ready to process the next receiver for the current broadcast, + // but are on a queue that would like to wait for services to finish before moving + // on. If there are background services currently starting, then we will go into a + // special state where we hold off on continuing this broadcast until they are done. + if (mService.mServices.hasBackgroundServices(r.userId)) { + Slog.i(ActivityManagerService.TAG, "Delay finish: " + + r.curComponent.flattenToShortString()); + r.state = BroadcastRecord.WAITING_SERVICES; + return false; + } + } + + r.curComponent = null; // We will process the next receiver right now if this is finishing // an app receiver (which is always asynchronous) or after we have @@ -365,6 +384,18 @@ public final class BroadcastQueue { || state == BroadcastRecord.CALL_DONE_RECEIVE; } + public void backgroundServicesFinishedLocked(int userId) { + if (mOrderedBroadcasts.size() > 0) { + BroadcastRecord br = mOrderedBroadcasts.get(0); + if (br.userId == userId && br.state == BroadcastRecord.WAITING_SERVICES) { + Slog.i(ActivityManagerService.TAG, "Resuming delayed broadcast"); + br.curComponent = null; + br.state = BroadcastRecord.IDLE; + processNextBroadcast(false); + } + } + } + private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver, Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) throws RemoteException { @@ -821,7 +852,7 @@ public final class BroadcastQueue { // sent the broadcast. logBroadcastReceiverDiscardLocked(r); finishReceiverLocked(r, r.resultCode, r.resultData, - r.resultExtras, r.resultAbort, true); + r.resultExtras, r.resultAbort, false); scheduleBroadcastsLocked(); // We need to reset the state if we failed to start the receiver. r.state = BroadcastRecord.IDLE; @@ -850,7 +881,7 @@ public final class BroadcastQueue { + r.intent + ": process is bad"); logBroadcastReceiverDiscardLocked(r); finishReceiverLocked(r, r.resultCode, r.resultData, - r.resultExtras, r.resultAbort, true); + r.resultExtras, r.resultAbort, false); scheduleBroadcastsLocked(); r.state = BroadcastRecord.IDLE; return; @@ -917,7 +948,21 @@ public final class BroadcastQueue { } } - Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver + BroadcastRecord br = mOrderedBroadcasts.get(0); + if (br.state == BroadcastRecord.WAITING_SERVICES) { + // In this case the broadcast had already finished, but we had decided to wait + // for started services to finish as well before going on. So if we have actually + // waited long enough time timeout the broadcast, let's give up on the whole thing + // and just move on to the next. + Slog.i(ActivityManagerService.TAG, "Waited long enough for: " + (br.curComponent != null + ? br.curComponent.flattenToShortString() : "(null)")); + br.curComponent = null; + br.state = BroadcastRecord.IDLE; + processNextBroadcast(false); + return; + } + + Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r. receiver + ", started " + (now - r.receiverTime) + "ms ago"); r.receiverTime = now; r.anrCount++; @@ -957,7 +1002,7 @@ public final class BroadcastQueue { // Move on to the next receiver. finishReceiverLocked(r, r.resultCode, r.resultData, - r.resultExtras, r.resultAbort, true); + r.resultExtras, r.resultAbort, false); scheduleBroadcastsLocked(); if (anrMessage != null) { diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java index db61e88..b2cfd7a 100644 --- a/services/java/com/android/server/am/BroadcastRecord.java +++ b/services/java/com/android/server/am/BroadcastRecord.java @@ -70,6 +70,7 @@ final class BroadcastRecord extends Binder { static final int APP_RECEIVE = 1; static final int CALL_IN_RECEIVE = 2; static final int CALL_DONE_RECEIVE = 3; + static final int WAITING_SERVICES = 4; // The following are set when we are calling a receiver (one that // was found in our list of registered receivers). @@ -153,6 +154,7 @@ final class BroadcastRecord extends Binder { case APP_RECEIVE: stateStr=" (APP_RECEIVE)"; break; case CALL_IN_RECEIVE: stateStr=" (CALL_IN_RECEIVE)"; break; case CALL_DONE_RECEIVE: stateStr=" (CALL_DONE_RECEIVE)"; break; + case WAITING_SERVICES: stateStr=" (WAITING_SERVICES)"; break; } pw.print(prefix); pw.print("state="); pw.print(state); pw.println(stateStr); } |