summaryrefslogtreecommitdiffstats
path: root/services/java/com/android/server/am
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2013-09-18 20:34:11 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2013-09-18 20:34:11 +0000
commitb9466db4a56564101a26865962dda87aaeab56ff (patch)
tree7a36c64edcba8c55988f074f799826e4a497cef9 /services/java/com/android/server/am
parentbd49a1dadfbd7803642066a5bdc74305a1b2340b (diff)
parent6285a32f74890b761579b4f67afde1b08763fd0a (diff)
downloadframeworks_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')
-rw-r--r--services/java/com/android/server/am/ActiveServices.java15
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java29
-rw-r--r--services/java/com/android/server/am/BroadcastQueue.java107
-rw-r--r--services/java/com/android/server/am/BroadcastRecord.java2
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);
}