1 /* 2 * Copyright (C) 2022 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.server.devicepolicy; 18 19 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; 20 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; 21 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.annotation.UserIdInt; 25 import android.app.AppGlobals; 26 import android.app.AppOpsManager; 27 import android.app.admin.DevicePolicyCache; 28 import android.app.admin.DevicePolicyManager; 29 import android.app.admin.DevicePolicyManagerInternal; 30 import android.app.admin.IntentFilterPolicyKey; 31 import android.app.admin.LockTaskPolicy; 32 import android.app.admin.PackagePermissionPolicyKey; 33 import android.app.admin.PackagePolicyKey; 34 import android.app.admin.PolicyKey; 35 import android.app.admin.UserRestrictionPolicyKey; 36 import android.app.admin.flags.Flags; 37 import android.app.usage.UsageStatsManagerInternal; 38 import android.content.ComponentName; 39 import android.content.Context; 40 import android.content.Intent; 41 import android.content.IntentFilter; 42 import android.content.pm.IPackageManager; 43 import android.content.pm.PackageManager; 44 import android.content.pm.PackageManagerInternal; 45 import android.os.Binder; 46 import android.os.Bundle; 47 import android.os.Process; 48 import android.os.RemoteException; 49 import android.os.ServiceManager; 50 import android.os.SystemProperties; 51 import android.os.UserHandle; 52 import android.permission.AdminPermissionControlParams; 53 import android.permission.PermissionControllerManager; 54 import android.provider.Settings; 55 import android.util.ArraySet; 56 import android.util.Slog; 57 import android.view.IWindowManager; 58 59 import com.android.internal.infra.AndroidFuture; 60 import com.android.internal.os.BackgroundThread; 61 import com.android.internal.util.ArrayUtils; 62 import com.android.server.LocalServices; 63 import com.android.server.pm.UserManagerInternal; 64 import com.android.server.utils.Slogf; 65 66 import java.util.Collections; 67 import java.util.List; 68 import java.util.Objects; 69 import java.util.Set; 70 import java.util.concurrent.CompletableFuture; 71 import java.util.concurrent.CountDownLatch; 72 import java.util.concurrent.TimeUnit; 73 import java.util.concurrent.atomic.AtomicReference; 74 75 final class PolicyEnforcerCallbacks { 76 77 private static final String LOG_TAG = "PolicyEnforcerCallbacks"; 78 noOp(T value, Context context, Integer userId, PolicyKey policyKey)79 static <T> CompletableFuture<Boolean> noOp(T value, Context context, Integer userId, 80 PolicyKey policyKey) { 81 return AndroidFuture.completedFuture(true); 82 } 83 setAutoTimeZonePolicy( @ullable Integer policy, @NonNull Context context, int userId, @NonNull PolicyKey policyKey)84 static CompletableFuture<Boolean> setAutoTimeZonePolicy( 85 @Nullable Integer policy, @NonNull Context context, int userId, 86 @NonNull PolicyKey policyKey) { 87 if (!Flags.setAutoTimeZoneEnabledCoexistence()) { 88 Slogf.w(LOG_TAG, "Trying to enforce setAutoTimeZonePolicy while flag is off."); 89 return AndroidFuture.completedFuture(true); 90 } 91 return Binder.withCleanCallingIdentity(() -> { 92 Objects.requireNonNull(context); 93 if (policy != null && 94 policy == DevicePolicyManager.AUTO_TIME_ZONE_NOT_CONTROLLED_BY_POLICY) { 95 return AndroidFuture.completedFuture(false); 96 } 97 int enabled = policy != null && 98 policy == DevicePolicyManager.AUTO_TIME_ZONE_ENABLED ? 1 : 0; 99 return AndroidFuture.completedFuture(Settings.Global.putInt( 100 context.getContentResolver(), Settings.Global.AUTO_TIME_ZONE, 101 enabled)); 102 }); 103 } 104 setPermissionGrantState( @ullable Integer grantState, @NonNull Context context, int userId, @NonNull PolicyKey policyKey)105 static CompletableFuture<Boolean> setPermissionGrantState( 106 @Nullable Integer grantState, @NonNull Context context, int userId, 107 @NonNull PolicyKey policyKey) { 108 if (!Flags.setPermissionGrantStateCoexistence()) { 109 Slogf.w(LOG_TAG, "Trying to enforce setPermissionGrantState while flag is off."); 110 return AndroidFuture.completedFuture(true); 111 } 112 return Binder.withCleanCallingIdentity(() -> { 113 if (!(policyKey instanceof PackagePermissionPolicyKey)) { 114 throw new IllegalArgumentException("policyKey is not of type " 115 + "PermissionGrantStatePolicyKey, passed in policyKey is: " + policyKey); 116 } 117 PackagePermissionPolicyKey parsedKey = (PackagePermissionPolicyKey) policyKey; 118 Objects.requireNonNull(parsedKey.getPermissionName()); 119 Objects.requireNonNull(parsedKey.getPackageName()); 120 Objects.requireNonNull(context); 121 122 int value = grantState == null 123 ? DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT 124 : grantState; 125 126 // TODO(b/278710449): stop blocking in the main thread 127 BlockingCallback callback = new BlockingCallback(); 128 // TODO: remove canAdminGrantSensorPermissions once we expose a new method in 129 // permissionController that doesn't need it. 130 AdminPermissionControlParams permissionParams = new AdminPermissionControlParams( 131 parsedKey.getPackageName(), parsedKey.getPermissionName(), value, 132 /* canAdminGrantSensorPermissions= */ true); 133 getPermissionControllerManager(context, UserHandle.of(userId)) 134 // TODO: remove callingPackage param and stop passing context.getPackageName() 135 .setRuntimePermissionGrantStateByDeviceAdmin(context.getPackageName(), 136 permissionParams, context.getMainExecutor(), callback::trigger); 137 try { 138 return AndroidFuture.completedFuture( 139 callback.await(20_000, TimeUnit.MILLISECONDS)); 140 } catch (Exception e) { 141 // TODO: add logging 142 return AndroidFuture.completedFuture(false); 143 } 144 }); 145 } 146 147 @NonNull 148 private static PermissionControllerManager getPermissionControllerManager( 149 Context context, UserHandle user) { 150 if (user.equals(context.getUser())) { 151 return context.getSystemService(PermissionControllerManager.class); 152 } else { 153 try { 154 return context.createPackageContextAsUser(context.getPackageName(), /* flags= */ 0, 155 user).getSystemService(PermissionControllerManager.class); 156 } catch (PackageManager.NameNotFoundException notPossible) { 157 // not possible 158 throw new IllegalStateException(notPossible); 159 } 160 } 161 } 162 163 static CompletableFuture<Boolean> enforceSecurityLogging( 164 @Nullable Boolean value, @NonNull Context context, int userId, 165 @NonNull PolicyKey policyKey) { 166 final var dpmi = LocalServices.getService(DevicePolicyManagerInternal.class); 167 dpmi.enforceSecurityLoggingPolicy(Boolean.TRUE.equals(value)); 168 return AndroidFuture.completedFuture(true); 169 } 170 171 static CompletableFuture<Boolean> enforceAuditLogging( 172 @Nullable Boolean value, @NonNull Context context, int userId, 173 @NonNull PolicyKey policyKey) { 174 final var dpmi = LocalServices.getService(DevicePolicyManagerInternal.class); 175 dpmi.enforceAuditLoggingPolicy(Boolean.TRUE.equals(value)); 176 return AndroidFuture.completedFuture(true); 177 } 178 179 static CompletableFuture<Boolean> setLockTask( 180 @Nullable LockTaskPolicy policy, @NonNull Context context, int userId) { 181 List<String> packages = Collections.emptyList(); 182 int flags = LockTaskPolicy.DEFAULT_LOCK_TASK_FLAG; 183 if (policy != null) { 184 packages = List.copyOf(policy.getPackages()); 185 flags = policy.getFlags(); 186 } 187 DevicePolicyManagerService.updateLockTaskPackagesLocked(context, packages, userId); 188 DevicePolicyManagerService.updateLockTaskFeaturesLocked(flags, userId); 189 return AndroidFuture.completedFuture(true); 190 } 191 192 193 /** 194 * Application restrictions are stored and retrieved from DPMS, so no enforcing (aka pushing 195 * it to UMS) is required. Only need to send broadcast to the target user here as we rely on 196 * the inheritable policy propagation logic in PolicyEngine to apply this policy to multiple 197 * profiles. The broadcast should only be sent when an application restriction is set, so we 198 * rely on the POLICY_FLAG_SKIP_ENFORCEMENT_IF_UNCHANGED flag so DPE only invokes this callback 199 * when the policy is set, and not during system boot or other situations. 200 */ 201 static CompletableFuture<Boolean> setApplicationRestrictions(Bundle bundle, Context context, 202 Integer userId, PolicyKey policyKey) { 203 Binder.withCleanCallingIdentity(() -> { 204 PackagePolicyKey key = (PackagePolicyKey) policyKey; 205 String packageName = key.getPackageName(); 206 Objects.requireNonNull(packageName); 207 Intent changeIntent = new Intent(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED); 208 changeIntent.setPackage(packageName); 209 changeIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 210 context.sendBroadcastAsUser(changeIntent, UserHandle.of(userId)); 211 }); 212 return AndroidFuture.completedFuture(true); 213 } 214 215 public static CompletableFuture<Boolean> setAutoTimePolicy( 216 Integer policy, Context context, Integer userId, PolicyKey policyKey) { 217 if (!Flags.setAutoTimeEnabledCoexistence()) { 218 Slogf.w(LOG_TAG, "Trying to enforce setAutoTimePolicy while flag is off."); 219 return AndroidFuture.completedFuture(true); 220 } 221 return Binder.withCleanCallingIdentity(() -> { 222 Objects.requireNonNull(context); 223 if (policy != null 224 && policy == DevicePolicyManager.AUTO_TIME_NOT_CONTROLLED_BY_POLICY) { 225 return AndroidFuture.completedFuture(false); 226 } 227 int enabled = policy != null && policy == DevicePolicyManager.AUTO_TIME_ENABLED ? 1 : 0; 228 return AndroidFuture.completedFuture( 229 Settings.Global.putInt( 230 context.getContentResolver(), Settings.Global.AUTO_TIME, enabled)); 231 }); 232 } 233 234 private static class BlockingCallback { 235 private final CountDownLatch mLatch = new CountDownLatch(1); 236 private final AtomicReference<Boolean> mValue = new AtomicReference<>(); 237 238 public void trigger(Boolean value) { 239 mValue.set(value); 240 mLatch.countDown(); 241 } 242 243 public Boolean await(long timeout, TimeUnit unit) throws InterruptedException { 244 if (!mLatch.await(timeout, unit)) { 245 Slogf.e(LOG_TAG, "Callback was not received"); 246 } 247 return mValue.get(); 248 } 249 } 250 251 // TODO: when a local policy exists for a user, this callback will be invoked for this user 252 // individually as well as for USER_ALL. This can be optimized by separating local and global 253 // enforcement in the policy engine. 254 static CompletableFuture<Boolean> setUserControlDisabledPackages( 255 @Nullable Set<String> packages, Context context, int userId, PolicyKey policyKey) { 256 Binder.withCleanCallingIdentity(() -> { 257 PackageManagerInternal pmi = 258 LocalServices.getService(PackageManagerInternal.class); 259 AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); 260 261 pmi.setOwnerProtectedPackages(userId, 262 packages == null ? null : packages.stream().toList()); 263 LocalServices.getService(UsageStatsManagerInternal.class) 264 .setAdminProtectedPackages( 265 packages == null ? null : new ArraySet<>(packages), userId); 266 267 if (packages == null || packages.isEmpty()) { 268 return; 269 } 270 271 for (int user : resolveUsers(userId)) { 272 setBgUsageAppOp(packages, pmi, user, appOpsManager); 273 if (Flags.disallowUserControlStoppedStateFix()) { 274 for (String packageName : packages) { 275 pmi.setPackageStoppedState(packageName, false, user); 276 } 277 } 278 } 279 }); 280 return AndroidFuture.completedFuture(true); 281 } 282 283 /** Handles USER_ALL expanding it into the list of all intact users. */ 284 private static List<Integer> resolveUsers(int userId) { 285 if (userId == UserHandle.USER_ALL) { 286 UserManagerInternal userManager = LocalServices.getService(UserManagerInternal.class); 287 return userManager.getUsers(/* excludeDying= */ true) 288 .stream().map(ui -> ui.id).toList(); 289 } else { 290 return List.of(userId); 291 } 292 } 293 294 private static void setBgUsageAppOp(Set<String> packages, PackageManagerInternal pmi, 295 int userId, AppOpsManager appOpsManager) { 296 for (var pkg : packages) { 297 int packageFlags = MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE; 298 final var appInfo = pmi.getApplicationInfo(pkg, packageFlags, Process.myUid(), userId); 299 if (appInfo != null) { 300 DevicePolicyManagerService.setBgUsageAppOp(appOpsManager, appInfo); 301 } 302 } 303 } 304 305 static CompletableFuture<Boolean> addPersistentPreferredActivity( 306 @Nullable ComponentName preferredActivity, @NonNull Context context, int userId, 307 @NonNull PolicyKey policyKey) { 308 Binder.withCleanCallingIdentity(() -> { 309 try { 310 if (!(policyKey instanceof IntentFilterPolicyKey)) { 311 throw new IllegalArgumentException("policyKey is not of type " 312 + "IntentFilterPolicyKey, passed in policyKey is: " + policyKey); 313 } 314 IntentFilterPolicyKey parsedKey = 315 (IntentFilterPolicyKey) policyKey; 316 IntentFilter filter = Objects.requireNonNull(parsedKey.getIntentFilter()); 317 318 IPackageManager packageManager = AppGlobals.getPackageManager(); 319 if (preferredActivity != null) { 320 packageManager.addPersistentPreferredActivity( 321 filter, preferredActivity, userId); 322 } else { 323 packageManager.clearPersistentPreferredActivity(filter, userId); 324 } 325 packageManager.flushPackageRestrictionsAsUser(userId); 326 } catch (RemoteException re) { 327 // Shouldn't happen 328 Slog.wtf(LOG_TAG, "Error adding/removing persistent preferred activity", re); 329 } 330 }); 331 return AndroidFuture.completedFuture(true); 332 } 333 334 static CompletableFuture<Boolean> setUninstallBlocked( 335 @Nullable Boolean uninstallBlocked, @NonNull Context context, int userId, 336 @NonNull PolicyKey policyKey) { 337 return Binder.withCleanCallingIdentity(() -> { 338 if (!(policyKey instanceof PackagePolicyKey)) { 339 throw new IllegalArgumentException("policyKey is not of type " 340 + "PackagePolicyKey, passed in policyKey is: " + policyKey); 341 } 342 PackagePolicyKey parsedKey = (PackagePolicyKey) policyKey; 343 String packageName = Objects.requireNonNull(parsedKey.getPackageName()); 344 DevicePolicyManagerService.setUninstallBlockedUnchecked( 345 packageName, 346 uninstallBlocked != null && uninstallBlocked, 347 userId); 348 return AndroidFuture.completedFuture(true); 349 }); 350 } 351 352 static CompletableFuture<Boolean> setUserRestriction( 353 @Nullable Boolean enabled, @NonNull Context context, int userId, 354 @NonNull PolicyKey policyKey) { 355 return Binder.withCleanCallingIdentity(() -> { 356 if (!(policyKey instanceof UserRestrictionPolicyKey)) { 357 throw new IllegalArgumentException("policyKey is not of type " 358 + "UserRestrictionPolicyKey, passed in policyKey is: " + policyKey); 359 } 360 UserRestrictionPolicyKey parsedKey = 361 (UserRestrictionPolicyKey) policyKey; 362 UserManagerInternal userManager = LocalServices.getService(UserManagerInternal.class); 363 userManager.setUserRestriction( 364 userId, parsedKey.getRestriction(), enabled != null && enabled); 365 return AndroidFuture.completedFuture(true); 366 }); 367 } 368 369 static CompletableFuture<Boolean> setApplicationHidden( 370 @Nullable Boolean hide, @NonNull Context context, int userId, 371 @NonNull PolicyKey policyKey) { 372 return Binder.withCleanCallingIdentity(() -> { 373 if (!(policyKey instanceof PackagePolicyKey)) { 374 throw new IllegalArgumentException("policyKey is not of type " 375 + "PackagePolicyKey, passed in policyKey is: " + policyKey); 376 } 377 PackagePolicyKey parsedKey = (PackagePolicyKey) policyKey; 378 String packageName = Objects.requireNonNull(parsedKey.getPackageName()); 379 IPackageManager packageManager = AppGlobals.getPackageManager(); 380 return AndroidFuture.completedFuture( 381 packageManager.setApplicationHiddenSettingAsUser( 382 packageName, hide != null && hide, userId)); 383 }); 384 } 385 386 static CompletableFuture<Boolean> setScreenCaptureDisabled( 387 @Nullable Boolean disabled, @NonNull Context context, int userId, 388 @NonNull PolicyKey policyKey) { 389 Binder.withCleanCallingIdentity(() -> { 390 DevicePolicyCache cache = DevicePolicyCache.getInstance(); 391 if (cache instanceof DevicePolicyCacheImpl) { 392 DevicePolicyCacheImpl parsedCache = (DevicePolicyCacheImpl) cache; 393 parsedCache.setScreenCaptureDisallowedUser( 394 userId, disabled != null && disabled); 395 updateScreenCaptureDisabled(); 396 } 397 }); 398 return AndroidFuture.completedFuture(true); 399 } 400 401 static CompletableFuture<Boolean> setContentProtectionPolicy( 402 @Nullable Integer value, 403 @NonNull Context context, 404 @UserIdInt Integer userId, 405 @NonNull PolicyKey policyKey) { 406 Binder.withCleanCallingIdentity( 407 () -> { 408 DevicePolicyCache cache = DevicePolicyCache.getInstance(); 409 if (cache instanceof DevicePolicyCacheImpl cacheImpl) { 410 cacheImpl.setContentProtectionPolicy(userId, value); 411 } 412 }); 413 return AndroidFuture.completedFuture(true); 414 } 415 416 private static void updateScreenCaptureDisabled() { 417 BackgroundThread.getHandler().post(() -> { 418 try { 419 IWindowManager.Stub 420 .asInterface(ServiceManager.getService(Context.WINDOW_SERVICE)) 421 .refreshScreenCaptureDisabled(); 422 } catch (RemoteException e) { 423 Slogf.w(LOG_TAG, "Unable to notify WindowManager.", e); 424 } 425 }); 426 } 427 428 static CompletableFuture<Boolean> setPersonalAppsSuspended( 429 @Nullable Boolean suspended, @NonNull Context context, int userId, 430 @NonNull PolicyKey policyKey) { 431 Binder.withCleanCallingIdentity(() -> { 432 if (suspended != null && suspended) { 433 suspendPersonalAppsInPackageManager(context, userId); 434 } else { 435 LocalServices.getService(PackageManagerInternal.class) 436 .unsuspendAdminSuspendedPackages(userId); 437 } 438 }); 439 return AndroidFuture.completedFuture(true); 440 } 441 442 private static void suspendPersonalAppsInPackageManager(Context context, int userId) { 443 final String[] appsToSuspend = PersonalAppsSuspensionHelper.forUser(context, userId) 444 .getPersonalAppsForSuspension(); 445 Slogf.i(LOG_TAG, "Suspending personal apps: %s", String.join(",", appsToSuspend)); 446 final String[] failedApps = LocalServices.getService(PackageManagerInternal.class) 447 .setPackagesSuspendedByAdmin(userId, appsToSuspend, true); 448 if (!ArrayUtils.isEmpty(failedApps)) { 449 Slogf.wtf(LOG_TAG, "Failed to suspend apps: " + String.join(",", failedApps)); 450 } 451 } 452 453 static CompletableFuture<Boolean> setUsbDataSignalingEnabled(@Nullable Boolean value, 454 @NonNull Context context) { 455 return Binder.withCleanCallingIdentity(() -> { 456 Objects.requireNonNull(context); 457 458 boolean enabled = value == null || value; 459 DevicePolicyManagerService.updateUsbDataSignal(context, enabled); 460 return AndroidFuture.completedFuture(true); 461 }); 462 } 463 464 static CompletableFuture<Boolean> setMtePolicy( 465 @Nullable Integer mtePolicy, @NonNull Context context, int userId, 466 @NonNull PolicyKey policyKey) { 467 if (mtePolicy == null) { 468 mtePolicy = DevicePolicyManager.MTE_NOT_CONTROLLED_BY_POLICY; 469 } 470 final Set<Integer> allowedModes = 471 Set.of( 472 DevicePolicyManager.MTE_NOT_CONTROLLED_BY_POLICY, 473 DevicePolicyManager.MTE_DISABLED, 474 DevicePolicyManager.MTE_ENABLED); 475 if (!allowedModes.contains(mtePolicy)) { 476 Slog.wtf(LOG_TAG, "MTE policy is not a known one: " + mtePolicy); 477 return AndroidFuture.completedFuture(false); 478 } 479 480 final String mteDpmSystemProperty = 481 "ro.arm64.memtag.bootctl_device_policy_manager"; 482 final String mteSettingsSystemProperty = 483 "ro.arm64.memtag.bootctl_settings_toggle"; 484 final String mteControlProperty = "arm64.memtag.bootctl"; 485 486 final boolean isAvailable = SystemProperties.getBoolean(mteDpmSystemProperty, 487 SystemProperties.getBoolean(mteSettingsSystemProperty, false)); 488 if (!isAvailable) { 489 return AndroidFuture.completedFuture(false); 490 } 491 492 if (mtePolicy == DevicePolicyManager.MTE_ENABLED) { 493 SystemProperties.set(mteControlProperty, "memtag"); 494 } else if (mtePolicy == DevicePolicyManager.MTE_DISABLED) { 495 SystemProperties.set(mteControlProperty, "memtag-off"); 496 } else if (mtePolicy == DevicePolicyManager.MTE_NOT_CONTROLLED_BY_POLICY) { 497 SystemProperties.set(mteControlProperty, "default"); 498 } 499 500 return AndroidFuture.completedFuture(true); 501 } 502 } 503