blob: 8a8462d7f92fb9ed6da64bb8e08310e2292433ab [file] [log] [blame]
/*
* Copyright (C) 2020 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 android.suspendapps.cts;
import static android.content.Intent.EXTRA_PACKAGE_NAME;
import static android.os.UserManager.DISALLOW_APPS_CONTROL;
import static android.os.UserManager.DISALLOW_UNINSTALL_APPS;
import static android.suspendapps.cts.Constants.ALL_TEST_PACKAGES;
import static android.suspendapps.cts.Constants.DEVICE_ADMIN_COMPONENT;
import static android.suspendapps.cts.Constants.TEST_APP_PACKAGE_NAME;
import static android.suspendapps.cts.Constants.TEST_PACKAGE_ARRAY;
import static android.suspendapps.cts.SuspendTestUtils.addAndAssertProfileOwner;
import static android.suspendapps.cts.SuspendTestUtils.createSingleKeyBundle;
import static android.suspendapps.cts.SuspendTestUtils.removeDeviceAdmin;
import static android.suspendapps.cts.SuspendTestUtils.requestDpmAction;
import static com.android.suspendapps.testdeviceadmin.TestCommsReceiver.ACTION_ADD_USER_RESTRICTION;
import static com.android.suspendapps.testdeviceadmin.TestCommsReceiver.ACTION_BLOCK_UNINSTALL;
import static com.android.suspendapps.testdeviceadmin.TestCommsReceiver.ACTION_SUSPEND;
import static com.android.suspendapps.testdeviceadmin.TestCommsReceiver.ACTION_UNBLOCK_UNINSTALL;
import static com.android.suspendapps.testdeviceadmin.TestCommsReceiver.ACTION_UNSUSPEND;
import static com.android.suspendapps.testdeviceadmin.TestCommsReceiver.EXTRA_USER_RESTRICTION;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
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.Bundle;
import android.os.Handler;
import android.os.Looper;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
import androidx.test.filters.RequiresDevice;
import androidx.test.runner.AndroidJUnit4;
import com.android.compatibility.common.util.FeatureUtil;
import libcore.util.EmptyArray;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@LargeTest
@RequiresDevice
public class DualSuspendTests {
private Context mContext;
private Handler mReceiverHandler;
private TestAppInterface mTestAppInterface;
@Before
public void setUp() {
mContext = InstrumentationRegistry.getTargetContext();
mReceiverHandler = new Handler(Looper.getMainLooper());
assumeTrue("Skipping test that requires device admin",
FeatureUtil.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN));
addAndAssertProfileOwner();
}
private boolean setSuspendViaDpm(boolean suspend) throws Exception {
return requestDpmAction(suspend ? ACTION_SUSPEND : ACTION_UNSUSPEND,
createSingleKeyBundle(Intent.EXTRA_PACKAGE_NAME, TEST_APP_PACKAGE_NAME),
mReceiverHandler);
}
@Test
public void testMyPackageSuspended() throws Exception {
mTestAppInterface = new TestAppInterface(mContext);
mTestAppInterface.startListeningForBroadcast(Intent.ACTION_MY_PACKAGE_SUSPENDED);
SuspendTestUtils.suspend(null, null, null);
assertNotNull(Intent.ACTION_MY_PACKAGE_SUSPENDED + " not reported",
mTestAppInterface.awaitBroadcast());
mTestAppInterface.startListeningForBroadcast(Intent.ACTION_MY_PACKAGE_SUSPENDED);
assertTrue("Suspend via dpm failed", setSuspendViaDpm(true));
assertNotNull(Intent.ACTION_MY_PACKAGE_SUSPENDED + " not reported",
mTestAppInterface.awaitBroadcast());
}
@Test
public void testMyPackageUnsuspended() throws Exception {
mTestAppInterface = new TestAppInterface(mContext);
SuspendTestUtils.suspend(null, null, null);
assertTrue("Suspend via dpm failed", setSuspendViaDpm(true));
mTestAppInterface.startListeningForBroadcast(Intent.ACTION_MY_PACKAGE_UNSUSPENDED);
SuspendTestUtils.unsuspendAll();
final Intent unexpectedIntent = mTestAppInterface.awaitBroadcast(5_000);
assertNull(unexpectedIntent + " reported after just one unsuspend", unexpectedIntent);
assertTrue("Unsuspend via dpm failed", setSuspendViaDpm(false));
assertNotNull(Intent.ACTION_MY_PACKAGE_UNSUSPENDED + " not reported after both unsuspends",
mTestAppInterface.awaitBroadcast());
}
@Test
public void testIsPackageSuspended() throws Exception {
final PackageManager pm = mContext.getPackageManager();
assertFalse(pm.isPackageSuspended(TEST_APP_PACKAGE_NAME));
SuspendTestUtils.suspend(null, null, null);
assertTrue("Suspend via dpm failed", setSuspendViaDpm(true));
assertTrue("Package should be suspended by both",
pm.isPackageSuspended(TEST_APP_PACKAGE_NAME));
SuspendTestUtils.unsuspendAll();
assertTrue("Package should be suspended by dpm",
pm.isPackageSuspended(TEST_APP_PACKAGE_NAME));
SuspendTestUtils.suspend(null, null, null);
assertTrue("Unsuspend via dpm failed", setSuspendViaDpm(false));
assertTrue("Package should be suspended by shell",
pm.isPackageSuspended(TEST_APP_PACKAGE_NAME));
SuspendTestUtils.unsuspendAll();
assertFalse("Package should be suspended by neither",
pm.isPackageSuspended(TEST_APP_PACKAGE_NAME));
}
private void assertDpmCanSuspendUnderUserRestriction(String userRestriction) throws Exception {
mTestAppInterface = new TestAppInterface(mContext);
final Bundle extra = createSingleKeyBundle(EXTRA_USER_RESTRICTION, userRestriction);
assertTrue("Request to add restriction" + userRestriction + " failed",
requestDpmAction(ACTION_ADD_USER_RESTRICTION, extra, mReceiverHandler));
assertTrue("Request to suspend via dpm failed", setSuspendViaDpm(true));
assertTrue("Test app not suspended", mTestAppInterface.isTestAppSuspended());
}
@Test
public void testDpmCanSuspendUnderDisallowAppsControl() throws Exception {
assertDpmCanSuspendUnderUserRestriction(DISALLOW_APPS_CONTROL);
}
@Test
public void testDpmCanSuspendUnderDisallowUninstallApps() throws Exception {
assertDpmCanSuspendUnderUserRestriction(DISALLOW_UNINSTALL_APPS);
}
@Test
public void testUnsuspendedOnUninstallBlocked() throws Exception {
mTestAppInterface = new TestAppInterface(mContext);
SuspendTestUtils.suspendAndAssertResult(ALL_TEST_PACKAGES, null, null, null,
EmptyArray.STRING);
final Bundle extras = createSingleKeyBundle(EXTRA_PACKAGE_NAME, TEST_APP_PACKAGE_NAME);
assertTrue("Block uninstall request failed", requestDpmAction(
ACTION_BLOCK_UNINSTALL, extras, mReceiverHandler));
// Package is unsuspended synchronously as part of setUninstallBlocked so the suspended
// state should be immediately reflected
assertFalse("Test app still suspended", mTestAppInterface.isTestAppSuspended());
}
private void assertUnsuspendedOnUserRestriction(String userRestriction) throws Exception {
mTestAppInterface = new TestAppInterface(mContext);
assertTrue("Test app not suspended before setting user restriction",
mTestAppInterface.isTestAppSuspended());
// Packages will be unsuspended asynchronously, so cannot check the suspended state directly
mTestAppInterface.startListeningForBroadcast(Intent.ACTION_MY_PACKAGE_UNSUSPENDED);
final Bundle extras = createSingleKeyBundle(EXTRA_USER_RESTRICTION, userRestriction);
assertTrue("Request to add restriction " + userRestriction + " failed",
requestDpmAction(ACTION_ADD_USER_RESTRICTION, extras, mReceiverHandler));
assertNotNull(Intent.ACTION_MY_PACKAGE_UNSUSPENDED
+ " not reported after setting restriction " + userRestriction,
mTestAppInterface.awaitBroadcast());
}
@Test
public void testUnsuspendedOnDisallowUninstallApps() throws Exception {
SuspendTestUtils.suspend(null, null, null);
assertUnsuspendedOnUserRestriction(DISALLOW_UNINSTALL_APPS);
}
@Test
public void testUnsuspendedOnDisallowAppsControl() throws Exception {
SuspendTestUtils.suspend(null, null, null);
assertUnsuspendedOnUserRestriction(DISALLOW_APPS_CONTROL);
}
@Test
public void testCannotSuspendWhenUninstallBlocked() throws Exception {
final Bundle extras = createSingleKeyBundle(EXTRA_PACKAGE_NAME, TEST_APP_PACKAGE_NAME);
assertTrue("Block uninstall request failed", requestDpmAction(
ACTION_BLOCK_UNINSTALL, extras, mReceiverHandler));
SuspendTestUtils.suspendAndAssertResult(ALL_TEST_PACKAGES, null, null, null,
TEST_PACKAGE_ARRAY);
}
private void assertCannotSuspendUnderUserRestriction(String userRestriction) throws Exception {
final Bundle extras = createSingleKeyBundle(EXTRA_USER_RESTRICTION, userRestriction);
assertTrue("Request to add restriction" + userRestriction + " failed",
requestDpmAction(ACTION_ADD_USER_RESTRICTION, extras, mReceiverHandler));
SuspendTestUtils.suspendAndAssertResult(ALL_TEST_PACKAGES, null, null, null,
ALL_TEST_PACKAGES);
}
@Test
public void testCannotSuspendUnderDisallowAppsControl() throws Exception {
assertCannotSuspendUnderUserRestriction(DISALLOW_APPS_CONTROL);
}
@Test
public void testCannotSuspendUnderDisallowUninstallApps() throws Exception {
assertCannotSuspendUnderUserRestriction(DISALLOW_UNINSTALL_APPS);
}
@After
public void tearDown() throws Exception {
if (mTestAppInterface != null) {
mTestAppInterface.disconnect();
}
final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
if (dpm.isAdminActive(ComponentName.unflattenFromString(DEVICE_ADMIN_COMPONENT))) {
setSuspendViaDpm(false);
final Bundle extras = createSingleKeyBundle(EXTRA_PACKAGE_NAME, TEST_APP_PACKAGE_NAME);
requestDpmAction(ACTION_UNBLOCK_UNINSTALL, extras, mReceiverHandler);
}
removeDeviceAdmin();
SuspendTestUtils.unsuspendAll();
}
}