1 /* 2 * Copyright (C) 2018 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.role; 18 19 import android.Manifest; 20 import android.annotation.AnyThread; 21 import android.annotation.MainThread; 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.annotation.UserIdInt; 25 import android.annotation.WorkerThread; 26 import android.app.AppOpsManager; 27 import android.app.role.IOnRoleHoldersChangedListener; 28 import android.app.role.IRoleManager; 29 import android.app.role.RoleControllerManager; 30 import android.app.role.RoleManager; 31 import android.content.BroadcastReceiver; 32 import android.content.Context; 33 import android.content.Intent; 34 import android.content.IntentFilter; 35 import android.content.pm.PackageManager; 36 import android.os.Binder; 37 import android.os.Build; 38 import android.os.Handler; 39 import android.os.ParcelFileDescriptor; 40 import android.os.Process; 41 import android.os.RemoteCallback; 42 import android.os.RemoteCallbackList; 43 import android.os.RemoteException; 44 import android.os.UserHandle; 45 import android.os.UserManager; 46 import android.text.TextUtils; 47 import android.util.ArraySet; 48 import android.util.IndentingPrintWriter; 49 import android.util.Log; 50 import android.util.SparseArray; 51 import android.util.proto.ProtoOutputStream; 52 53 import androidx.annotation.RequiresApi; 54 55 import com.android.internal.annotations.GuardedBy; 56 import com.android.internal.infra.AndroidFuture; 57 import com.android.internal.util.Preconditions; 58 import com.android.internal.util.dump.DualDumpOutputStream; 59 import com.android.permission.compat.UserHandleCompat; 60 import com.android.permission.util.ArrayUtils; 61 import com.android.permission.util.CollectionUtils; 62 import com.android.permission.util.ForegroundThread; 63 import com.android.permission.util.ThrottledRunnable; 64 import com.android.server.LocalManagerRegistry; 65 import com.android.server.SystemService; 66 import com.android.server.role.RoleServicePlatformHelper; 67 68 import java.io.FileDescriptor; 69 import java.io.FileOutputStream; 70 import java.io.PrintWriter; 71 import java.util.ArrayList; 72 import java.util.Collections; 73 import java.util.List; 74 import java.util.Map; 75 import java.util.Objects; 76 import java.util.Set; 77 import java.util.concurrent.ExecutionException; 78 import java.util.concurrent.TimeUnit; 79 import java.util.concurrent.TimeoutException; 80 81 /** 82 * Service for role management. 83 * 84 * @see RoleManager 85 */ 86 @RequiresApi(Build.VERSION_CODES.S) 87 public class RoleService extends SystemService implements RoleUserState.Callback { 88 private static final String LOG_TAG = RoleService.class.getSimpleName(); 89 90 private static final boolean DEBUG = false; 91 92 private static final long GRANT_DEFAULT_ROLES_INTERVAL_MILLIS = 1000; 93 94 @NonNull 95 private final AppOpsManager mAppOpsManager; 96 @NonNull 97 private final UserManager mUserManager; 98 99 @NonNull 100 private final Object mLock = new Object(); 101 102 @NonNull 103 private final RoleServicePlatformHelper mPlatformHelper; 104 105 /** 106 * Maps user id to its state. 107 */ 108 @GuardedBy("mLock") 109 @NonNull 110 private final SparseArray<RoleUserState> mUserStates = new SparseArray<>(); 111 112 /** 113 * Maps user id to its controller. 114 */ 115 @GuardedBy("mLock") 116 @NonNull 117 private final SparseArray<RoleControllerManager> mControllers = new SparseArray<>(); 118 119 /** 120 * Maps user id to its list of listeners. 121 */ 122 @GuardedBy("mLock") 123 @NonNull 124 private final SparseArray<RemoteCallbackList<IOnRoleHoldersChangedListener>> mListeners = 125 new SparseArray<>(); 126 127 @NonNull 128 private final Handler mListenerHandler = ForegroundThread.getHandler(); 129 130 @GuardedBy("mLock") 131 private boolean mBypassingRoleQualification; 132 133 /** 134 * Maps user id to its throttled runnable for granting default roles. 135 */ 136 @GuardedBy("mLock") 137 @NonNull 138 private final SparseArray<ThrottledRunnable> mGrantDefaultRolesThrottledRunnables = 139 new SparseArray<>(); 140 RoleService(@onNull Context context)141 public RoleService(@NonNull Context context) { 142 super(context); 143 144 mPlatformHelper = LocalManagerRegistry.getManager(RoleServicePlatformHelper.class); 145 146 RoleControllerManager.initializeRemoteServiceComponentName(context); 147 148 mAppOpsManager = context.getSystemService(AppOpsManager.class); 149 mUserManager = context.getSystemService(UserManager.class); 150 151 LocalManagerRegistry.addManager(RoleManagerLocal.class, new Local()); 152 153 registerUserRemovedReceiver(); 154 } 155 registerUserRemovedReceiver()156 private void registerUserRemovedReceiver() { 157 IntentFilter intentFilter = new IntentFilter(); 158 intentFilter.addAction(Intent.ACTION_USER_REMOVED); 159 getContext().registerReceiverForAllUsers(new BroadcastReceiver() { 160 @Override 161 public void onReceive(@NonNull Context context, @NonNull Intent intent) { 162 if (TextUtils.equals(intent.getAction(), Intent.ACTION_USER_REMOVED)) { 163 int userId = intent.<UserHandle>getParcelableExtra(Intent.EXTRA_USER) 164 .getIdentifier(); 165 onRemoveUser(userId); 166 } 167 } 168 }, intentFilter, null, null); 169 } 170 171 @Override onStart()172 public void onStart() { 173 publishBinderService(Context.ROLE_SERVICE, new Stub()); 174 175 IntentFilter intentFilter = new IntentFilter(); 176 intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 177 intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 178 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 179 intentFilter.addDataScheme("package"); 180 intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); 181 getContext().registerReceiverForAllUsers(new BroadcastReceiver() { 182 @Override 183 public void onReceive(Context context, Intent intent) { 184 int userId = UserHandleCompat.getUserId(intent.getIntExtra(Intent.EXTRA_UID, -1)); 185 if (DEBUG) { 186 Log.i(LOG_TAG, "Packages changed - re-running initial grants for user " 187 + userId); 188 } 189 if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction()) 190 && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 191 // Package is being upgraded - we're about to get ACTION_PACKAGE_ADDED 192 return; 193 } 194 maybeGrantDefaultRolesAsync(userId); 195 } 196 }, intentFilter, null, null); 197 } 198 199 @Override onUserStarting(@onNull TargetUser user)200 public void onUserStarting(@NonNull TargetUser user) { 201 maybeGrantDefaultRolesSync(user.getUserHandle().getIdentifier()); 202 } 203 204 @MainThread maybeGrantDefaultRolesSync(@serIdInt int userId)205 private void maybeGrantDefaultRolesSync(@UserIdInt int userId) { 206 AndroidFuture<Void> future = maybeGrantDefaultRolesInternal(userId); 207 try { 208 future.get(30, TimeUnit.SECONDS); 209 } catch (InterruptedException | ExecutionException | TimeoutException e) { 210 Log.e(LOG_TAG, "Failed to grant default roles for user " + userId, e); 211 } 212 } 213 maybeGrantDefaultRolesAsync(@serIdInt int userId)214 private void maybeGrantDefaultRolesAsync(@UserIdInt int userId) { 215 ThrottledRunnable runnable; 216 synchronized (mLock) { 217 runnable = mGrantDefaultRolesThrottledRunnables.get(userId); 218 if (runnable == null) { 219 runnable = new ThrottledRunnable(ForegroundThread.getHandler(), 220 GRANT_DEFAULT_ROLES_INTERVAL_MILLIS, 221 () -> maybeGrantDefaultRolesInternal(userId)); 222 mGrantDefaultRolesThrottledRunnables.put(userId, runnable); 223 } 224 } 225 runnable.run(); 226 } 227 228 @AnyThread 229 @NonNull maybeGrantDefaultRolesInternal(@serIdInt int userId)230 private AndroidFuture<Void> maybeGrantDefaultRolesInternal(@UserIdInt int userId) { 231 RoleUserState userState = getOrCreateUserState(userId); 232 String oldPackagesHash = userState.getPackagesHash(); 233 String newPackagesHash = mPlatformHelper.computePackageStateHash(userId); 234 if (Objects.equals(oldPackagesHash, newPackagesHash)) { 235 if (DEBUG) { 236 Log.i(LOG_TAG, "Already granted default roles for packages hash " 237 + newPackagesHash); 238 } 239 return AndroidFuture.completedFuture(null); 240 } 241 242 // Some package state has changed, so grant default roles again. 243 Log.i(LOG_TAG, "Granting default roles..."); 244 AndroidFuture<Void> future = new AndroidFuture<>(); 245 getOrCreateController(userId).grantDefaultRoles(ForegroundThread.getExecutor(), 246 successful -> { 247 if (successful) { 248 userState.setPackagesHash(newPackagesHash); 249 future.complete(null); 250 } else { 251 future.completeExceptionally(new RuntimeException()); 252 } 253 }); 254 return future; 255 } 256 257 @NonNull getOrCreateUserState(@serIdInt int userId)258 private RoleUserState getOrCreateUserState(@UserIdInt int userId) { 259 synchronized (mLock) { 260 RoleUserState userState = mUserStates.get(userId); 261 if (userState == null) { 262 userState = new RoleUserState(userId, mPlatformHelper, this); 263 mUserStates.put(userId, userState); 264 } 265 return userState; 266 } 267 } 268 269 @NonNull getOrCreateController(@serIdInt int userId)270 private RoleControllerManager getOrCreateController(@UserIdInt int userId) { 271 synchronized (mLock) { 272 RoleControllerManager controller = mControllers.get(userId); 273 if (controller == null) { 274 Context systemContext = getContext(); 275 Context context; 276 try { 277 context = systemContext.createPackageContextAsUser( 278 systemContext.getPackageName(), 0, UserHandle.of(userId)); 279 } catch (PackageManager.NameNotFoundException e) { 280 throw new RuntimeException(e); 281 } 282 controller = RoleControllerManager.createWithInitializedRemoteServiceComponentName( 283 ForegroundThread.getHandler(), context); 284 mControllers.put(userId, controller); 285 } 286 return controller; 287 } 288 } 289 290 @Nullable getListeners(@serIdInt int userId)291 private RemoteCallbackList<IOnRoleHoldersChangedListener> getListeners(@UserIdInt int userId) { 292 synchronized (mLock) { 293 return mListeners.get(userId); 294 } 295 } 296 297 @NonNull getOrCreateListeners( @serIdInt int userId)298 private RemoteCallbackList<IOnRoleHoldersChangedListener> getOrCreateListeners( 299 @UserIdInt int userId) { 300 synchronized (mLock) { 301 RemoteCallbackList<IOnRoleHoldersChangedListener> listeners = mListeners.get(userId); 302 if (listeners == null) { 303 listeners = new RemoteCallbackList<>(); 304 mListeners.put(userId, listeners); 305 } 306 return listeners; 307 } 308 } 309 onRemoveUser(@serIdInt int userId)310 private void onRemoveUser(@UserIdInt int userId) { 311 RemoteCallbackList<IOnRoleHoldersChangedListener> listeners; 312 RoleUserState userState; 313 synchronized (mLock) { 314 mGrantDefaultRolesThrottledRunnables.remove(userId); 315 listeners = mListeners.get(userId); 316 mListeners.remove(userId); 317 mControllers.remove(userId); 318 userState = mUserStates.get(userId); 319 mUserStates.remove(userId); 320 } 321 if (listeners != null) { 322 listeners.kill(); 323 } 324 if (userState != null) { 325 userState.destroy(); 326 } 327 } 328 329 @Override onRoleHoldersChanged(@onNull String roleName, @UserIdInt int userId)330 public void onRoleHoldersChanged(@NonNull String roleName, @UserIdInt int userId) { 331 mListenerHandler.post(() -> notifyRoleHoldersChanged(roleName, userId)); 332 } 333 334 @WorkerThread notifyRoleHoldersChanged(@onNull String roleName, @UserIdInt int userId)335 private void notifyRoleHoldersChanged(@NonNull String roleName, @UserIdInt int userId) { 336 RemoteCallbackList<IOnRoleHoldersChangedListener> listeners = getListeners(userId); 337 if (listeners != null) { 338 notifyRoleHoldersChangedForListeners(listeners, roleName, userId); 339 } 340 341 RemoteCallbackList<IOnRoleHoldersChangedListener> allUsersListeners = getListeners( 342 UserHandleCompat.USER_ALL); 343 if (allUsersListeners != null) { 344 notifyRoleHoldersChangedForListeners(allUsersListeners, roleName, userId); 345 } 346 } 347 348 @WorkerThread notifyRoleHoldersChangedForListeners( @onNull RemoteCallbackList<IOnRoleHoldersChangedListener> listeners, @NonNull String roleName, @UserIdInt int userId)349 private void notifyRoleHoldersChangedForListeners( 350 @NonNull RemoteCallbackList<IOnRoleHoldersChangedListener> listeners, 351 @NonNull String roleName, @UserIdInt int userId) { 352 int broadcastCount = listeners.beginBroadcast(); 353 try { 354 for (int i = 0; i < broadcastCount; i++) { 355 IOnRoleHoldersChangedListener listener = listeners.getBroadcastItem(i); 356 try { 357 listener.onRoleHoldersChanged(roleName, userId); 358 } catch (RemoteException e) { 359 Log.e(LOG_TAG, "Error calling OnRoleHoldersChangedListener", e); 360 } 361 } 362 } finally { 363 listeners.finishBroadcast(); 364 } 365 } 366 367 private class Stub extends IRoleManager.Stub { 368 369 @Override isRoleAvailable(@onNull String roleName)370 public boolean isRoleAvailable(@NonNull String roleName) { 371 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); 372 373 int userId = UserHandleCompat.getUserId(getCallingUid()); 374 return getOrCreateUserState(userId).isRoleAvailable(roleName); 375 } 376 377 @Override isRoleHeld(@onNull String roleName, @NonNull String packageName)378 public boolean isRoleHeld(@NonNull String roleName, @NonNull String packageName) { 379 int callingUid = getCallingUid(); 380 mAppOpsManager.checkPackage(callingUid, packageName); 381 382 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); 383 Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty"); 384 385 int userId = UserHandleCompat.getUserId(callingUid); 386 ArraySet<String> roleHolders = getOrCreateUserState(userId).getRoleHolders(roleName); 387 if (roleHolders == null) { 388 return false; 389 } 390 return roleHolders.contains(packageName); 391 } 392 393 @NonNull 394 @Override getRoleHoldersAsUser(@onNull String roleName, @UserIdInt int userId)395 public List<String> getRoleHoldersAsUser(@NonNull String roleName, @UserIdInt int userId) { 396 enforceCrossUserPermission(userId, false, "getRoleHoldersAsUser"); 397 if (!isUserExistent(userId)) { 398 Log.e(LOG_TAG, "user " + userId + " does not exist"); 399 return Collections.emptyList(); 400 } 401 402 getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, 403 "getRoleHoldersAsUser"); 404 405 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); 406 407 ArraySet<String> roleHolders = getOrCreateUserState(userId).getRoleHolders(roleName); 408 if (roleHolders == null) { 409 return Collections.emptyList(); 410 } 411 return new ArrayList<>(roleHolders); 412 } 413 414 @Override addRoleHolderAsUser(@onNull String roleName, @NonNull String packageName, @RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId, @NonNull RemoteCallback callback)415 public void addRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName, 416 @RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId, 417 @NonNull RemoteCallback callback) { 418 enforceCrossUserPermission(userId, false, "addRoleHolderAsUser"); 419 if (!isUserExistent(userId)) { 420 Log.e(LOG_TAG, "user " + userId + " does not exist"); 421 return; 422 } 423 424 getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, 425 "addRoleHolderAsUser"); 426 427 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); 428 Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty"); 429 Objects.requireNonNull(callback, "callback cannot be null"); 430 431 getOrCreateController(userId).onAddRoleHolder(roleName, packageName, flags, 432 callback); 433 } 434 435 @Override removeRoleHolderAsUser(@onNull String roleName, @NonNull String packageName, @RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId, @NonNull RemoteCallback callback)436 public void removeRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName, 437 @RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId, 438 @NonNull RemoteCallback callback) { 439 enforceCrossUserPermission(userId, false, "removeRoleHolderAsUser"); 440 if (!isUserExistent(userId)) { 441 Log.e(LOG_TAG, "user " + userId + " does not exist"); 442 return; 443 } 444 445 getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, 446 "removeRoleHolderAsUser"); 447 448 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); 449 Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty"); 450 Objects.requireNonNull(callback, "callback cannot be null"); 451 452 getOrCreateController(userId).onRemoveRoleHolder(roleName, packageName, flags, 453 callback); 454 } 455 456 @Override clearRoleHoldersAsUser(@onNull String roleName, @RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId, @NonNull RemoteCallback callback)457 public void clearRoleHoldersAsUser(@NonNull String roleName, 458 @RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId, 459 @NonNull RemoteCallback callback) { 460 enforceCrossUserPermission(userId, false, "clearRoleHoldersAsUser"); 461 if (!isUserExistent(userId)) { 462 Log.e(LOG_TAG, "user " + userId + " does not exist"); 463 return; 464 } 465 466 getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, 467 "clearRoleHoldersAsUser"); 468 469 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); 470 Objects.requireNonNull(callback, "callback cannot be null"); 471 472 getOrCreateController(userId).onClearRoleHolders(roleName, flags, callback); 473 } 474 475 @Override addOnRoleHoldersChangedListenerAsUser( @onNull IOnRoleHoldersChangedListener listener, @UserIdInt int userId)476 public void addOnRoleHoldersChangedListenerAsUser( 477 @NonNull IOnRoleHoldersChangedListener listener, @UserIdInt int userId) { 478 enforceCrossUserPermission(userId, true, "addOnRoleHoldersChangedListenerAsUser"); 479 if (userId != UserHandleCompat.USER_ALL && !isUserExistent(userId)) { 480 Log.e(LOG_TAG, "user " + userId + " does not exist"); 481 return; 482 } 483 484 getContext().enforceCallingOrSelfPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS, 485 "addOnRoleHoldersChangedListenerAsUser"); 486 487 Objects.requireNonNull(listener, "listener cannot be null"); 488 489 RemoteCallbackList<IOnRoleHoldersChangedListener> listeners = getOrCreateListeners( 490 userId); 491 listeners.register(listener); 492 } 493 494 @Override removeOnRoleHoldersChangedListenerAsUser( @onNull IOnRoleHoldersChangedListener listener, @UserIdInt int userId)495 public void removeOnRoleHoldersChangedListenerAsUser( 496 @NonNull IOnRoleHoldersChangedListener listener, @UserIdInt int userId) { 497 enforceCrossUserPermission(userId, true, "removeOnRoleHoldersChangedListenerAsUser"); 498 if (userId != UserHandleCompat.USER_ALL && !isUserExistent(userId)) { 499 Log.e(LOG_TAG, "user " + userId + " does not exist"); 500 return; 501 } 502 503 getContext().enforceCallingOrSelfPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS, 504 "removeOnRoleHoldersChangedListenerAsUser"); 505 506 Objects.requireNonNull(listener, "listener cannot be null"); 507 508 RemoteCallbackList<IOnRoleHoldersChangedListener> listeners = getListeners(userId); 509 if (listener == null) { 510 return; 511 } 512 listeners.unregister(listener); 513 } 514 515 @Override isBypassingRoleQualification()516 public boolean isBypassingRoleQualification() { 517 getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, 518 "isBypassingRoleQualification"); 519 synchronized (mLock) { 520 return mBypassingRoleQualification; 521 } 522 } 523 524 @Override setBypassingRoleQualification(boolean bypassRoleQualification)525 public void setBypassingRoleQualification(boolean bypassRoleQualification) { 526 getContext().enforceCallingOrSelfPermission( 527 Manifest.permission.BYPASS_ROLE_QUALIFICATION, "setBypassingRoleQualification"); 528 synchronized (mLock) { 529 mBypassingRoleQualification = bypassRoleQualification; 530 } 531 } 532 533 @Override setRoleNamesFromController(@onNull List<String> roleNames)534 public void setRoleNamesFromController(@NonNull List<String> roleNames) { 535 getContext().enforceCallingOrSelfPermission( 536 RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER, 537 "setRoleNamesFromController"); 538 539 Objects.requireNonNull(roleNames, "roleNames cannot be null"); 540 541 int userId = UserHandleCompat.getUserId(Binder.getCallingUid()); 542 getOrCreateUserState(userId).setRoleNames(roleNames); 543 } 544 545 @Override addRoleHolderFromController(@onNull String roleName, @NonNull String packageName)546 public boolean addRoleHolderFromController(@NonNull String roleName, 547 @NonNull String packageName) { 548 getContext().enforceCallingOrSelfPermission( 549 RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER, 550 "addRoleHolderFromController"); 551 552 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); 553 Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty"); 554 555 int userId = UserHandleCompat.getUserId(Binder.getCallingUid()); 556 return getOrCreateUserState(userId).addRoleHolder(roleName, packageName); 557 } 558 559 @Override removeRoleHolderFromController(@onNull String roleName, @NonNull String packageName)560 public boolean removeRoleHolderFromController(@NonNull String roleName, 561 @NonNull String packageName) { 562 getContext().enforceCallingOrSelfPermission( 563 RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER, 564 "removeRoleHolderFromController"); 565 566 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); 567 Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty"); 568 569 int userId = UserHandleCompat.getUserId(Binder.getCallingUid()); 570 return getOrCreateUserState(userId).removeRoleHolder(roleName, packageName); 571 } 572 573 @Override getHeldRolesFromController(@onNull String packageName)574 public List<String> getHeldRolesFromController(@NonNull String packageName) { 575 getContext().enforceCallingOrSelfPermission( 576 RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER, 577 "getRolesHeldFromController"); 578 579 Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty"); 580 581 int userId = UserHandleCompat.getUserId(Binder.getCallingUid()); 582 return getOrCreateUserState(userId).getHeldRoles(packageName); 583 } 584 isUserExistent(@serIdInt int userId)585 private boolean isUserExistent(@UserIdInt int userId) { 586 final long identity = Binder.clearCallingIdentity(); 587 try { 588 return mUserManager.getUserHandles(true).contains(UserHandle.of(userId)); 589 } finally { 590 Binder.restoreCallingIdentity(identity); 591 } 592 } 593 enforceCrossUserPermission(@serIdInt int userId, boolean allowAll, @NonNull String message)594 private void enforceCrossUserPermission(@UserIdInt int userId, boolean allowAll, 595 @NonNull String message) { 596 final int callingUid = Binder.getCallingUid(); 597 final int callingUserId = UserHandleCompat.getUserId(callingUid); 598 if (userId == callingUserId) { 599 return; 600 } 601 Preconditions.checkArgument(userId >= UserHandleCompat.USER_SYSTEM 602 || (allowAll && userId == UserHandleCompat.USER_ALL), "Invalid user " + userId); 603 getContext().enforceCallingOrSelfPermission( 604 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message); 605 if (callingUid == Process.SHELL_UID && userId >= UserHandleCompat.USER_SYSTEM) { 606 if (mUserManager.hasUserRestrictionForUser(UserManager.DISALLOW_DEBUGGING_FEATURES, 607 UserHandle.of(userId))) { 608 throw new SecurityException("Shell does not have permission to access user " 609 + userId); 610 } 611 } 612 } 613 614 @Override handleShellCommand(@onNull ParcelFileDescriptor in, @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, @NonNull String[] args)615 public int handleShellCommand(@NonNull ParcelFileDescriptor in, 616 @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, 617 @NonNull String[] args) { 618 return new RoleShellCommand(this).exec(this, in.getFileDescriptor(), 619 out.getFileDescriptor(), err.getFileDescriptor(), args); 620 } 621 622 @Nullable 623 @Override getBrowserRoleHolder(@serIdInt int userId)624 public String getBrowserRoleHolder(@UserIdInt int userId) { 625 final int callingUid = Binder.getCallingUid(); 626 if (UserHandleCompat.getUserId(callingUid) != userId) { 627 getContext().enforceCallingOrSelfPermission( 628 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null); 629 } 630 if (isInstantApp(callingUid)) { 631 return null; 632 } 633 634 final long identity = Binder.clearCallingIdentity(); 635 try { 636 return CollectionUtils.firstOrNull(getRoleHoldersAsUser(RoleManager.ROLE_BROWSER, 637 userId)); 638 } finally { 639 Binder.restoreCallingIdentity(identity); 640 } 641 } 642 isInstantApp(int uid)643 private boolean isInstantApp(int uid) { 644 final long identity = Binder.clearCallingIdentity(); 645 try { 646 final UserHandle user = UserHandle.getUserHandleForUid(uid); 647 final Context userContext = getContext().createContextAsUser(user, 0); 648 final PackageManager userPackageManager = userContext.getPackageManager(); 649 // Instant apps can not have shared UID, so it's safe to check only the first 650 // package name here. 651 final String packageName = ArrayUtils.firstOrNull( 652 userPackageManager.getPackagesForUid(uid)); 653 if (packageName == null) { 654 return false; 655 } 656 return userPackageManager.isInstantApp(packageName); 657 } finally { 658 Binder.restoreCallingIdentity(identity); 659 } 660 } 661 662 @Override setBrowserRoleHolder(@ullable String packageName, @UserIdInt int userId)663 public boolean setBrowserRoleHolder(@Nullable String packageName, @UserIdInt int userId) { 664 final Context context = getContext(); 665 context.enforceCallingOrSelfPermission( 666 android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null); 667 if (UserHandleCompat.getUserId(Binder.getCallingUid()) != userId) { 668 context.enforceCallingOrSelfPermission( 669 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null); 670 } 671 672 if (!isUserExistent(userId)) { 673 return false; 674 } 675 676 final AndroidFuture<Void> future = new AndroidFuture<>(); 677 final RemoteCallback callback = new RemoteCallback(result -> { 678 boolean successful = result != null; 679 if (successful) { 680 future.complete(null); 681 } else { 682 future.completeExceptionally(new RuntimeException()); 683 } 684 }); 685 final long identity = Binder.clearCallingIdentity(); 686 try { 687 if (packageName != null) { 688 addRoleHolderAsUser(RoleManager.ROLE_BROWSER, packageName, 0, userId, callback); 689 } else { 690 clearRoleHoldersAsUser(RoleManager.ROLE_BROWSER, 0, userId, callback); 691 } 692 try { 693 future.get(5, TimeUnit.SECONDS); 694 } catch (InterruptedException | ExecutionException | TimeoutException e) { 695 Log.e(LOG_TAG, "Exception while setting default browser: " + packageName, e); 696 return false; 697 } 698 } finally { 699 Binder.restoreCallingIdentity(identity); 700 } 701 702 return true; 703 } 704 705 @Override getSmsRoleHolder(int userId)706 public String getSmsRoleHolder(int userId) { 707 enforceCrossUserPermission(userId, false, "getSmsRoleHolder"); 708 if (!isUserExistent(userId)) { 709 Log.e(LOG_TAG, "user " + userId + " does not exist"); 710 return null; 711 } 712 713 final long identity = Binder.clearCallingIdentity(); 714 try { 715 return CollectionUtils.firstOrNull(getRoleHoldersAsUser(RoleManager.ROLE_SMS, 716 userId)); 717 } finally { 718 Binder.restoreCallingIdentity(identity); 719 } 720 } 721 722 @Override dump(@onNull FileDescriptor fd, @NonNull PrintWriter fout, @Nullable String[] args)723 protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout, 724 @Nullable String[] args) { 725 if (!checkDumpPermission("role", fout)) { 726 return; 727 } 728 729 boolean dumpAsProto = args != null && ArrayUtils.contains(args, "--proto"); 730 DualDumpOutputStream dumpOutputStream; 731 if (dumpAsProto) { 732 dumpOutputStream = new DualDumpOutputStream(new ProtoOutputStream( 733 new FileOutputStream(fd))); 734 } else { 735 fout.println("ROLE STATE (dumpsys role):"); 736 dumpOutputStream = new DualDumpOutputStream(new IndentingPrintWriter(fout, " ")); 737 } 738 739 synchronized (mLock) { 740 final int userStatesSize = mUserStates.size(); 741 for (int i = 0; i < userStatesSize; i++) { 742 final RoleUserState userState = mUserStates.valueAt(i); 743 744 userState.dump(dumpOutputStream, "user_states", 745 RoleServiceDumpProto.USER_STATES); 746 } 747 } 748 749 dumpOutputStream.flush(); 750 } 751 checkDumpPermission(@onNull String serviceName, @NonNull PrintWriter writer)752 private boolean checkDumpPermission(@NonNull String serviceName, 753 @NonNull PrintWriter writer) { 754 if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 755 != PackageManager.PERMISSION_GRANTED) { 756 writer.println("Permission Denial: can't dump " + serviceName + " from from pid=" 757 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() 758 + " due to missing " + android.Manifest.permission.DUMP + " permission"); 759 return false; 760 } else { 761 return true; 762 } 763 } 764 } 765 766 private class Local implements RoleManagerLocal { 767 @NonNull 768 @Override getRolesAndHolders(@serIdInt int userId)769 public Map<String, Set<String>> getRolesAndHolders(@UserIdInt int userId) { 770 // Convert ArrayMap<String, ArraySet<String>> to Map<String, Set<String>> for the API. 771 //noinspection unchecked 772 return (Map<String, Set<String>>) (Map<String, ?>) 773 getOrCreateUserState(userId).getRolesAndHolders(); 774 } 775 } 776 } 777