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.controller.service; 18 19 import android.app.role.RoleControllerService; 20 import android.app.role.RoleManager; 21 import android.content.Context; 22 import android.content.pm.ApplicationInfo; 23 import android.os.Process; 24 import android.os.UserHandle; 25 import android.util.ArrayMap; 26 import android.util.ArraySet; 27 import android.util.Log; 28 29 import androidx.annotation.NonNull; 30 import androidx.annotation.WorkerThread; 31 32 import com.android.role.controller.model.Role; 33 import com.android.role.controller.model.Roles; 34 import com.android.role.controller.util.CollectionUtils; 35 import com.android.role.controller.util.LegacyRoleFallbackEnabledUtils; 36 import com.android.role.controller.util.PackageUtils; 37 import com.android.role.controller.util.UserUtils; 38 39 import java.util.ArrayList; 40 import java.util.List; 41 import java.util.Objects; 42 43 /** 44 * Implementation of {@link RoleControllerService}. 45 */ 46 public class RoleControllerServiceImpl extends RoleControllerService { 47 48 private static final String LOG_TAG = RoleControllerServiceImpl.class.getSimpleName(); 49 50 private static final boolean DEBUG = false; 51 52 53 private UserHandle mUser; 54 private Context mContext; 55 private RoleManager mUserRoleManager; 56 RoleControllerServiceImpl()57 public RoleControllerServiceImpl() {} 58 RoleControllerServiceImpl(@onNull UserHandle user, @NonNull Context context)59 public RoleControllerServiceImpl(@NonNull UserHandle user, @NonNull Context context) { 60 init(user, context); 61 } 62 63 @Override onCreate()64 public void onCreate() { 65 super.onCreate(); 66 67 init(Process.myUserHandle(), this); 68 } 69 init(@onNull UserHandle user, @NonNull Context context)70 private void init(@NonNull UserHandle user, @NonNull Context context) { 71 mUser = user; 72 mContext = context; 73 Context userContext = UserUtils.getUserContext(context, user); 74 mUserRoleManager = userContext.getSystemService(RoleManager.class); 75 } 76 77 @Override 78 @WorkerThread onGrantDefaultRoles()79 public boolean onGrantDefaultRoles() { 80 if (DEBUG) { 81 Log.i(LOG_TAG, "Granting default roles, user: " + mUser.myUserId()); 82 } 83 84 // Gather the available roles for current user. 85 ArrayMap<String, Role> roleMap = Roles.get(mContext); 86 List<Role> roles = new ArrayList<>(); 87 List<String> roleNames = new ArrayList<>(); 88 ArraySet<String> addedRoleNames = new ArraySet<>(); 89 int roleMapSize = roleMap.size(); 90 for (int i = 0; i < roleMapSize; i++) { 91 Role role = roleMap.valueAt(i); 92 93 if (!role.isAvailableAsUser(mUser, mContext)) { 94 continue; 95 } 96 roles.add(role); 97 String roleName = role.getName(); 98 roleNames.add(roleName); 99 if (!mUserRoleManager.isRoleAvailable(roleName)) { 100 addedRoleNames.add(roleName); 101 } 102 } 103 104 // TODO: Clean up holders of roles that will be removed. 105 106 // Set the available role names in RoleManager. 107 mUserRoleManager.setRoleNamesFromController(roleNames); 108 109 int addedRoleNamesSize = addedRoleNames.size(); 110 for (int i = 0; i < addedRoleNamesSize; i++) { 111 String roleName = addedRoleNames.valueAt(i); 112 113 Role role = roleMap.get(roleName); 114 role.onRoleAddedAsUser(mUser, mContext); 115 } 116 117 // Go through the holders of all roles. 118 int rolesSize = roles.size(); 119 for (int rolesIndex = 0; rolesIndex < rolesSize; rolesIndex++) { 120 Role role = roles.get(rolesIndex); 121 122 String roleName = role.getName(); 123 124 // For each of the current holders, check if it is still qualified, redo grant if so, or 125 // remove it otherwise. 126 List<String> currentPackageNames = mUserRoleManager.getRoleHolders(roleName); 127 int currentPackageNamesSize = currentPackageNames.size(); 128 for (int currentPackageNamesIndex = 0; 129 currentPackageNamesIndex < currentPackageNamesSize; 130 currentPackageNamesIndex++) { 131 String packageName = currentPackageNames.get(currentPackageNamesIndex); 132 133 if (role.isPackageQualifiedAsUser(packageName, mUser, mContext)) { 134 if (!role.shouldOnlyGrantWhenAdded()) { 135 // We should not override user set or fixed permissions because we are only 136 // redoing the grant here. Otherwise, user won't be able to revoke 137 // permissions granted by role. 138 addRoleHolderInternal(role, packageName, false, false, true); 139 } 140 } else { 141 Log.i(LOG_TAG, "Removing package that no longer qualifies for the role," 142 + " package: " + packageName + ", role: " + roleName); 143 removeRoleHolderInternal(role, packageName, false); 144 } 145 } 146 147 // If there is no holder for a role now, or the role is static, we need to add default 148 // or fallback holders, if any. 149 currentPackageNames = mUserRoleManager.getRoleHolders(roleName); 150 currentPackageNamesSize = currentPackageNames.size(); 151 boolean isStaticRole = role.isStatic(); 152 if (currentPackageNamesSize == 0 || isStaticRole) { 153 List<String> packageNamesToAdd = null; 154 if (addedRoleNames.contains(roleName) || isStaticRole) { 155 packageNamesToAdd = role.getDefaultHoldersAsUser(mUser, mContext); 156 } 157 if (packageNamesToAdd == null || packageNamesToAdd.isEmpty()) { 158 packageNamesToAdd = CollectionUtils.singletonOrEmpty( 159 role.getFallbackHolderAsUser(mUser, mContext)); 160 } 161 162 int packageNamesToAddSize = packageNamesToAdd.size(); 163 for (int packageNamesToAddIndex = 0; packageNamesToAddIndex < packageNamesToAddSize; 164 packageNamesToAddIndex++) { 165 String packageName = packageNamesToAdd.get(packageNamesToAddIndex); 166 167 if (currentPackageNames.contains(packageName)) { 168 // This may happen when we are ensuring all default holders are added for 169 // static roles. 170 continue; 171 } 172 if (!role.isPackageQualifiedAsUser(packageName, mUser, mContext)) { 173 Log.e(LOG_TAG, "Default/fallback role holder package doesn't qualify for" 174 + " the role, package: " + packageName + ", role: " + roleName); 175 continue; 176 } 177 Log.i(LOG_TAG, "Adding package as default/fallback role holder, package: " 178 + packageName + ", role: " + roleName); 179 // TODO: If we don't override user here, user might end up missing incoming 180 // phone calls or SMS, so we just keep the old behavior. But overriding user 181 // choice about permission without explicit user action is bad, so maybe we 182 // should at least show a notification? 183 addRoleHolderInternal(role, packageName, role.shouldOverrideUserWhenGranting()); 184 } 185 } 186 187 // Ensure that an exclusive role has at most one holder. 188 currentPackageNames = mUserRoleManager.getRoleHolders(roleName); 189 currentPackageNamesSize = currentPackageNames.size(); 190 if (role.isExclusive() && currentPackageNamesSize > 1) { 191 Log.w(LOG_TAG, "Multiple packages holding an exclusive role, role: " 192 + roleName); 193 // No good way to determine who should be the only one, just keep the first one. 194 for (int currentPackageNamesIndex = 1; 195 currentPackageNamesIndex < currentPackageNamesSize; 196 currentPackageNamesIndex++) { 197 String packageName = currentPackageNames.get(currentPackageNamesIndex); 198 199 Log.i(LOG_TAG, "Removing extraneous package for an exclusive role, package: " 200 + packageName + ", role: " + roleName); 201 removeRoleHolderInternal(role, packageName, false); 202 } 203 } 204 } 205 206 return true; 207 } 208 209 @Override 210 @WorkerThread onAddRoleHolder(@onNull String roleName, @NonNull String packageName, int flags)211 public boolean onAddRoleHolder(@NonNull String roleName, @NonNull String packageName, 212 int flags) { 213 if (!checkFlags(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP)) { 214 return false; 215 } 216 217 Role role = Roles.get(mContext).get(roleName); 218 if (role == null) { 219 Log.e(LOG_TAG, "Unknown role: " + roleName); 220 return false; 221 } 222 if (!role.isAvailableAsUser(mUser, mContext)) { 223 Log.e(LOG_TAG, "Role is unavailable: " + roleName); 224 return false; 225 } 226 227 if (!role.isPackageQualifiedAsUser(packageName, mUser, mContext)) { 228 Log.e(LOG_TAG, "Package does not qualify for the role, package: " + packageName 229 + ", role: " + roleName); 230 return false; 231 } 232 233 boolean added = false; 234 if (role.isExclusive()) { 235 List<String> currentPackageNames = mUserRoleManager.getRoleHolders(roleName); 236 int currentPackageNamesSize = currentPackageNames.size(); 237 for (int i = 0; i < currentPackageNamesSize; i++) { 238 String currentPackageName = currentPackageNames.get(i); 239 240 if (Objects.equals(currentPackageName, packageName)) { 241 Log.i(LOG_TAG, "Package is already a role holder, package: " + packageName 242 + ", role: " + roleName); 243 added = true; 244 continue; 245 } 246 247 boolean removed = removeRoleHolderInternal(role, currentPackageName, false); 248 if (!removed) { 249 // TODO: Clean up? 250 return false; 251 } 252 } 253 } 254 255 boolean dontKillApp = hasFlag(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP); 256 added = addRoleHolderInternal(role, packageName, dontKillApp, 257 role.shouldOverrideUserWhenGranting(), added); 258 if (!added) { 259 return false; 260 } 261 262 role.onHolderAddedAsUser(packageName, mUser, mContext); 263 role.onHolderChangedAsUser(mUser, mContext); 264 265 return true; 266 } 267 268 @Override 269 @WorkerThread onRemoveRoleHolder(@onNull String roleName, @NonNull String packageName, int flags)270 public boolean onRemoveRoleHolder(@NonNull String roleName, @NonNull String packageName, 271 int flags) { 272 if (!checkFlags(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP)) { 273 return false; 274 } 275 276 Role role = Roles.get(mContext).get(roleName); 277 if (role == null) { 278 Log.e(LOG_TAG, "Unknown role: " + roleName); 279 return false; 280 } 281 if (!role.isAvailableAsUser(mUser, mContext)) { 282 Log.e(LOG_TAG, "Role is unavailable: " + roleName); 283 return false; 284 } 285 286 boolean dontKillApp = hasFlag(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP); 287 boolean removed = removeRoleHolderInternal(role, packageName, dontKillApp); 288 if (!removed) { 289 return false; 290 } 291 292 // TODO: Should we consider this successful regardless? 293 boolean fallbackSuccessful = addFallbackRoleHolderMaybe(role); 294 if (!fallbackSuccessful) { 295 return false; 296 } 297 298 role.onHolderChangedAsUser(mUser, mContext); 299 300 return true; 301 } 302 303 @Override 304 @WorkerThread onClearRoleHolders(@onNull String roleName, int flags)305 public boolean onClearRoleHolders(@NonNull String roleName, int flags) { 306 if (!checkFlags(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP)) { 307 return false; 308 } 309 310 Role role = Roles.get(mContext).get(roleName); 311 if (role == null) { 312 Log.e(LOG_TAG, "Unknown role: " + roleName); 313 return false; 314 } 315 if (!role.isAvailableAsUser(mUser, mContext)) { 316 Log.e(LOG_TAG, "Role is unavailable: " + roleName); 317 return false; 318 } 319 320 boolean dontKillApp = hasFlag(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP); 321 boolean cleared = clearRoleHoldersInternal(role, dontKillApp); 322 if (!cleared) { 323 return false; 324 } 325 326 // TODO: Should we consider this successful regardless? 327 boolean fallbackSuccessful = addFallbackRoleHolderMaybe(role); 328 if (!fallbackSuccessful) { 329 return false; 330 } 331 332 role.onHolderChangedAsUser(mUser, mContext); 333 334 return true; 335 } 336 337 @WorkerThread addRoleHolderInternal(@onNull Role role, @NonNull String packageName, boolean overrideUser)338 private boolean addRoleHolderInternal(@NonNull Role role, @NonNull String packageName, 339 boolean overrideUser) { 340 return addRoleHolderInternal(role, packageName, false, overrideUser, false); 341 } 342 343 @WorkerThread addRoleHolderInternal(@onNull Role role, @NonNull String packageName, boolean dontKillApp, boolean overrideUser, boolean added)344 private boolean addRoleHolderInternal(@NonNull Role role, @NonNull String packageName, 345 boolean dontKillApp, boolean overrideUser, boolean added) { 346 role.grantAsUser(packageName, dontKillApp, overrideUser, mUser, mContext); 347 348 String roleName = role.getName(); 349 if (!added) { 350 added = mUserRoleManager.addRoleHolderFromController(roleName, packageName); 351 } 352 if (!added) { 353 Log.e(LOG_TAG, "Failed to add role holder in RoleManager, package: " + packageName 354 + ", role: " + roleName); 355 } 356 return added; 357 } 358 359 @WorkerThread removeRoleHolderInternal(@onNull Role role, @NonNull String packageName, boolean dontKillApp)360 private boolean removeRoleHolderInternal(@NonNull Role role, @NonNull String packageName, 361 boolean dontKillApp) { 362 ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName, 363 mUser, mContext); 364 if (applicationInfo == null) { 365 Log.w(LOG_TAG, "Cannot get ApplicationInfo for package: " + packageName); 366 } 367 368 if (applicationInfo != null) { 369 role.revokeAsUser(packageName, dontKillApp, false, mUser, mContext); 370 } 371 372 String roleName = role.getName(); 373 boolean removed = mUserRoleManager.removeRoleHolderFromController(roleName, packageName); 374 if (!removed) { 375 Log.e(LOG_TAG, "Failed to remove role holder in RoleManager," + " package: " 376 + packageName + ", role: " + roleName); 377 } 378 return removed; 379 } 380 381 @WorkerThread clearRoleHoldersInternal(@onNull Role role, boolean dontKillApp)382 private boolean clearRoleHoldersInternal(@NonNull Role role, boolean dontKillApp) { 383 String roleName = role.getName(); 384 List<String> packageNames = mUserRoleManager.getRoleHolders(roleName); 385 boolean cleared = true; 386 387 int packageNamesSize = packageNames.size(); 388 for (int i = 0; i < packageNamesSize; i++) { 389 String packageName = packageNames.get(i); 390 boolean removed = removeRoleHolderInternal(role, packageName, dontKillApp); 391 if (!removed) { 392 cleared = false; 393 } 394 } 395 396 if (!cleared) { 397 Log.e(LOG_TAG, "Failed to clear role holders, role: " + roleName); 398 } 399 return cleared; 400 } 401 402 @WorkerThread addFallbackRoleHolderMaybe(@onNull Role role)403 private boolean addFallbackRoleHolderMaybe(@NonNull Role role) { 404 String roleName = role.getName(); 405 List<String> currentPackageNames = mUserRoleManager.getRoleHolders(roleName); 406 if (!currentPackageNames.isEmpty()) { 407 return true; 408 } 409 410 String fallbackPackageName = role.getFallbackHolderAsUser(mUser, mContext); 411 if (fallbackPackageName == null) { 412 return true; 413 } 414 415 if (!role.isPackageQualifiedAsUser(fallbackPackageName, mUser, mContext)) { 416 Log.e(LOG_TAG, "Fallback role holder package doesn't qualify for the role, package: " 417 + fallbackPackageName + ", role: " + roleName); 418 return false; 419 } 420 421 Log.i(LOG_TAG, "Adding package as fallback role holder, package: " + fallbackPackageName 422 + ", role: " + roleName); 423 // TODO: If we don't override user here, user might end up missing incoming 424 // phone calls or SMS, so we just keep the old behavior. But overriding user 425 // choice about permission without explicit user action is bad, so maybe we 426 // should at least show a notification? 427 return addRoleHolderInternal(role, fallbackPackageName, 428 role.shouldOverrideUserWhenGranting()); 429 } 430 431 @Override onIsApplicationQualifiedForRole(@onNull String roleName, @NonNull String packageName)432 public boolean onIsApplicationQualifiedForRole(@NonNull String roleName, 433 @NonNull String packageName) { 434 // This API has been deprecated and Settings has been using onIsApplicationVisibleForRole() 435 // instead. 436 return false; 437 } 438 439 @Override onIsApplicationVisibleForRole(@onNull String roleName, @NonNull String packageName)440 public boolean onIsApplicationVisibleForRole(@NonNull String roleName, 441 @NonNull String packageName) { 442 Role role = Roles.get(mContext).get(roleName); 443 if (role == null) { 444 return false; 445 } 446 if (!role.isAvailableAsUser(mUser, mContext)) { 447 return false; 448 } 449 if (!role.isPackageQualifiedAsUser(packageName, mUser, mContext)) { 450 return false; 451 } 452 ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName, 453 mUser, mContext); 454 if (applicationInfo == null || !role.isApplicationVisibleAsUser(applicationInfo, mUser, 455 mContext)) { 456 return false; 457 } 458 return true; 459 } 460 461 @Override onIsRoleVisible(@onNull String roleName)462 public boolean onIsRoleVisible(@NonNull String roleName) { 463 Role role = Roles.get(mContext).get(roleName); 464 if (role == null) { 465 return false; 466 } 467 if (!role.isAvailableAsUser(mUser, mContext)) { 468 return false; 469 } 470 471 return role.isVisibleAsUser(mUser, mContext); 472 } 473 474 @Override 475 @NonNull onGetLegacyFallbackDisabledRoles()476 public List<String> onGetLegacyFallbackDisabledRoles() { 477 return LegacyRoleFallbackEnabledUtils.getFallbackDisabledRoles(mUser, mContext); 478 } 479 480 checkFlags(int flags, int allowedFlags)481 private static boolean checkFlags(int flags, int allowedFlags) { 482 if ((flags & allowedFlags) != flags) { 483 Log.e(LOG_TAG, "flags is invalid, flags: 0x" + Integer.toHexString(flags) 484 + ", allowed flags: 0x" + Integer.toHexString(allowedFlags)); 485 return false; 486 } 487 return true; 488 } 489 hasFlag(int flags, int flag)490 private static boolean hasFlag(int flags, int flag) { 491 return (flags & flag) == flag; 492 } 493 } 494