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