1 /* 2 * Copyright (C) 2021 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.bedstead.nene.devicepolicy; 18 19 import static android.cts.testapisreflection.TestApisReflectionKt.isRemovingAdmin; 20 import static com.android.bedstead.permissions.CommonPermissions.INTERACT_ACROSS_USERS_FULL; 21 22 import static com.google.common.truth.Truth.assertThat; 23 24 import android.app.Activity; 25 import android.app.admin.DeviceAdminReceiver; 26 import android.app.admin.DevicePolicyManager; 27 import android.content.ComponentName; 28 import android.content.Context; 29 import android.content.Intent; 30 31 import com.android.bedstead.nene.TestApis; 32 import com.android.bedstead.nene.annotations.Experimental; 33 import com.android.bedstead.nene.packages.Package; 34 import com.android.bedstead.nene.users.UserReference; 35 import com.android.bedstead.nene.utils.BlockingBroadcastReceiver; 36 import com.android.bedstead.nene.utils.Poll; 37 import com.android.bedstead.nene.utils.Retry; 38 import com.android.bedstead.permissions.PermissionContext; 39 import com.android.bedstead.testapisreflection.TestApisConstants; 40 41 import java.time.Duration; 42 import java.util.Objects; 43 44 /** 45 * A reference to either a Device Owner or a Profile Owner. 46 */ 47 public abstract class DevicePolicyController implements AutoCloseable { 48 49 protected static final String TEST_APP_APP_COMPONENT_FACTORY = 50 "com.android.bedstead.testapp.TestAppAppComponentFactory"; 51 52 protected final UserReference mUser; 53 protected final Package mPackage; 54 protected final ComponentName mComponentName; 55 DevicePolicyController(UserReference user, Package pkg, ComponentName componentName)56 DevicePolicyController(UserReference user, Package pkg, ComponentName componentName) { 57 if (user == null || pkg == null || componentName == null) { 58 throw new NullPointerException(); 59 } 60 61 mUser = user; 62 mPackage = pkg; 63 mComponentName = componentName; 64 } 65 66 /** 67 * Get the {@link UserReference} which this device policy controller is installed into. 68 */ user()69 public UserReference user() { 70 return mUser; 71 } 72 73 /** 74 * Get the {@link Package} of the device policy controller. 75 */ pkg()76 public Package pkg() { 77 return mPackage; 78 } 79 80 /** 81 * Get the {@link ComponentName} of the {@link DeviceAdminReceiver} for this device policy 82 * controller. 83 */ componentName()84 public ComponentName componentName() { 85 return mComponentName; 86 } 87 88 /** 89 * Remove this device policy controller. 90 */ remove()91 public abstract void remove(); 92 93 /** 94 * Remove test app. 95 * 96 * Special case for removing TestApp DPCs - this works even when not testOnly 97 * but not on profiles 98 */ removeTestApp()99 protected void removeTestApp() { 100 // Special case for removing TestApp DPCs - this works even when not testOnly 101 Intent intent = new Intent(TestApisConstants.ACTION_DISABLE_SELF); 102 intent.setComponent(new ComponentName(pkg().packageName(), 103 "com.android.bedstead.testapp.TestAppBroadcastController")); 104 Context context = TestApis.context().androidContextAsUser(mUser); 105 106 try (PermissionContext p = 107 TestApis.permissions().withPermission(INTERACT_ACROSS_USERS_FULL)) { 108 // If the profile isn't ready then the broadcast won't be sent and the profile owner 109 // will not be removed. So we can retry until the broadcast has been dealt with. 110 Retry.logic(() -> { 111 com.android.bedstead.nene.utils.BlockingBroadcastReceiver 112 b = new BlockingBroadcastReceiver( 113 TestApis.context().instrumentedContext()); 114 115 context.sendOrderedBroadcast( 116 intent, /* receiverPermission= */ null, b, /* scheduler= */ 117 null, /* initialCode= */ 118 Activity.RESULT_CANCELED, /* initialData= */ null, /* initialExtras= */ 119 null); 120 121 b.awaitForBroadcastOrFail(Duration.ofSeconds(30).toMillis()); 122 assertThat(b.getResultCode()).isEqualTo(Activity.RESULT_OK); 123 }).timeout(Duration.ofMinutes(5)).runAndWrapException(); 124 125 DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class); 126 127 Poll.forValue(() -> isRemovingAdmin(dpm, mComponentName, mUser.id())) 128 .toNotBeEqualTo(true) 129 .timeout(Duration.ofMinutes(5)) 130 .errorOnFail() 131 .await(); 132 } 133 134 } 135 136 /** 137 * Check if DPC is active 138 */ 139 @Experimental isActive()140 public boolean isActive() { 141 try (PermissionContext p = 142 TestApis.permissions().withPermission(INTERACT_ACROSS_USERS_FULL)) { 143 DevicePolicyManager devicePolicyManager = 144 TestApis.context().androidContextAsUser(mUser) 145 .getSystemService(DevicePolicyManager.class); 146 147 return devicePolicyManager.isAdminActive(mComponentName); 148 } 149 } 150 151 /** 152 * Check if DPC has granted the specified policy. 153 */ 154 @Experimental hasGrantedPolicy(int policy)155 public boolean hasGrantedPolicy(int policy) { 156 try (PermissionContext p = 157 TestApis.permissions().withPermission(INTERACT_ACROSS_USERS_FULL)) { 158 DevicePolicyManager devicePolicyManager = 159 TestApis.context().androidContextAsUser(mUser) 160 .getSystemService(DevicePolicyManager.class); 161 162 return devicePolicyManager.hasGrantedPolicy(mComponentName, policy); 163 } 164 } 165 166 @Override hashCode()167 public int hashCode() { 168 return Objects.hashCode(mUser) 169 + Objects.hashCode(mPackage) 170 + Objects.hashCode(mComponentName); 171 } 172 173 /** See {@link #remove}. */ 174 @Override close()175 public void close() { 176 remove(); 177 } 178 } 179