blob: f49e5eb4d7c2bd2315a244759939799c0c89cc9e [file] [log] [blame]
/*
* Copyright 2016, 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.managedprovisioning.finalization;
import static android.app.admin.DeviceAdminReceiver.ACTION_PROFILE_PROVISIONING_COMPLETE;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISIONING_SUCCESSFUL;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE;
import static android.app.admin.DevicePolicyManager.PROVISIONING_MODE_MANAGED_PROFILE;
import static com.android.managedprovisioning.TestUtils.createTestAdminExtras;
import static com.android.managedprovisioning.finalization.SendDpcBroadcastService.EXTRA_PROVISIONING_PARAMS;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import android.accounts.Account;
import android.app.Activity;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.PersistableBundle;
import android.os.UserHandle;
import android.os.UserManager;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.managedprovisioning.TestUtils;
import com.android.managedprovisioning.analytics.DeferredMetricsReader;
import com.android.managedprovisioning.common.NotificationHelper;
import com.android.managedprovisioning.common.SettingsFacade;
import com.android.managedprovisioning.common.Utils;
import com.android.managedprovisioning.model.ProvisioningParams;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static com.google.common.truth.Truth.assertThat;
/**
* Unit tests for {@link FinalizationPostSuwControllerLogic}.
*/
public class FinalizationPostSuwControllerTest extends AndroidTestCase {
private static final UserHandle MANAGED_PROFILE_USER_HANDLE = UserHandle.of(123);
private static final String TEST_MDM_PACKAGE_NAME = "mdm.package.name";
private static final String TEST_MDM_ADMIN_RECEIVER = TEST_MDM_PACKAGE_NAME + ".AdminReceiver";
private static final ComponentName TEST_MDM_ADMIN = new ComponentName(TEST_MDM_PACKAGE_NAME,
TEST_MDM_ADMIN_RECEIVER);
private static final PersistableBundle TEST_MDM_EXTRA_BUNDLE = createTestAdminExtras();
private static final Account TEST_ACCOUNT = new Account("test@account.com", "account.type");
@Mock private Activity mActivity;
@Mock private Utils mUtils;
@Mock private SettingsFacade mSettingsFacade;
@Mock private UserProvisioningStateHelper mHelper;
@Mock private NotificationHelper mNotificationHelper;
@Mock private DeferredMetricsReader mDeferredMetricsReader;
private PreFinalizationController mPreFinalizationController;
private FinalizationController mFinalizationController;
@Override
public void setUp() throws Exception {
// this is necessary for mockito to work
System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString());
MockitoAnnotations.initMocks(this);
when(mUtils.canResolveIntentAsUser(any(Context.class), any(Intent.class), anyInt()))
.thenReturn(true);
when(mActivity.getFilesDir()).thenReturn(getContext().getFilesDir());
final ProvisioningParamsUtils provisioningParamsUtils = new ProvisioningParamsUtils();
mPreFinalizationController = new PreFinalizationController(
mActivity, mUtils, mSettingsFacade, mHelper,
provisioningParamsUtils, new SendDpcBroadcastServiceUtils());
mFinalizationController = new FinalizationController(
mActivity,
new FinalizationPostSuwControllerLogic(
mActivity, mUtils, new SendDpcBroadcastServiceUtils()),
mUtils, mSettingsFacade, mHelper, mNotificationHelper, mDeferredMetricsReader,
provisioningParamsUtils);
}
@Override
public void tearDown() throws Exception {
mFinalizationController.clearParamsFile();
}
@SmallTest
public void testInitiallyDone_alreadyCalled() {
// GIVEN that deviceManagementEstablished has already been called
when(mHelper.isStateUnmanagedOrFinalized()).thenReturn(false);
final ProvisioningParams params = createProvisioningParams(
ACTION_PROVISION_MANAGED_PROFILE, false);
// WHEN calling deviceManagementEstablished
mPreFinalizationController.deviceManagementEstablished(params);
// THEN nothing should happen
verify(mHelper, never()).markUserProvisioningStateInitiallyDone(params);
verify(mHelper, never()).markUserProvisioningStateFinalized(params);
verifyZeroInteractions(mDeferredMetricsReader);
}
@SmallTest
public void testFinalized_alreadyCalled() {
// GIVEN that deviceManagementEstablished has already been called
when(mHelper.isStateUnmanagedOrFinalized()).thenReturn(true);
final ProvisioningParams params = createProvisioningParams(
ACTION_PROVISION_MANAGED_PROFILE, false);
// WHEN calling provisioningFinalized and commitFinalizedState
mFinalizationController.provisioningFinalized();
mFinalizationController.commitFinalizedState();
// THEN nothing should happen
verify(mHelper, never()).markUserProvisioningStateInitiallyDone(params);
verify(mHelper, never()).markUserProvisioningStateFinalized(params);
verifyZeroInteractions(mDeferredMetricsReader);
}
@SmallTest
public void testFinalized_noParamsStored() {
// GIVEN that the user provisioning state is correct
when(mHelper.isStateUnmanagedOrFinalized()).thenReturn(false);
// WHEN calling provisioningFinalized and commitFinalizedState
mFinalizationController.provisioningFinalized();
mFinalizationController.commitFinalizedState();
// THEN nothing should happen
verify(mHelper, never())
.markUserProvisioningStateInitiallyDone(any(ProvisioningParams.class));
verify(mHelper, never()).markUserProvisioningStateFinalized(any(ProvisioningParams.class));
verifyZeroInteractions(mDeferredMetricsReader);
}
@SmallTest
public void testManagedProfileAfterSuw() {
// GIVEN that deviceManagementEstablished has never been called
when(mHelper.isStateUnmanagedOrFinalized()).thenReturn(true);
// GIVEN that we've provisioned a managed profile after SUW
final ProvisioningParams params = createProvisioningParams(
ACTION_PROVISION_MANAGED_PROFILE, true);
when(mSettingsFacade.isUserSetupCompleted(mActivity)).thenReturn(true);
when(mSettingsFacade.isDuringSetupWizard(mActivity)).thenReturn(false);
when(mUtils.getManagedProfile(mActivity))
.thenReturn(MANAGED_PROFILE_USER_HANDLE);
// WHEN calling deviceManagementEstablished
mPreFinalizationController.deviceManagementEstablished(params);
// THEN the user provisioning state should be marked as initially done
verify(mHelper).markUserProvisioningStateInitiallyDone(params);
// THEN the service which starts the DPC is started.
verifySendDpcServiceStarted(true);
// THEN deferred metrics are not written
verifyZeroInteractions(mDeferredMetricsReader);
}
@SmallTest
public void testManagedProfileDuringSuw() {
// GIVEN that deviceManagementEstablished has never been called
when(mHelper.isStateUnmanagedOrFinalized()).thenReturn(true);
// GIVEN that we've provisioned a managed profile after SUW
final ProvisioningParams params = createProvisioningParams(
ACTION_PROVISION_MANAGED_PROFILE, true);
when(mSettingsFacade.isUserSetupCompleted(mActivity)).thenReturn(false);
when(mSettingsFacade.isDuringSetupWizard(mActivity)).thenReturn(true);
when(mUtils.getManagedProfile(mActivity))
.thenReturn(MANAGED_PROFILE_USER_HANDLE);
// WHEN calling deviceManagementEstablished
mPreFinalizationController.deviceManagementEstablished(params);
// THEN the user provisioning state should be marked as initially done
verify(mHelper).markUserProvisioningStateInitiallyDone(params);
// THEN the provisioning params have been stored and will be read in provisioningFinalized
// GIVEN that SUW is now complete
when(mSettingsFacade.isUserSetupCompleted(mActivity)).thenReturn(true);
when(mSettingsFacade.isDuringSetupWizard(mActivity)).thenReturn(false);
// GIVEN that the provisioning state is now incomplete
when(mHelper.isStateUnmanagedOrFinalized()).thenReturn(false);
// WHEN calling provisioningFinalized
mFinalizationController.provisioningFinalized();
// THEN the user provisioning state is not yet finalized
verify(mHelper, never()).markUserProvisioningStateFinalized(params);
// THEN the service which starts the DPC, is started.
verifySendDpcServiceStarted(true);
// WHEN the provisioning state changes are now committed
mFinalizationController.commitFinalizedState();
// THEN deferred metrics are written
verify(mDeferredMetricsReader).scheduleDumpMetrics(any(Context.class));
verifyNoMoreInteractions(mDeferredMetricsReader);
// THEN the user provisioning state is finalized
verify(mHelper).markUserProvisioningStateFinalized(params);
}
@SmallTest
public void testCorpOwnedManagedProfileDuringSuw() throws PackageManager.NameNotFoundException {
// GIVEN that deviceManagementEstablished has never been called
when(mHelper.isStateUnmanagedOrFinalized()).thenReturn(true);
// GIVEN that we're provisioning a corp-owned managed profile DURING SUW
final ProvisioningParams params =
createProvisioningParamsBuilder(ACTION_PROVISION_MANAGED_PROFILE, true)
.setIsOrganizationOwnedProvisioning(true)
.setProvisioningMode(PROVISIONING_MODE_MANAGED_PROFILE)
.build();
when(mSettingsFacade.isUserSetupCompleted(mActivity)).thenReturn(false);
when(mSettingsFacade.isDuringSetupWizard(mActivity)).thenReturn(true);
when(mUtils.getManagedProfile(mActivity))
.thenReturn(MANAGED_PROFILE_USER_HANDLE);
when(mUtils.isAdminIntegratedFlow(params)).thenCallRealMethod();
// Mock DPM for testing access to device IDs is granted.
final DevicePolicyManager mockDpm = mock(DevicePolicyManager.class);
when(mActivity.getSystemServiceName(DevicePolicyManager.class))
.thenReturn(Context.DEVICE_POLICY_SERVICE);
when(mActivity.getSystemService(DevicePolicyManager.class)).thenReturn(mockDpm);
final int managedProfileUserId = MANAGED_PROFILE_USER_HANDLE.getIdentifier();
when(mockDpm.getProfileOwnerAsUser(managedProfileUserId)).thenReturn(TEST_MDM_ADMIN);
// Actual Device IDs access is granted to the DPM of the managed profile, in the context
// of the managed profile.
final Context profileContext = mock(Context.class);
when(mActivity.createPackageContextAsUser(mActivity.getPackageName(), /*flags=*/ 0,
MANAGED_PROFILE_USER_HANDLE)).thenReturn(profileContext);
when(profileContext.getSystemServiceName(DevicePolicyManager.class))
.thenReturn(Context.DEVICE_POLICY_SERVICE);
final DevicePolicyManager mockProfileDpm = mock(DevicePolicyManager.class);
when(profileContext.getSystemService(DevicePolicyManager.class)).thenReturn(mockProfileDpm);
// Mock UserManager for testing user restriction.
final UserManager mockUserManager = mock(UserManager.class);
when(mActivity.getSystemServiceName(UserManager.class))
.thenReturn(Context.USER_SERVICE);
when(mActivity.getSystemService(Context.USER_SERVICE)).thenReturn(mockUserManager);
// WHEN calling deviceManagementEstablished
mPreFinalizationController.deviceManagementEstablished(params);
// THEN the user provisioning state should be marked as initially done
verify(mHelper).markUserProvisioningStateInitiallyDone(params);
// THEN the managed profile DPC has been granted access to device IDs.
verify(mockProfileDpm).markProfileOwnerOnOrganizationOwnedDevice(TEST_MDM_ADMIN);
// THEN the user restriction for removing a managed profile has been applied.
verify(mockUserManager).setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
true);
// GIVEN that SUW is now complete
when(mSettingsFacade.isUserSetupCompleted(mActivity)).thenReturn(true);
when(mSettingsFacade.isDuringSetupWizard(mActivity)).thenReturn(false);
// GIVEN that the provisioning state is now incomplete
when(mHelper.isStateUnmanagedOrFinalized()).thenReturn(false);
// WHEN calling provisioningFinalized
mFinalizationController.provisioningFinalized();
// THEN the user provisioning state is not yet finalized
verify(mHelper, never()).markUserProvisioningStateFinalized(params);
// WHEN the provisioning state changes are now committed
mFinalizationController.commitFinalizedState();
// THEN deferred metrics are written
verify(mDeferredMetricsReader).scheduleDumpMetrics(any(Context.class));
verifyNoMoreInteractions(mDeferredMetricsReader);
// THEN the user provisioning state is finalized
verify(mHelper).markUserProvisioningStateFinalized(params);
// THEN account migration is triggered
verify(mUtils).removeAccountAsync(eq(mActivity), eq(TEST_ACCOUNT), any());
}
@SmallTest
public void testDeviceOwner() {
// GIVEN that deviceManagementEstablished has never been called
when(mHelper.isStateUnmanagedOrFinalized()).thenReturn(true);
// GIVEN that we've provisioned a device owner during SUW
final ProvisioningParams params = createProvisioningParams(
ACTION_PROVISION_MANAGED_DEVICE, false);
when(mSettingsFacade.isUserSetupCompleted(mActivity)).thenReturn(false);
when(mSettingsFacade.isDuringSetupWizard(mActivity)).thenReturn(true);
// WHEN calling deviceManagementEstablished
mPreFinalizationController.deviceManagementEstablished(params);
// THEN the user provisioning state should be marked as initially done
verify(mHelper).markUserProvisioningStateInitiallyDone(params);
// THEN the provisioning params have been stored and will be read in provisioningFinalized
// GIVEN that SUW is now complete
when(mSettingsFacade.isUserSetupCompleted(mActivity)).thenReturn(true);
when(mSettingsFacade.isDuringSetupWizard(mActivity)).thenReturn(false);
// GIVEN that the provisioning state is now incomplete
when(mHelper.isStateUnmanagedOrFinalized()).thenReturn(false);
// WHEN calling provisioningFinalized
mFinalizationController.provisioningFinalized();
// THEN provisioning successful intent should be sent to the dpc.
verifyDpcLaunchedForUser(UserHandle.of(UserHandle.myUserId()));
// WHEN the provisioning state changes are now committed
mFinalizationController.commitFinalizedState();
// THEN deferred metrics are written
verify(mDeferredMetricsReader).scheduleDumpMetrics(any(Context.class));
verifyNoMoreInteractions(mDeferredMetricsReader);
// THEN the user provisioning state is finalized
verify(mHelper).markUserProvisioningStateFinalized(params);
// THEN a broadcast was sent to the primary user
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mActivity).sendBroadcast(intentCaptor.capture());
verify(mNotificationHelper).showPrivacyReminderNotification(eq(mActivity), anyInt());
// THEN the intent should be ACTION_PROFILE_PROVISIONING_COMPLETE
assertEquals(ACTION_PROFILE_PROVISIONING_COMPLETE, intentCaptor.getValue().getAction());
// THEN the intent should be sent to the admin receiver
assertEquals(TEST_MDM_ADMIN, intentCaptor.getValue().getComponent());
// THEN the admin extras bundle should contain mdm extras
assertExtras(intentCaptor.getValue());
}
private void verifyDpcLaunchedForUser(UserHandle userHandle) {
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mActivity).startActivityAsUser(intentCaptor.capture(), eq(userHandle));
// THEN the intent should be ACTION_PROVISIONING_SUCCESSFUL
assertEquals(ACTION_PROVISIONING_SUCCESSFUL, intentCaptor.getValue().getAction());
// THEN the intent should only be sent to the dpc
assertEquals(TEST_MDM_PACKAGE_NAME, intentCaptor.getValue().getPackage());
// THEN the admin extras bundle should contain mdm extras
assertExtras(intentCaptor.getValue());
}
private void verifySendDpcServiceStarted(boolean migrateAccount) {
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mActivity).startService(intentCaptor.capture());
// THEN the intent should launch the SendDpcBroadcastService
assertEquals(SendDpcBroadcastService.class.getName(),
intentCaptor.getValue().getComponent().getClassName());
// THEN the service extras should contain mdm extras
assertSendDpcBroadcastServiceParams(intentCaptor.getValue(), migrateAccount);
}
private void assertExtras(Intent intent) {
assertTrue(TestUtils.bundleEquals(TEST_MDM_EXTRA_BUNDLE,
(PersistableBundle) intent.getExtra(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE)));
}
private void assertSendDpcBroadcastServiceParams(Intent intent, boolean migrateAccount) {
final ProvisioningParams expectedParams =
createProvisioningParams(ACTION_PROVISION_MANAGED_PROFILE, migrateAccount);
final ProvisioningParams actualParams =
intent.getParcelableExtra(EXTRA_PROVISIONING_PARAMS);
assertThat(actualParams).isEqualTo(expectedParams);
}
private ProvisioningParams createProvisioningParams(String action, boolean migrateAccount) {
return createProvisioningParamsBuilder(action, migrateAccount).build();
}
private ProvisioningParams.Builder createProvisioningParamsBuilder(String action,
boolean migrateAccount) {
ProvisioningParams.Builder builder = new ProvisioningParams.Builder()
.setDeviceAdminComponentName(TEST_MDM_ADMIN)
.setProvisioningAction(action)
.setAdminExtrasBundle(TEST_MDM_EXTRA_BUNDLE);
if (migrateAccount) {
builder.setAccountToMigrate(TEST_ACCOUNT);
builder.setKeepAccountMigrated(false);
}
return builder;
}
}