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 package com.android.car.settings.enterprise; 17 18 import android.Manifest; 19 import android.annotation.Nullable; 20 import android.annotation.UserIdInt; 21 import android.app.admin.DeviceAdminInfo; 22 import android.app.admin.DevicePolicyManager; 23 import android.content.ComponentName; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.pm.ActivityInfo; 27 import android.content.pm.PackageManager; 28 import android.os.Bundle; 29 import android.os.UserHandle; 30 import android.os.UserManager; 31 32 import com.android.car.settings.common.Logger; 33 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; 34 import com.android.settingslib.RestrictedLockUtilsInternal; 35 36 import org.xmlpull.v1.XmlPullParserException; 37 38 import java.io.IOException; 39 import java.util.List; 40 41 /** 42 * Generic helper methods for this package. 43 */ 44 public final class EnterpriseUtils { 45 46 private static final Logger LOG = new Logger(EnterpriseUtils.class); 47 // TODO: ideally, we should not create a special user restriction other than what are 48 // defined in UserManager. 49 public static final String DISABLED_INPUT_METHOD = "disabled-input-method"; 50 // TODO: same as for DISABLED_INPUT_METHOD 51 public static final String BLOCKED_UNINSTALL_APP = "blocked-uninstall-app"; 52 53 static final String[] CAMERA_PERMISSIONS = new String[] { 54 Manifest.permission.CAMERA 55 }; 56 static final String[] LOCATION_PERMISSIONS = new String[] { 57 Manifest.permission.ACCESS_COARSE_LOCATION, 58 Manifest.permission.ACCESS_FINE_LOCATION 59 }; 60 static final String[] MICROPHONE_PERMISSIONS = new String[] { 61 Manifest.permission.RECORD_AUDIO 62 }; 63 64 /** 65 * Gets the active admin for the given package. 66 */ 67 @Nullable getAdminWithinPackage(Context context, String packageName)68 public static ComponentName getAdminWithinPackage(Context context, String packageName) { 69 List<ComponentName> admins = context.getSystemService(DevicePolicyManager.class) 70 .getActiveAdmins(); 71 if (admins == null) { 72 LOG.v("getAdminWithinPackage(): no active admins on context"); 73 return null; 74 } 75 return admins.stream().filter(i -> i.getPackageName().equals(packageName)).findAny() 76 .orElse(null); 77 } 78 79 /** 80 * Gets the active admin info for the given admin . 81 */ 82 @Nullable getDeviceAdminInfo(Context context, ComponentName admin)83 public static DeviceAdminInfo getDeviceAdminInfo(Context context, ComponentName admin) { 84 LOG.d("getDeviceAdminInfo()(): " + admin.flattenToShortString()); 85 86 ActivityInfo ai; 87 try { 88 ai = context.getPackageManager().getReceiverInfo(admin, PackageManager.GET_META_DATA); 89 } catch (PackageManager.NameNotFoundException e) { 90 LOG.v("Unable to get activity info for " + admin.flattenToShortString() + ": " + e); 91 return null; 92 } 93 94 try { 95 return new DeviceAdminInfo(context, ai); 96 } catch (XmlPullParserException | IOException e) { 97 LOG.v("Unable to retrieve device policy for " + admin.flattenToShortString() + ": ", 98 e); 99 return null; 100 } 101 } 102 103 /** 104 * Checks whether current user has the flag {@link UserManager.FLAG_DEMO}. 105 */ isDemoUser(Context context)106 public static boolean isDemoUser(Context context) { 107 return UserManager.isDeviceInDemoMode(context) 108 && getUserManager(context).isDemoUser(); 109 } 110 111 /** 112 * Checks whether current user has the flag {@link UserManager.FLAG_ADMIN}. 113 */ isAdminUser(Context context)114 public static boolean isAdminUser(Context context) { 115 return getUserManager(context).isAdminUser(); 116 } 117 118 /** 119 * Checks whether the restriction is set on the current user by device owner / profile owners 120 * but not by {@link UserManager}. 121 * 122 * <p>This includes restriction set on device owner but current user has affiliated profile 123 * owner. 124 */ hasUserRestrictionByDpm(Context context, String restriction)125 public static boolean hasUserRestrictionByDpm(Context context, String restriction) { 126 if (hasUserRestrictionByUm(context, restriction)) { 127 return false; 128 } 129 return getUserManager(context).hasUserRestriction(restriction); 130 } 131 132 /** 133 * Checks whether there are restrictions set via {@link UserManager} which doesn't include 134 * restrictions set by device owner / profile owners. 135 */ hasUserRestrictionByUm(Context context, String restriction)136 public static boolean hasUserRestrictionByUm(Context context, String restriction) { 137 return getUserManager(context) 138 .hasBaseUserRestriction(restriction, UserHandle.of(context.getUserId())); 139 } 140 141 /** 142 * Checks whether the device is managed. 143 */ isDeviceManaged(Context context)144 public static boolean isDeviceManaged(Context context) { 145 DevicePolicyManager dpm = getDevicePolicyManager(context); 146 return dpm.isDeviceManaged(); 147 } 148 149 /** 150 * Checks whether device owner is set on the device. 151 */ hasDeviceOwner(Context context)152 public static boolean hasDeviceOwner(Context context) { 153 DevicePolicyManager dpm = getDevicePolicyManager(context); 154 return dpm.isDeviceManaged() && getDeviceOwner(context) != null; 155 } 156 157 /** 158 * Gets device owner user id on the device. 159 */ 160 @UserIdInt getDeviceOwnerUserId(Context context)161 private static int getDeviceOwnerUserId(Context context) { 162 return getDevicePolicyManager(context).getDeviceOwnerUserId(); 163 } 164 165 /** 166 * Gets device owner component on the device. 167 */ 168 @Nullable getDeviceOwner(Context context)169 private static ComponentName getDeviceOwner(Context context) { 170 return getDevicePolicyManager(context).getDeviceOwnerComponentOnAnyUser(); 171 } 172 getUserManager(Context context)173 private static UserManager getUserManager(Context context) { 174 return context.getSystemService(UserManager.class); 175 } 176 getDevicePolicyManager(Context context)177 private static DevicePolicyManager getDevicePolicyManager(Context context) { 178 return context.getSystemService(DevicePolicyManager.class); 179 } 180 181 /** 182 * Gets an {@code ActionDisabledByAdminDialogFragment} for the target restriction to show on 183 * the current user. 184 */ getActionDisabledByAdminDialog( Context context, String restriction)185 public static ActionDisabledByAdminDialogFragment getActionDisabledByAdminDialog( 186 Context context, String restriction) { 187 return getActionDisabledByAdminDialog(context, restriction, /* restrictedPackage= */ null); 188 } 189 190 /** 191 * Gets an {@code ActionDisabledByAdminDialogFragment} when the input method is restricted for 192 * the current user. 193 */ getInputMethodDisabledByAdminDialog( Context context, String restriction)194 public static ActionDisabledByAdminDialogFragment getInputMethodDisabledByAdminDialog( 195 Context context, String restriction) { 196 return getActionDisabledByAdminDialog(context, restriction, /* restrictedPackage= */ null); 197 } 198 199 /** 200 * Gets an {@code ActionDisabledByAdminDialogFragment} for the target restriction to show on 201 * the current user with additional restricted package information. 202 */ getActionDisabledByAdminDialog( Context context, String restriction, @Nullable String restrictedPackage)203 public static ActionDisabledByAdminDialogFragment getActionDisabledByAdminDialog( 204 Context context, String restriction, @Nullable String restrictedPackage) { 205 int adminUser = hasDeviceOwner(context) 206 ? getDeviceOwnerUserId(context) 207 : context.getUserId(); 208 return ActionDisabledByAdminDialogFragment 209 .newInstance(restriction, restrictedPackage, adminUser); 210 } 211 212 /** 213 * Gets enforced admin information from Intent that started the 214 * {@code ActionDisabledByAdminDialogActivity}. 215 */ getEnforcedAdminFromIntent(Context context, Intent intent)216 public static EnforcedAdmin getEnforcedAdminFromIntent(Context context, Intent intent) { 217 EnforcedAdmin admin = new EnforcedAdmin(null, context.getUser()); 218 if (intent == null) { 219 return admin; 220 } 221 admin.component = intent.getParcelableExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN); 222 int userId = intent.getIntExtra(Intent.EXTRA_USER_ID, context.getUserId()); 223 224 Bundle adminDetails = null; 225 if (admin.component == null) { 226 DevicePolicyManager devicePolicyManager = getDevicePolicyManager(context); 227 admin.component = adminDetails.getParcelable(DevicePolicyManager.EXTRA_DEVICE_ADMIN); 228 } 229 230 if (intent.hasExtra(Intent.EXTRA_USER)) { 231 admin.user = intent.getParcelableExtra(Intent.EXTRA_USER); 232 } else { 233 if (adminDetails != null) { 234 userId = adminDetails.getInt(Intent.EXTRA_USER_ID, UserHandle.myUserId()); 235 } 236 if (userId == UserHandle.USER_NULL) { 237 admin.user = null; 238 } else { 239 admin.user = UserHandle.of(userId); 240 } 241 } 242 return admin; 243 } 244 245 /** 246 * Gets {@code RestrictedLockUtils.EnforcedAdmin} for the device policy that affects 247 * current user. 248 * 249 * @param context for current user 250 * @param adminUser which can be either profile owner on current user or device owner on 251 * headless system user 252 * @param restriction which can be user restriction or restriction policy defined 253 * in this class 254 * @param restrictedPackage is the target package that restriction policy is set 255 * @return {@code RestrictedLockUtils.EnforcedAdmin} 256 */ getEnforcedAdmin(Context context, @UserIdInt int adminUser, @Nullable String restriction, String restrictedPackage)257 public static EnforcedAdmin getEnforcedAdmin(Context context, @UserIdInt int adminUser, 258 @Nullable String restriction, String restrictedPackage) { 259 if (restriction == null) { 260 return null; 261 } 262 EnforcedAdmin admin = null; 263 if (hasUserRestrictionByDpm(context, restriction)) { 264 admin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced( 265 context, restriction, context.getUserId()); 266 LOG.v("getEnforcedAdmin(): " + adminUser + " restriction: " + restriction 267 + " restrictedPackage: " + restrictedPackage); 268 269 if (admin.component == null && context.getUserId() != adminUser) { 270 // User restriction might be set on primary user which is user 0 as a device-wide 271 // policy. 272 admin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced( 273 context, restriction, adminUser); 274 } 275 } else if (restriction.equals(DISABLED_INPUT_METHOD)) { 276 if (restrictedPackage == null) { 277 LOG.e("getEnforcedAdmin() for " + DISABLED_INPUT_METHOD 278 + " fails since restrictedPackage is null"); 279 return admin; 280 } 281 admin = RestrictedLockUtilsInternal.checkIfInputMethodDisallowed( 282 context, restrictedPackage, context.getUserId()); 283 } else if (restriction.equals(BLOCKED_UNINSTALL_APP)) { 284 admin = RestrictedLockUtilsInternal.checkIfUninstallBlocked( 285 context, restrictedPackage, context.getUserId()); 286 } 287 LOG.v("getEnforcedAdmin():" + admin); 288 return admin; 289 } 290 EnterpriseUtils()291 private EnterpriseUtils() { 292 throw new UnsupportedOperationException("Provides only static methods"); 293 } 294 } 295