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