1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.cts.managedprofile; 18 19 import static com.android.cts.managedprofile.BaseManagedProfileTest.ADMIN_RECEIVER_COMPONENT; 20 21 import android.app.admin.DevicePolicyManager; 22 import android.content.BroadcastReceiver; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.IntentFilter; 26 import android.content.pm.PackageManager; 27 import android.content.pm.ResolveInfo; 28 import android.os.UserManager; 29 import android.provider.MediaStore; 30 import android.test.InstrumentationTestCase; 31 32 import java.util.ArrayList; 33 import java.util.Arrays; 34 import java.util.List; 35 import java.util.concurrent.CountDownLatch; 36 import java.util.concurrent.TimeUnit; 37 38 /** 39 * Verify that certain cross profile intent filters are disallowed when the device admin sets 40 * DISALLOW_SHARE_INTO_MANAGED_PROFILE restriction. 41 * <p> 42 * The way we check if a particular cross profile intent filter is disallowed is by trying to 43 * resolve an example intent that matches the intent filter. The cross profile filter functions 44 * correctly if and only if the resolution result contains a system intent forwarder activity 45 * (com.android.internal.app.IntentForwarderActivity), which is the framework's mechanism to 46 * trampoline intents across profiles. Instead of hardcoding the system's intent forwarder activity, 47 * we retrieve it programmatically by resolving known cross profile intents specifically set up for 48 * this purpose: {@link #KNOWN_ACTION_TO_PROFILE} and {@link #KNOWN_ACTION_TO_PERSONAL} 49 */ 50 public class DisallowSharingIntoProfileTest extends InstrumentationTestCase { 51 52 // These are the data sharing intents which can be forwarded to the managed profile. 53 private final List<Intent> sharingIntentsToProfile = Arrays.asList( 54 new Intent(Intent.ACTION_SEND).setType("*/*"), 55 new Intent(Intent.ACTION_SEND_MULTIPLE).setType("*/*")); 56 57 // These are the data sharing intents which can be forwarded to the primary profile. 58 private final List<Intent> sharingIntentsToPersonal = new ArrayList<>(Arrays.asList( 59 new Intent(Intent.ACTION_GET_CONTENT).setType("*/*").addCategory( 60 Intent.CATEGORY_OPENABLE), 61 new Intent(Intent.ACTION_OPEN_DOCUMENT).setType("*/*").addCategory( 62 Intent.CATEGORY_OPENABLE), 63 new Intent(Intent.ACTION_PICK).setType("*/*").addCategory( 64 Intent.CATEGORY_DEFAULT), 65 new Intent(Intent.ACTION_PICK).addCategory(Intent.CATEGORY_DEFAULT))); 66 67 // These are the data sharing intents which can be forwarded to the primary profile, 68 // if the device supports FEATURE_CAMERA 69 private final List<Intent> sharingIntentsToPersonalIfCameraExists = Arrays.asList( 70 new Intent(MediaStore.ACTION_IMAGE_CAPTURE), 71 new Intent(MediaStore.ACTION_VIDEO_CAPTURE), 72 new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA), 73 new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA), 74 new Intent(MediaStore.ACTION_IMAGE_CAPTURE_SECURE), 75 new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE)); 76 77 private static final String KNOWN_ACTION_TO_PROFILE = ManagedProfileActivity.ACTION; 78 private static final String KNOWN_ACTION_TO_PERSONAL = PrimaryUserActivity.ACTION; 79 80 protected Context mContext; 81 protected DevicePolicyManager mDevicePolicyManager; 82 83 @Override setUp()84 public void setUp() throws Exception { 85 super.setUp(); 86 87 mContext = getInstrumentation().getContext(); 88 mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class); 89 assertNotNull(mDevicePolicyManager); 90 } 91 testSetUp()92 public void testSetUp() throws Exception { 93 // toggle the restriction to reset system's built-in cross profile intent filters, 94 // simulating the default state of a work profile created by ManagedProvisioning 95 testDisableSharingIntoProfile(); 96 testEnableSharingIntoProfile(); 97 98 PackageManager pm = mContext.getPackageManager(); 99 if (pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)) { 100 sharingIntentsToPersonal.addAll(sharingIntentsToPersonalIfCameraExists); 101 } 102 103 mDevicePolicyManager.clearCrossProfileIntentFilters(ADMIN_RECEIVER_COMPONENT); 104 // Set up cross profile intent filters so we can resolve these to find out framework's 105 // intent forwarder activity as ground truth 106 mDevicePolicyManager.addCrossProfileIntentFilter(ADMIN_RECEIVER_COMPONENT, 107 new IntentFilter(KNOWN_ACTION_TO_PERSONAL), 108 DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED); 109 mDevicePolicyManager.addCrossProfileIntentFilter(ADMIN_RECEIVER_COMPONENT, 110 new IntentFilter(KNOWN_ACTION_TO_PROFILE), 111 DevicePolicyManager.FLAG_MANAGED_CAN_ACCESS_PARENT); 112 } 113 114 /** 115 * Test sharing initiated from the personal side are mainly driven from the host side, see 116 * ManagedProfileTest.testDisallowSharingIntoProfileFromPersonal() See javadoc of 117 * {@link #DisallowSharingIntoProfileTest} class for the mechanism behind this test. 118 */ testSharingFromPersonalFails()119 public void testSharingFromPersonalFails() { 120 ResolveInfo toProfileForwarderInfo = getIntentForwarder( 121 new Intent(KNOWN_ACTION_TO_PROFILE)); 122 assertCrossProfileIntentsResolvability(sharingIntentsToProfile, toProfileForwarderInfo, 123 /* expectForwardable */ false); 124 } 125 testSharingFromPersonalSucceeds()126 public void testSharingFromPersonalSucceeds() { 127 ResolveInfo toProfileForwarderInfo = getIntentForwarder( 128 new Intent(KNOWN_ACTION_TO_PROFILE)); 129 assertCrossProfileIntentsResolvability(sharingIntentsToProfile, toProfileForwarderInfo, 130 /* expectForwardable */ true); 131 } 132 133 /** 134 * Test sharing initiated from the profile side i.e. user tries to pick up personal data within 135 * a work app. See javadoc of {@link #DisallowSharingIntoProfileTest} class for the mechanism 136 * behind this test. 137 */ testSharingFromProfile()138 public void testSharingFromProfile() throws Exception { 139 testSetUp(); 140 ResolveInfo toPersonalForwarderInfo = getIntentForwarder( 141 new Intent(KNOWN_ACTION_TO_PERSONAL)); 142 143 testDisableSharingIntoProfile(); 144 assertCrossProfileIntentsResolvability(sharingIntentsToPersonal, toPersonalForwarderInfo, 145 /* expectForwardable */ false); 146 testEnableSharingIntoProfile(); 147 assertCrossProfileIntentsResolvability(sharingIntentsToPersonal, toPersonalForwarderInfo, 148 /* expectForwardable */ true); 149 } 150 testEnableSharingIntoProfile()151 public void testEnableSharingIntoProfile() throws Exception { 152 setSharingEnabled(true); 153 } 154 testDisableSharingIntoProfile()155 public void testDisableSharingIntoProfile() throws Exception { 156 setSharingEnabled(false); 157 } 158 setSharingEnabled(boolean enabled)159 private void setSharingEnabled(boolean enabled) throws InterruptedException { 160 final CountDownLatch latch = new CountDownLatch(1); 161 BroadcastReceiver receiver = new BroadcastReceiver() { 162 @Override 163 public void onReceive(Context context, Intent intent) { 164 latch.countDown(); 165 } 166 }; 167 IntentFilter filter = new IntentFilter(); 168 filter.addAction(DevicePolicyManager.ACTION_DATA_SHARING_RESTRICTION_APPLIED); 169 mContext.registerReceiver(receiver, filter); 170 try { 171 if (enabled) { 172 mDevicePolicyManager.clearUserRestriction(ADMIN_RECEIVER_COMPONENT, 173 UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE); 174 } else { 175 mDevicePolicyManager.addUserRestriction(ADMIN_RECEIVER_COMPONENT, 176 UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE); 177 } 178 // Wait for the restriction to apply 179 assertTrue("Restriction not applied after 5 seconds", latch.await(5, TimeUnit.SECONDS)); 180 } finally { 181 mContext.unregisterReceiver(receiver); 182 } 183 } 184 assertCrossProfileIntentsResolvability(List<Intent> intents, ResolveInfo expectedForwarder, boolean expectForwardable)185 private void assertCrossProfileIntentsResolvability(List<Intent> intents, 186 ResolveInfo expectedForwarder, boolean expectForwardable) { 187 for (Intent intent : intents) { 188 List<ResolveInfo> resolveInfoList = mContext.getPackageManager().queryIntentActivities( 189 intent, 190 PackageManager.MATCH_DEFAULT_ONLY); 191 if (expectForwardable) { 192 assertTrue("Expect " + intent + " to be forwardable, but resolve list" 193 + " does not contain expected intent forwarder " + expectedForwarder, 194 containsResolveInfo(resolveInfoList, expectedForwarder)); 195 } else { 196 assertFalse("Expect " + intent + " not to be forwardable, but resolve list " 197 + "contains intent forwarder " + expectedForwarder, 198 containsResolveInfo(resolveInfoList, expectedForwarder)); 199 } 200 } 201 } 202 getIntentForwarder(Intent intent)203 private ResolveInfo getIntentForwarder(Intent intent) { 204 List<ResolveInfo> result = mContext.getPackageManager().queryIntentActivities(intent, 205 PackageManager.MATCH_DEFAULT_ONLY); 206 assertEquals("Expect only one resolve result for " + intent, 1, result.size()); 207 return result.get(0); 208 } 209 containsResolveInfo(List<ResolveInfo> list, ResolveInfo info)210 private boolean containsResolveInfo(List<ResolveInfo> list, ResolveInfo info) { 211 for (ResolveInfo entry : list) { 212 if (entry.activityInfo.packageName.equals(info.activityInfo.packageName) 213 && entry.activityInfo.name.equals(info.activityInfo.name)) { 214 return true; 215 } 216 } 217 return false; 218 } 219 } 220