[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
|
// 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) {
|
boolean isPendingBroadcastProcessLocked(int pid) {
|
||||||
return mFgBroadcastQueue.isPendingBroadcastProcessLocked(pid)
|
return mFgBroadcastQueue.isPendingBroadcastProcessLocked(pid)
|
||||||
|| mBgBroadcastQueue.isPendingBroadcastProcessLocked(pid);
|
|| mBgBroadcastQueue.isPendingBroadcastProcessLocked(pid);
|
||||||
@ -15185,10 +15161,11 @@ public final class ActivityManagerService extends ActivityManagerNative
|
|||||||
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
|
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
|
||||||
IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
|
IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
|
||||||
enforceNotIsolatedCaller("registerReceiver");
|
enforceNotIsolatedCaller("registerReceiver");
|
||||||
|
ArrayList<Intent> stickyIntents = null;
|
||||||
|
ProcessRecord callerApp = null;
|
||||||
int callingUid;
|
int callingUid;
|
||||||
int callingPid;
|
int callingPid;
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
ProcessRecord callerApp = null;
|
|
||||||
if (caller != null) {
|
if (caller != null) {
|
||||||
callerApp = getRecordForAppLocked(caller);
|
callerApp = getRecordForAppLocked(caller);
|
||||||
if (callerApp == null) {
|
if (callerApp == null) {
|
||||||
@ -15211,39 +15188,66 @@ public final class ActivityManagerService extends ActivityManagerNative
|
|||||||
callingPid = Binder.getCallingPid();
|
callingPid = Binder.getCallingPid();
|
||||||
}
|
}
|
||||||
|
|
||||||
userId = this.handleIncomingUser(callingPid, callingUid, userId,
|
userId = handleIncomingUser(callingPid, callingUid, userId,
|
||||||
true, ALLOW_FULL_ONLY, "registerReceiver", callerPackage);
|
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...
|
// Collect stickies of users
|
||||||
Iterator actions = filter.actionsIterator();
|
int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
|
||||||
if (actions != null) {
|
while (actions.hasNext()) {
|
||||||
while (actions.hasNext()) {
|
String action = actions.next();
|
||||||
String action = (String)actions.next();
|
for (int id : userIds) {
|
||||||
allSticky = getStickiesLocked(action, filter, allSticky,
|
ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
|
||||||
UserHandle.USER_ALL);
|
if (stickies != null) {
|
||||||
allSticky = getStickiesLocked(action, filter, allSticky,
|
ArrayList<Intent> intents = stickies.get(action);
|
||||||
UserHandle.getUserId(callingUid));
|
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
|
ArrayList<Intent> allSticky = null;
|
||||||
// the client.
|
if (stickyIntents != null) {
|
||||||
Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
|
final ContentResolver resolver = mContext.getContentResolver();
|
||||||
|
// Look for any matching sticky broadcasts...
|
||||||
if (DEBUG_BROADCAST) Slog.v(TAG, "Register receiver " + filter
|
for (int i = 0, N = stickyIntents.size(); i < N; i++) {
|
||||||
+ ": " + sticky);
|
Intent intent = stickyIntents.get(i);
|
||||||
|
// If intent has scheme "content", it will need to acccess
|
||||||
if (receiver == null) {
|
// provider that needs to lock mProviderMap in ActivityThread
|
||||||
return sticky;
|
// 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 rl
|
||||||
= (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
|
= (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
|
||||||
if (rl == null) {
|
if (rl == null) {
|
||||||
|
Reference in New Issue
Block a user