Merge "Don't call ActivityManagerService on main thread" into qt-dev

This commit is contained in:
Alex Salo
2019-06-05 00:50:14 +00:00
committed by Android (Google) Code Review
2 changed files with 33 additions and 27 deletions

View File

@@ -190,9 +190,7 @@ public class AttentionManagerService extends SystemService {
final UserState userState = getOrCreateCurrentUserStateLocked(); final UserState userState = getOrCreateCurrentUserStateLocked();
// lazily start the service, which should be very lightweight to start // lazily start the service, which should be very lightweight to start
if (!userState.bindLocked()) { userState.bindLocked();
return false;
}
// throttle frequent requests // throttle frequent requests
final AttentionCheckCache cache = userState.mAttentionCheckCache; final AttentionCheckCache cache = userState.mAttentionCheckCache;
@@ -310,7 +308,7 @@ public class AttentionManagerService extends SystemService {
protected UserState getOrCreateUserStateLocked(int userId) { protected UserState getOrCreateUserStateLocked(int userId) {
UserState result = mUserStates.get(userId); UserState result = mUserStates.get(userId);
if (result == null) { if (result == null) {
result = new UserState(userId, mContext, mLock, mComponentName); result = new UserState(userId, mContext, mLock, mAttentionHandler, mComponentName);
mUserStates.put(userId, result); mUserStates.put(userId, result);
} }
return result; return result;
@@ -456,31 +454,33 @@ public class AttentionManagerService extends SystemService {
@VisibleForTesting @VisibleForTesting
protected static class UserState { protected static class UserState {
final ComponentName mComponentName; private final ComponentName mComponentName;
final AttentionServiceConnection mConnection = new AttentionServiceConnection(); private final AttentionServiceConnection mConnection = new AttentionServiceConnection();
@GuardedBy("mLock") @GuardedBy("mLock")
IAttentionService mService; IAttentionService mService;
@GuardedBy("mLock") @GuardedBy("mLock")
boolean mBinding;
@GuardedBy("mLock")
AttentionCheck mCurrentAttentionCheck; AttentionCheck mCurrentAttentionCheck;
@GuardedBy("mLock") @GuardedBy("mLock")
AttentionCheckCache mAttentionCheckCache; AttentionCheckCache mAttentionCheckCache;
@GuardedBy("mLock")
private boolean mBinding;
@UserIdInt @UserIdInt
final int mUserId; private final int mUserId;
final Context mContext; private final Context mContext;
final Object mLock; private final Object mLock;
private final Handler mAttentionHandler;
UserState(int userId, Context context, Object lock, ComponentName componentName) { UserState(int userId, Context context, Object lock, Handler handler,
ComponentName componentName) {
mUserId = userId; mUserId = userId;
mContext = Preconditions.checkNotNull(context); mContext = Preconditions.checkNotNull(context);
mLock = Preconditions.checkNotNull(lock); mLock = Preconditions.checkNotNull(lock);
mComponentName = Preconditions.checkNotNull(componentName); mComponentName = Preconditions.checkNotNull(componentName);
mAttentionHandler = handler;
} }
@GuardedBy("mLock") @GuardedBy("mLock")
private void handlePendingCallbackLocked() { private void handlePendingCallbackLocked() {
if (!mCurrentAttentionCheck.mIsDispatched) { if (!mCurrentAttentionCheck.mIsDispatched) {
@@ -499,26 +499,25 @@ public class AttentionManagerService extends SystemService {
/** Binds to the system's AttentionService which provides an actual implementation. */ /** Binds to the system's AttentionService which provides an actual implementation. */
@GuardedBy("mLock") @GuardedBy("mLock")
private boolean bindLocked() { private void bindLocked() {
// No need to bind if service is binding or has already been bound. // No need to bind if service is binding or has already been bound.
if (mBinding || mService != null) { if (mBinding || mService != null) {
return true; return;
} }
final boolean willBind; mBinding = true;
final long identity = Binder.clearCallingIdentity(); // mContext.bindServiceAsUser() calls into ActivityManagerService which it may already
// hold the lock and had called into PowerManagerService, which holds a lock.
try { // That would create a deadlock. To solve that, putting it on a handler.
final Intent mServiceIntent = new Intent( mAttentionHandler.post(() -> {
final Intent serviceIntent = new Intent(
AttentionService.SERVICE_INTERFACE).setComponent( AttentionService.SERVICE_INTERFACE).setComponent(
mComponentName); mComponentName);
willBind = mContext.bindServiceAsUser(mServiceIntent, mConnection, // Note: no reason to clear the calling identity, we won't have one in a handler.
mContext.bindServiceAsUser(serviceIntent, mConnection,
Context.BIND_AUTO_CREATE, UserHandle.CURRENT); Context.BIND_AUTO_CREATE, UserHandle.CURRENT);
mBinding = willBind;
} finally { });
Binder.restoreCallingIdentity(identity);
}
return willBind;
} }
private void dump(IndentingPrintWriter pw) { private void dump(IndentingPrintWriter pw) {
@@ -587,6 +586,7 @@ public class AttentionManagerService extends SystemService {
super(Looper.myLooper()); super(Looper.myLooper());
} }
@Override
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
switch (msg.what) { switch (msg.what) {
// Do not occupy resources when not in use - unbind proactively. // Do not occupy resources when not in use - unbind proactively.
@@ -651,7 +651,12 @@ public class AttentionManagerService extends SystemService {
return; return;
} }
mContext.unbindService(userState.mConnection); mAttentionHandler.post(() -> mContext.unbindService(userState.mConnection));
// Note: this will set mBinding to false even though it could still be trying to bind
// (i.e. the runnable was posted in bindLocked but then cancelAndUnbindLocked was
// called before it's run yet). This is a safe state at the moment,
// since it will eventually, but feels like a source for confusion down the road and
// may cause some expensive and unnecessary work to be done.
userState.mConnection.cleanupService(); userState.mConnection.cleanupService();
mUserStates.remove(userState.mUserId); mUserStates.remove(userState.mUserId);
} }

View File

@@ -86,6 +86,7 @@ public class AttentionManagerServiceTest {
UserState mUserState = new UserState(0, UserState mUserState = new UserState(0,
mContext, mContext,
mLock, mLock,
mMockHandler,
componentName); componentName);
mUserState.mService = new MockIAttentionService(); mUserState.mService = new MockIAttentionService();
mSpyUserState = spy(mUserState); mSpyUserState = spy(mUserState);