Merge "Adds unit tests in attention manager service for two interfaces: -checkAttention() -cancelAttentionCheck()" into qt-dev

This commit is contained in:
Yi Jiang
2019-04-16 20:38:28 +00:00
committed by Android (Google) Code Review
2 changed files with 182 additions and 19 deletions

View File

@@ -58,6 +58,7 @@ import android.util.StatsLog;
import com.android.internal.R; import com.android.internal.R;
import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils; import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions; import com.android.internal.util.Preconditions;
@@ -100,16 +101,25 @@ public class AttentionManagerService extends SystemService {
private final Object mLock; private final Object mLock;
@GuardedBy("mLock") @GuardedBy("mLock")
private final SparseArray<UserState> mUserStates = new SparseArray<>(); private final SparseArray<UserState> mUserStates = new SparseArray<>();
private final AttentionHandler mAttentionHandler; private AttentionHandler mAttentionHandler;
private ComponentName mComponentName; @VisibleForTesting
ComponentName mComponentName;
public AttentionManagerService(Context context) { public AttentionManagerService(Context context) {
this(context, (PowerManager) context.getSystemService(Context.POWER_SERVICE),
new Object(), null);
mAttentionHandler = new AttentionHandler();
}
@VisibleForTesting
AttentionManagerService(Context context, PowerManager powerManager, Object lock,
AttentionHandler handler) {
super(context); super(context);
mContext = Preconditions.checkNotNull(context); mContext = Preconditions.checkNotNull(context);
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mPowerManager = powerManager;
mLock = new Object(); mLock = lock;
mAttentionHandler = new AttentionHandler(); mAttentionHandler = handler;
} }
@Override @Override
@@ -147,7 +157,8 @@ public class AttentionManagerService extends SystemService {
return isServiceEnabled() && isServiceAvailable(); return isServiceEnabled() && isServiceAvailable();
} }
private boolean isServiceEnabled() { @VisibleForTesting
protected boolean isServiceEnabled() {
return DeviceConfig.getBoolean(NAMESPACE_ATTENTION_MANAGER_SERVICE, SERVICE_ENABLED, return DeviceConfig.getBoolean(NAMESPACE_ATTENTION_MANAGER_SERVICE, SERVICE_ENABLED,
DEFAULT_SERVICE_ENABLED); DEFAULT_SERVICE_ENABLED);
} }
@@ -161,7 +172,8 @@ public class AttentionManagerService extends SystemService {
* *
* @return {@code true} if the framework was able to dispatch the request * @return {@code true} if the framework was able to dispatch the request
*/ */
private boolean checkAttention(long timeout, AttentionCallbackInternal callbackInternal) { @VisibleForTesting
boolean checkAttention(long timeout, AttentionCallbackInternal callbackInternal) {
Preconditions.checkNotNull(callbackInternal); Preconditions.checkNotNull(callbackInternal);
if (!isAttentionServiceSupported()) { if (!isAttentionServiceSupported()) {
@@ -257,24 +269,24 @@ public class AttentionManagerService extends SystemService {
} }
/** Cancels the specified attention check. */ /** Cancels the specified attention check. */
private void cancelAttentionCheck(AttentionCallbackInternal callbackInternal) { @VisibleForTesting
void cancelAttentionCheck(AttentionCallbackInternal callbackInternal) {
synchronized (mLock) { synchronized (mLock) {
final UserState userState = peekCurrentUserStateLocked(); final UserState userState = peekCurrentUserStateLocked();
if (userState == null) { if (userState == null) {
return; return;
} }
if (!userState.mCurrentAttentionCheck.mCallbackInternal.equals(callbackInternal)) { if (!userState.mCurrentAttentionCheck.mCallbackInternal.equals(callbackInternal)) {
Slog.e(LOG_TAG, "Cannot cancel a non-current request"); Slog.e(LOG_TAG, "Cannot cancel a non-current request");
return; return;
} }
cancel(userState); cancel(userState);
} }
} }
@GuardedBy("mLock") @GuardedBy("mLock")
private void freeIfInactiveLocked() { @VisibleForTesting
protected void freeIfInactiveLocked() {
// If we are called here, it means someone used the API again - reset the timer then. // If we are called here, it means someone used the API again - reset the timer then.
mAttentionHandler.removeMessages(AttentionHandler.CHECK_CONNECTION_EXPIRATION); mAttentionHandler.removeMessages(AttentionHandler.CHECK_CONNECTION_EXPIRATION);
@@ -291,7 +303,8 @@ public class AttentionManagerService extends SystemService {
@GuardedBy("mLock") @GuardedBy("mLock")
private UserState getOrCreateCurrentUserStateLocked() { @VisibleForTesting
protected UserState getOrCreateCurrentUserStateLocked() {
return getOrCreateUserStateLocked(ActivityManager.getCurrentUser()); return getOrCreateUserStateLocked(ActivityManager.getCurrentUser());
} }
@@ -307,7 +320,8 @@ public class AttentionManagerService extends SystemService {
@GuardedBy("mLock") @GuardedBy("mLock")
@Nullable @Nullable
private UserState peekCurrentUserStateLocked() { @VisibleForTesting
protected UserState peekCurrentUserStateLocked() {
return peekUserStateLocked(ActivityManager.getCurrentUser()); return peekUserStateLocked(ActivityManager.getCurrentUser());
} }
@@ -418,7 +432,8 @@ public class AttentionManagerService extends SystemService {
} }
} }
private static final class AttentionCheck { @VisibleForTesting
static final class AttentionCheck {
private final AttentionCallbackInternal mCallbackInternal; private final AttentionCallbackInternal mCallbackInternal;
private final IAttentionCallback mIAttentionCallback; private final IAttentionCallback mIAttentionCallback;
private boolean mIsDispatched; private boolean mIsDispatched;
@@ -435,7 +450,8 @@ public class AttentionManagerService extends SystemService {
} }
} }
private static final class UserState { @VisibleForTesting
protected static class UserState {
final ComponentName mComponentName; final ComponentName mComponentName;
final AttentionServiceConnection mConnection = new AttentionServiceConnection(); final AttentionServiceConnection mConnection = new AttentionServiceConnection();
@@ -453,7 +469,7 @@ public class AttentionManagerService extends SystemService {
final Context mContext; final Context mContext;
final Object mLock; final Object mLock;
private UserState(int userId, Context context, Object lock, ComponentName componentName) { UserState(int userId, Context context, Object lock, ComponentName componentName) {
mUserId = userId; mUserId = userId;
mContext = Preconditions.checkNotNull(context); mContext = Preconditions.checkNotNull(context);
mLock = Preconditions.checkNotNull(lock); mLock = Preconditions.checkNotNull(lock);
@@ -509,7 +525,7 @@ public class AttentionManagerService extends SystemService {
} }
} }
private final class AttentionServiceConnection implements ServiceConnection { private class AttentionServiceConnection implements ServiceConnection {
@Override @Override
public void onServiceConnected(ComponentName name, IBinder service) { public void onServiceConnected(ComponentName name, IBinder service) {
init(IAttentionService.Stub.asInterface(service)); init(IAttentionService.Stub.asInterface(service));
@@ -544,7 +560,8 @@ public class AttentionManagerService extends SystemService {
} }
} }
private class AttentionHandler extends Handler { @VisibleForTesting
protected class AttentionHandler extends Handler {
private static final int CHECK_CONNECTION_EXPIRATION = 1; private static final int CHECK_CONNECTION_EXPIRATION = 1;
private static final int ATTENTION_CHECK_TIMEOUT = 2; private static final int ATTENTION_CHECK_TIMEOUT = 2;
@@ -576,7 +593,8 @@ public class AttentionManagerService extends SystemService {
} }
} }
private void cancel(UserState userState) { @VisibleForTesting
void cancel(UserState userState) {
if (userState == null || userState.mCurrentAttentionCheck == null) { if (userState == null || userState.mCurrentAttentionCheck == null) {
return; return;
} }

View File

@@ -0,0 +1,145 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.attention;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.attention.AttentionManagerInternal.AttentionCallbackInternal;
import android.content.ComponentName;
import android.content.Context;
import android.os.IBinder;
import android.os.IPowerManager;
import android.os.PowerManager;
import android.os.RemoteException;
import android.service.attention.IAttentionCallback;
import android.service.attention.IAttentionService;
import androidx.test.filters.SmallTest;
import com.android.server.attention.AttentionManagerService.AttentionCheck;
import com.android.server.attention.AttentionManagerService.AttentionHandler;
import com.android.server.attention.AttentionManagerService.UserState;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
/**
* Tests for {@link com.android.server.attention.AttentionManagerService}
*/
@SmallTest
public class AttentionManagerServiceTest {
private AttentionManagerService mSpyAttentionManager;
private UserState mSpyUserState;
private final int mTimeout = 1000;
@Mock private AttentionCallbackInternal mMockAttentionCallbackInternal;
@Mock private AttentionHandler mMockHandler;
@Mock private IAttentionCallback mMockIAttentionCallback;
@Mock private IPowerManager mMockIPowerManager;
@Mock Context mContext;
@Before
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
// setup context mock
doReturn(true).when(mContext).bindServiceAsUser(any(), any(), anyInt(), any());
// setup power manager mock
PowerManager mPowerManager;
doReturn(true).when(mMockIPowerManager).isInteractive();
mPowerManager = new PowerManager(mContext, mMockIPowerManager, null);
Object mLock = new Object();
// setup a spy on attention manager
AttentionManagerService mAttentionManager = new AttentionManagerService(
mContext,
mPowerManager,
mLock,
mMockHandler);
mSpyAttentionManager = Mockito.spy(mAttentionManager);
// setup a spy on user state
ComponentName componentName = new ComponentName("a", "b");
mSpyAttentionManager.mComponentName = componentName;
UserState mUserState = new UserState(0,
mContext,
mLock,
componentName);
mUserState.mService = new MockIAttentionService();
mSpyUserState = spy(mUserState);
}
@Test
public void testCancelAttentionCheck_noCrashWhenNoUserStateLocked() {
mSpyAttentionManager.cancelAttentionCheck(null);
}
@Test
public void testCancelAttentionCheck_noCrashWhenCallbackMismatched() {
mSpyUserState.mCurrentAttentionCheck =
new AttentionCheck(mMockAttentionCallbackInternal, mMockIAttentionCallback);
doReturn(mSpyUserState).when(mSpyAttentionManager).peekCurrentUserStateLocked();
mSpyAttentionManager.cancelAttentionCheck(null);
}
@Test
public void testCancelAttentionCheck_cancelCallbackWhenMatched() {
mSpyUserState.mCurrentAttentionCheck =
new AttentionCheck(mMockAttentionCallbackInternal, mMockIAttentionCallback);
doReturn(mSpyUserState).when(mSpyAttentionManager).peekCurrentUserStateLocked();
mSpyAttentionManager.cancelAttentionCheck(mMockAttentionCallbackInternal);
verify(mSpyAttentionManager).cancel(any());
}
@Test
public void testCheckAttention_returnFalseWhenPowerManagerNotInteract() throws RemoteException {
doReturn(false).when(mMockIPowerManager).isInteractive();
AttentionCallbackInternal callback = Mockito.mock(AttentionCallbackInternal.class);
assertThat(mSpyAttentionManager.checkAttention(mTimeout, callback)).isFalse();
}
@Test
public void testCheckAttention_callOnSuccess() throws RemoteException {
doReturn(true).when(mSpyAttentionManager).isServiceEnabled();
doReturn(true).when(mMockIPowerManager).isInteractive();
doReturn(mSpyUserState).when(mSpyAttentionManager).getOrCreateCurrentUserStateLocked();
doNothing().when(mSpyAttentionManager).freeIfInactiveLocked();
AttentionCallbackInternal callback = Mockito.mock(AttentionCallbackInternal.class);
mSpyAttentionManager.checkAttention(mTimeout, callback);
verify(callback).onSuccess(anyInt(), anyLong());
}
private class MockIAttentionService implements IAttentionService {
public void checkAttention(IAttentionCallback callback) throws RemoteException {
callback.onSuccess(0, 0);
}
public void cancelAttentionCheck(IAttentionCallback callback) {
}
public IBinder asBinder() {
return null;
}
}
}