[ActivityManager] Prevent application holding AMS lock
Symptom: Watchdog timeout. Reproduce code: String action = "lets.deadlock"; Uri baseUri = Uri.parse("content://i.am.bad"); Uri uri = ContentUris.withAppendedId(baseUri, 1); Intent intent = new Intent(action, uri); sendStickyBroadcast(intent); IntentFilter filter = new IntentFilter(action); filter.addDataScheme(baseUri.getScheme()); filter.addDataAuthority(baseUri.getAuthority(), null); filter.addDataPath(uri.getPath(), 0); registerReceiver(null, filter); In target provider's getType: Invoke AMS function will result deadlock. Or sleep a long time will also trigger watchdog timeout. Root Cause: If broadcast is sticky with content scheme intent. Register receiver will trigger access provider when matching intent with IntentFilter, and it executes in ActivityManagerService's lock. Solution: Obtain necessary data to local to split lock block. Change-Id: I0fb94472cdc478997e40ba2a60a988c5f53badb2
This commit is contained in:
@ -15137,30 +15137,6 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
// BROADCASTS
|
||||
// =========================================================
|
||||
|
||||
private final List getStickiesLocked(String action, IntentFilter filter,
|
||||
List cur, int userId) {
|
||||
final ContentResolver resolver = mContext.getContentResolver();
|
||||
ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
|
||||
if (stickies == null) {
|
||||
return cur;
|
||||
}
|
||||
final ArrayList<Intent> list = stickies.get(action);
|
||||
if (list == null) {
|
||||
return cur;
|
||||
}
|
||||
int N = list.size();
|
||||
for (int i=0; i<N; i++) {
|
||||
Intent intent = list.get(i);
|
||||
if (filter.match(resolver, intent, true, TAG) >= 0) {
|
||||
if (cur == null) {
|
||||
cur = new ArrayList<Intent>();
|
||||
}
|
||||
cur.add(intent);
|
||||
}
|
||||
}
|
||||
return cur;
|
||||
}
|
||||
|
||||
boolean isPendingBroadcastProcessLocked(int pid) {
|
||||
return mFgBroadcastQueue.isPendingBroadcastProcessLocked(pid)
|
||||
|| mBgBroadcastQueue.isPendingBroadcastProcessLocked(pid);
|
||||
@ -15185,10 +15161,11 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
|
||||
IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
|
||||
enforceNotIsolatedCaller("registerReceiver");
|
||||
ArrayList<Intent> stickyIntents = null;
|
||||
ProcessRecord callerApp = null;
|
||||
int callingUid;
|
||||
int callingPid;
|
||||
synchronized(this) {
|
||||
ProcessRecord callerApp = null;
|
||||
if (caller != null) {
|
||||
callerApp = getRecordForAppLocked(caller);
|
||||
if (callerApp == null) {
|
||||
@ -15211,39 +15188,66 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
callingPid = Binder.getCallingPid();
|
||||
}
|
||||
|
||||
userId = this.handleIncomingUser(callingPid, callingUid, userId,
|
||||
userId = handleIncomingUser(callingPid, callingUid, userId,
|
||||
true, ALLOW_FULL_ONLY, "registerReceiver", callerPackage);
|
||||
|
||||
List allSticky = null;
|
||||
Iterator<String> actions = filter.actionsIterator();
|
||||
if (actions == null) {
|
||||
ArrayList<String> noAction = new ArrayList<String>(1);
|
||||
noAction.add(null);
|
||||
actions = noAction.iterator();
|
||||
}
|
||||
|
||||
// Look for any matching sticky broadcasts...
|
||||
Iterator actions = filter.actionsIterator();
|
||||
if (actions != null) {
|
||||
while (actions.hasNext()) {
|
||||
String action = (String)actions.next();
|
||||
allSticky = getStickiesLocked(action, filter, allSticky,
|
||||
UserHandle.USER_ALL);
|
||||
allSticky = getStickiesLocked(action, filter, allSticky,
|
||||
UserHandle.getUserId(callingUid));
|
||||
// Collect stickies of users
|
||||
int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
|
||||
while (actions.hasNext()) {
|
||||
String action = actions.next();
|
||||
for (int id : userIds) {
|
||||
ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
|
||||
if (stickies != null) {
|
||||
ArrayList<Intent> intents = stickies.get(action);
|
||||
if (intents != null) {
|
||||
if (stickyIntents == null) {
|
||||
stickyIntents = new ArrayList<Intent>();
|
||||
}
|
||||
stickyIntents.addAll(intents);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
allSticky = getStickiesLocked(null, filter, allSticky,
|
||||
UserHandle.USER_ALL);
|
||||
allSticky = getStickiesLocked(null, filter, allSticky,
|
||||
UserHandle.getUserId(callingUid));
|
||||
}
|
||||
}
|
||||
|
||||
// The first sticky in the list is returned directly back to
|
||||
// the client.
|
||||
Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
|
||||
|
||||
if (DEBUG_BROADCAST) Slog.v(TAG, "Register receiver " + filter
|
||||
+ ": " + sticky);
|
||||
|
||||
if (receiver == null) {
|
||||
return sticky;
|
||||
ArrayList<Intent> allSticky = null;
|
||||
if (stickyIntents != null) {
|
||||
final ContentResolver resolver = mContext.getContentResolver();
|
||||
// Look for any matching sticky broadcasts...
|
||||
for (int i = 0, N = stickyIntents.size(); i < N; i++) {
|
||||
Intent intent = stickyIntents.get(i);
|
||||
// If intent has scheme "content", it will need to acccess
|
||||
// provider that needs to lock mProviderMap in ActivityThread
|
||||
// and also it may need to wait application response, so we
|
||||
// cannot lock ActivityManagerService here.
|
||||
if (filter.match(resolver, intent, true, TAG) >= 0) {
|
||||
if (allSticky == null) {
|
||||
allSticky = new ArrayList<Intent>();
|
||||
}
|
||||
allSticky.add(intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The first sticky in the list is returned directly back to the client.
|
||||
Intent sticky = allSticky != null ? allSticky.get(0) : null;
|
||||
if (DEBUG_BROADCAST) Slog.v(TAG, "Register receiver " + filter + ": " + sticky);
|
||||
if (receiver == null) {
|
||||
return sticky;
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
if (callerApp != null && callerApp.pid == 0) {
|
||||
// Caller already died
|
||||
return null;
|
||||
}
|
||||
ReceiverList rl
|
||||
= (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
|
||||
if (rl == null) {
|
||||
|
Reference in New Issue
Block a user