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 com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; 20 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.app.AppGlobals; 24 import android.app.admin.DevicePolicyCache; 25 import android.app.admin.DevicePolicyManager; 26 import android.app.admin.IntentFilterPolicyKey; 27 import android.app.admin.LockTaskPolicy; 28 import android.app.admin.PackagePermissionPolicyKey; 29 import android.app.admin.PackagePolicyKey; 30 import android.app.admin.PolicyKey; 31 import android.app.admin.UserRestrictionPolicyKey; 32 import android.app.usage.UsageStatsManagerInternal; 33 import android.content.ComponentName; 34 import android.content.Context; 35 import android.content.IntentFilter; 36 import android.content.pm.IPackageManager; 37 import android.content.pm.PackageManager; 38 import android.content.pm.PackageManagerInternal; 39 import android.os.Binder; 40 import android.os.RemoteException; 41 import android.os.ServiceManager; 42 import android.os.UserHandle; 43 import android.permission.AdminPermissionControlParams; 44 import android.permission.PermissionControllerManager; 45 import android.provider.Settings; 46 import android.util.ArraySet; 47 import android.util.Slog; 48 import android.view.IWindowManager; 49 50 import com.android.internal.os.BackgroundThread; 51 import com.android.internal.util.ArrayUtils; 52 import com.android.server.LocalServices; 53 import com.android.server.pm.UserManagerInternal; 54 import com.android.server.utils.Slogf; 55 56 import java.util.Collections; 57 import java.util.List; 58 import java.util.Objects; 59 import java.util.Set; 60 import java.util.concurrent.CountDownLatch; 61 import java.util.concurrent.TimeUnit; 62 import java.util.concurrent.atomic.AtomicReference; 63 64 final class PolicyEnforcerCallbacks { 65 66 private static final String LOG_TAG = "PolicyEnforcerCallbacks"; 67 setAutoTimezoneEnabled(@ullable Boolean enabled, @NonNull Context context)68 static boolean setAutoTimezoneEnabled(@Nullable Boolean enabled, @NonNull Context context) { 69 return Binder.withCleanCallingIdentity(() -> { 70 Objects.requireNonNull(context); 71 72 int value = enabled != null && enabled ? 1 : 0; 73 return Settings.Global.putInt( 74 context.getContentResolver(), Settings.Global.AUTO_TIME_ZONE, 75 value); 76 }); 77 } 78 setPermissionGrantState( @ullable Integer grantState, @NonNull Context context, int userId, @NonNull PolicyKey policyKey)79 static boolean setPermissionGrantState( 80 @Nullable Integer grantState, @NonNull Context context, int userId, 81 @NonNull PolicyKey policyKey) { 82 return Boolean.TRUE.equals(Binder.withCleanCallingIdentity(() -> { 83 if (!(policyKey instanceof PackagePermissionPolicyKey)) { 84 throw new IllegalArgumentException("policyKey is not of type " 85 + "PermissionGrantStatePolicyKey, passed in policyKey is: " + policyKey); 86 } 87 PackagePermissionPolicyKey parsedKey = (PackagePermissionPolicyKey) policyKey; 88 Objects.requireNonNull(parsedKey.getPermissionName()); 89 Objects.requireNonNull(parsedKey.getPackageName()); 90 Objects.requireNonNull(context); 91 92 int value = grantState == null 93 ? DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT 94 : grantState; 95 96 // TODO(b/278710449): stop blocking in the main thread 97 BlockingCallback callback = new BlockingCallback(); 98 // TODO: remove canAdminGrantSensorPermissions once we expose a new method in 99 // permissionController that doesn't need it. 100 AdminPermissionControlParams permissionParams = new AdminPermissionControlParams( 101 parsedKey.getPackageName(), parsedKey.getPermissionName(), value, 102 /* canAdminGrantSensorPermissions= */ true); 103 getPermissionControllerManager(context, UserHandle.of(userId)) 104 // TODO: remove callingPackage param and stop passing context.getPackageName() 105 .setRuntimePermissionGrantStateByDeviceAdmin(context.getPackageName(), 106 permissionParams, context.getMainExecutor(), callback::trigger); 107 try { 108 return callback.await(20_000, TimeUnit.MILLISECONDS); 109 } catch (Exception e) { 110 // TODO: add logging 111 return false; 112 } 113 })); 114 } 115 116 @NonNull 117 private static PermissionControllerManager getPermissionControllerManager( 118 Context context, UserHandle user) { 119 if (user.equals(context.getUser())) { 120 return context.getSystemService(PermissionControllerManager.class); 121 } else { 122 try { 123 return context.createPackageContextAsUser(context.getPackageName(), /* flags= */ 0, 124 user).getSystemService(PermissionControllerManager.class); 125 } catch (PackageManager.NameNotFoundException notPossible) { 126 // not possible 127 throw new IllegalStateException(notPossible); 128 } 129 } 130 } 131 132 static boolean setLockTask( 133 @Nullable LockTaskPolicy policy, @NonNull Context context, int userId) { 134 List<String> packages = Collections.emptyList(); 135 int flags = LockTaskPolicy.DEFAULT_LOCK_TASK_FLAG; 136 if (policy != null) { 137 packages = List.copyOf(policy.getPackages()); 138 flags = policy.getFlags(); 139 } 140 DevicePolicyManagerService.updateLockTaskPackagesLocked(context, packages, userId); 141 DevicePolicyManagerService.updateLockTaskFeaturesLocked(flags, userId); 142 return true; 143 } 144 145 private static class BlockingCallback { 146 private final CountDownLatch mLatch = new CountDownLatch(1); 147 private final AtomicReference<Boolean> mValue = new AtomicReference<>(); 148 public void trigger(Boolean value) { 149 mValue.set(value); 150 mLatch.countDown(); 151 } 152 153 public Boolean await(long timeout, TimeUnit unit) throws InterruptedException { 154 if (!mLatch.await(timeout, unit)) { 155 Slogf.e(LOG_TAG, "Callback was not received"); 156 } 157 return mValue.get(); 158 } 159 } 160 161 static boolean setUserControlDisabledPackages( 162 @Nullable Set<String> packages, int userId) { 163 Binder.withCleanCallingIdentity(() -> { 164 LocalServices.getService(PackageManagerInternal.class) 165 .setOwnerProtectedPackages( 166 userId, 167 packages == null ? null : packages.stream().toList()); 168 LocalServices.getService(UsageStatsManagerInternal.class) 169 .setAdminProtectedPackages( 170 packages == null ? null : new ArraySet<>(packages), userId); 171 }); 172 return true; 173 } 174 175 static boolean addPersistentPreferredActivity( 176 @Nullable ComponentName preferredActivity, @NonNull Context context, int userId, 177 @NonNull PolicyKey policyKey) { 178 Binder.withCleanCallingIdentity(() -> { 179 try { 180 if (!(policyKey instanceof IntentFilterPolicyKey)) { 181 throw new IllegalArgumentException("policyKey is not of type " 182 + "IntentFilterPolicyKey, passed in policyKey is: " + policyKey); 183 } 184 IntentFilterPolicyKey parsedKey = 185 (IntentFilterPolicyKey) policyKey; 186 IntentFilter filter = Objects.requireNonNull(parsedKey.getIntentFilter()); 187 188 IPackageManager packageManager = AppGlobals.getPackageManager(); 189 if (preferredActivity != null) { 190 packageManager.addPersistentPreferredActivity( 191 filter, preferredActivity, userId); 192 } else { 193 packageManager.clearPersistentPreferredActivity(filter, userId); 194 } 195 packageManager.flushPackageRestrictionsAsUser(userId); 196 } catch (RemoteException re) { 197 // Shouldn't happen 198 Slog.wtf(LOG_TAG, "Error adding/removing persistent preferred activity", re); 199 } 200 }); 201 return true; 202 } 203 204 static boolean setUninstallBlocked( 205 @Nullable Boolean uninstallBlocked, @NonNull Context context, int userId, 206 @NonNull PolicyKey policyKey) { 207 return Boolean.TRUE.equals(Binder.withCleanCallingIdentity(() -> { 208 if (!(policyKey instanceof PackagePolicyKey)) { 209 throw new IllegalArgumentException("policyKey is not of type " 210 + "PackagePolicyKey, passed in policyKey is: " + policyKey); 211 } 212 PackagePolicyKey parsedKey = (PackagePolicyKey) policyKey; 213 String packageName = Objects.requireNonNull(parsedKey.getPackageName()); 214 DevicePolicyManagerService.setUninstallBlockedUnchecked( 215 packageName, 216 uninstallBlocked != null && uninstallBlocked, 217 userId); 218 return true; 219 })); 220 } 221 222 static boolean setUserRestriction( 223 @Nullable Boolean enabled, @NonNull Context context, int userId, 224 @NonNull PolicyKey policyKey) { 225 return Boolean.TRUE.equals(Binder.withCleanCallingIdentity(() -> { 226 if (!(policyKey instanceof UserRestrictionPolicyKey)) { 227 throw new IllegalArgumentException("policyKey is not of type " 228 + "UserRestrictionPolicyKey, passed in policyKey is: " + policyKey); 229 } 230 UserRestrictionPolicyKey parsedKey = 231 (UserRestrictionPolicyKey) policyKey; 232 UserManagerInternal userManager = LocalServices.getService(UserManagerInternal.class); 233 userManager.setUserRestriction( 234 userId, parsedKey.getRestriction(), enabled != null && enabled); 235 return true; 236 })); 237 } 238 239 static boolean setApplicationHidden( 240 @Nullable Boolean hide, @NonNull Context context, int userId, 241 @NonNull PolicyKey policyKey) { 242 return Boolean.TRUE.equals(Binder.withCleanCallingIdentity(() -> { 243 if (!(policyKey instanceof PackagePolicyKey)) { 244 throw new IllegalArgumentException("policyKey is not of type " 245 + "PackagePolicyKey, passed in policyKey is: " + policyKey); 246 } 247 PackagePolicyKey parsedKey = (PackagePolicyKey) policyKey; 248 String packageName = Objects.requireNonNull(parsedKey.getPackageName()); 249 IPackageManager packageManager = AppGlobals.getPackageManager(); 250 return packageManager.setApplicationHiddenSettingAsUser( 251 packageName, hide != null && hide, userId); 252 })); 253 } 254 255 static boolean setScreenCaptureDisabled( 256 @Nullable Boolean disabled, @NonNull Context context, int userId, 257 @NonNull PolicyKey policyKey) { 258 Binder.withCleanCallingIdentity(() -> { 259 DevicePolicyCache cache = DevicePolicyCache.getInstance(); 260 if (cache instanceof DevicePolicyCacheImpl) { 261 DevicePolicyCacheImpl parsedCache = (DevicePolicyCacheImpl) cache; 262 parsedCache.setScreenCaptureDisallowedUser( 263 userId, disabled != null && disabled); 264 updateScreenCaptureDisabled(); 265 } 266 }); 267 return true; 268 } 269 270 private static void updateScreenCaptureDisabled() { 271 BackgroundThread.getHandler().post(() -> { 272 try { 273 IWindowManager.Stub 274 .asInterface(ServiceManager.getService(Context.WINDOW_SERVICE)) 275 .refreshScreenCaptureDisabled(); 276 } catch (RemoteException e) { 277 Slogf.w(LOG_TAG, "Unable to notify WindowManager.", e); 278 } 279 }); 280 } 281 282 static boolean setPersonalAppsSuspended( 283 @Nullable Boolean suspended, @NonNull Context context, int userId, 284 @NonNull PolicyKey policyKey) { 285 Binder.withCleanCallingIdentity(() -> { 286 if (suspended != null && suspended) { 287 suspendPersonalAppsInPackageManager(context, userId); 288 } else { 289 LocalServices.getService(PackageManagerInternal.class) 290 .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, userId); 291 } 292 }); 293 return true; 294 } 295 296 private static void suspendPersonalAppsInPackageManager(Context context, int userId) { 297 final String[] appsToSuspend = PersonalAppsSuspensionHelper.forUser(context, userId) 298 .getPersonalAppsForSuspension(); 299 final String[] failedApps = LocalServices.getService(PackageManagerInternal.class) 300 .setPackagesSuspendedByAdmin(userId, appsToSuspend, true); 301 if (!ArrayUtils.isEmpty(failedApps)) { 302 Slogf.wtf(LOG_TAG, "Failed to suspend apps: " + String.join(",", failedApps)); 303 } 304 } 305 } 306