1 /* 2 * Copyright (C) 2015 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.car.pm; 18 19 import static android.Manifest.permission.QUERY_ALL_PACKAGES; 20 import static android.car.Car.PERMISSION_MANAGE_DISPLAY_COMPATIBILITY; 21 import static android.car.content.pm.CarPackageManager.BLOCKING_INTENT_EXTRA_BLOCKED_ACTIVITY_NAME; 22 import static android.car.content.pm.CarPackageManager.BLOCKING_INTENT_EXTRA_BLOCKED_TASK_ID; 23 import static android.car.content.pm.CarPackageManager.BLOCKING_INTENT_EXTRA_DISPLAY_ID; 24 import static android.car.content.pm.CarPackageManager.BLOCKING_INTENT_EXTRA_IS_ROOT_ACTIVITY_DO; 25 import static android.car.content.pm.CarPackageManager.BLOCKING_INTENT_EXTRA_ROOT_ACTIVITY_NAME; 26 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING; 27 28 import static com.android.car.CarServiceUtils.checkCalledByPackage; 29 import static com.android.car.CarServiceUtils.getHandlerThread; 30 import static com.android.car.CarServiceUtils.isEventOfType; 31 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO; 32 33 import android.annotation.NonNull; 34 import android.annotation.Nullable; 35 import android.annotation.UserIdInt; 36 import android.app.ActivityManager; 37 import android.app.PendingIntent; 38 import android.app.TaskInfo; 39 import android.car.Car; 40 import android.car.CarOccupantZoneManager; 41 import android.car.CarVersion; 42 import android.car.ICarOccupantZoneCallback; 43 import android.car.builtin.app.ActivityManagerHelper; 44 import android.car.builtin.app.TaskInfoHelper; 45 import android.car.builtin.content.pm.PackageManagerHelper; 46 import android.car.builtin.os.BuildHelper; 47 import android.car.builtin.os.ServiceManagerHelper; 48 import android.car.builtin.util.Slogf; 49 import android.car.content.pm.AppBlockingPackageInfo; 50 import android.car.content.pm.CarAppBlockingPolicy; 51 import android.car.content.pm.CarAppBlockingPolicyService; 52 import android.car.content.pm.CarPackageManager; 53 import android.car.content.pm.ICarBlockingUiCommandListener; 54 import android.car.content.pm.ICarPackageManager; 55 import android.car.drivingstate.CarUxRestrictions; 56 import android.car.drivingstate.ICarUxRestrictionsChangeListener; 57 import android.car.hardware.power.CarPowerPolicy; 58 import android.car.hardware.power.CarPowerPolicyFilter; 59 import android.car.hardware.power.ICarPowerPolicyListener; 60 import android.car.hardware.power.PowerComponent; 61 import android.car.user.CarUserManager.UserLifecycleListener; 62 import android.car.user.UserLifecycleEventFilter; 63 import android.content.BroadcastReceiver; 64 import android.content.ComponentName; 65 import android.content.Context; 66 import android.content.Intent; 67 import android.content.IntentFilter; 68 import android.content.pm.ActivityInfo; 69 import android.content.pm.ApplicationInfo; 70 import android.content.pm.PackageInfo; 71 import android.content.pm.PackageManager; 72 import android.content.pm.PackageManager.NameNotFoundException; 73 import android.content.pm.ResolveInfo; 74 import android.content.pm.ServiceInfo; 75 import android.content.pm.Signature; 76 import android.content.res.Resources; 77 import android.os.Binder; 78 import android.os.Handler; 79 import android.os.HandlerThread; 80 import android.os.IBinder; 81 import android.os.Looper; 82 import android.os.Message; 83 import android.os.ParcelFileDescriptor; 84 import android.os.Process; 85 import android.os.RemoteException; 86 import android.os.ServiceSpecificException; 87 import android.os.SystemClock; 88 import android.os.SystemProperties; 89 import android.os.UserHandle; 90 import android.text.TextUtils; 91 import android.util.ArraySet; 92 import android.util.Log; 93 import android.util.Pair; 94 import android.util.SparseArray; 95 import android.util.SparseIntArray; 96 import android.util.SparseLongArray; 97 import android.util.proto.ProtoOutputStream; 98 import android.view.Display; 99 import android.view.accessibility.AccessibilityEvent; 100 101 import com.android.car.CarLocalServices; 102 import com.android.car.CarLog; 103 import com.android.car.CarOccupantZoneService; 104 import com.android.car.CarServiceBase; 105 import com.android.car.CarServiceHelperWrapper; 106 import com.android.car.CarUxRestrictionsManagerService; 107 import com.android.car.R; 108 import com.android.car.am.CarActivityService; 109 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport; 110 import com.android.car.internal.util.DebugUtils; 111 import com.android.car.internal.util.IndentingPrintWriter; 112 import com.android.car.internal.util.LocalLog; 113 import com.android.car.internal.util.Sets; 114 import com.android.car.power.CarPowerManagementService; 115 import com.android.car.user.CarUserService; 116 import com.android.internal.annotations.GuardedBy; 117 import com.android.internal.annotations.VisibleForTesting; 118 119 import java.io.BufferedReader; 120 import java.io.FileReader; 121 import java.io.IOException; 122 import java.lang.ref.WeakReference; 123 import java.util.ArrayList; 124 import java.util.Arrays; 125 import java.util.HashMap; 126 import java.util.HashSet; 127 import java.util.LinkedList; 128 import java.util.List; 129 import java.util.Map; 130 import java.util.Map.Entry; 131 import java.util.Objects; 132 import java.util.Set; 133 134 /** 135 * Package manager service for cars. 136 */ 137 public final class CarPackageManagerService extends ICarPackageManager.Stub 138 implements CarServiceBase { 139 140 @VisibleForTesting 141 static final String TAG = CarLog.tagFor(CarPackageManagerService.class); 142 143 static final boolean DBG = Slogf.isLoggable(TAG, Log.DEBUG); 144 145 // Delimiters to parse packages and activities in the configuration XML resource. 146 private static final String PACKAGE_DELIMITER = ","; 147 private static final String PACKAGE_ACTIVITY_DELIMITER = "/"; 148 private static final int LOG_SIZE = 20; 149 private static final String[] WINDOW_DUMP_ARGUMENTS = new String[]{"windows"}; 150 151 private static final String PROPERTY_RO_DRIVING_SAFETY_REGION = 152 "ro.android.car.drivingsafetyregion"; 153 private static final int ABA_LAUNCH_TIMEOUT_MS = 1_000; 154 155 private final Context mContext; 156 private final CarActivityService mActivityService; 157 private final PackageManager mPackageManager; 158 private final ActivityManager mActivityManager; 159 private final IBinder mWindowManagerBinder; 160 161 private final HandlerThread mHandlerThread = getHandlerThread( 162 getClass().getSimpleName()); 163 private final PackageHandler mHandler = new PackageHandler(mHandlerThread.getLooper(), this); 164 private final Object mLock = new Object(); 165 166 // For dumpsys logging. 167 private final LocalLog mBlockedActivityLogs = new LocalLog(LOG_SIZE); 168 private final BlockingUiCommandListenerMediator mBlockingUiCommandListenerMediator; 169 170 // Store the allowlist and blocklist strings from the resource file. 171 private String mConfiguredAllowlist; 172 private String mConfiguredSystemAllowlist; 173 private String mConfiguredBlocklist; 174 @GuardedBy("mLock") 175 private Map<String, Set<String>> mConfiguredAllowlistMap; 176 @GuardedBy("mLock") 177 private Map<String, Set<String>> mConfiguredBlocklistMap; 178 179 private final List<String> mAllowedAppInstallSources; 180 181 @GuardedBy("mLock") 182 private final SparseArray<ComponentName> mTopActivityWithDialogPerDisplay = new SparseArray<>(); 183 184 /** 185 * Hold policy set from policy service or client. 186 * Key: packageName of policy service 187 */ 188 @GuardedBy("mLock") 189 private final HashMap<String, ClientPolicy> mClientPolicies = new HashMap<>(); 190 @GuardedBy("mLock") 191 private HashMap<String, AppBlockingPackageInfoWrapper> mActivityAllowlistMap = new HashMap<>(); 192 @GuardedBy("mLock") 193 private HashSet<String> mActivityDenylistPackages = new HashSet<String>(); 194 195 @GuardedBy("mLock") 196 private LinkedList<AppBlockingPolicyProxy> mProxies; 197 198 @GuardedBy("mLock") 199 private final LinkedList<CarAppBlockingPolicy> mWaitingPolicies = new LinkedList<>(); 200 201 @GuardedBy("mLock") 202 private String mCurrentDrivingSafetyRegion = CarPackageManager.DRIVING_SAFETY_REGION_ALL; 203 // Package name + '/' + className format 204 @GuardedBy("mLock") 205 private final ArraySet<String> mTempAllowedActivities = new ArraySet<>(); 206 207 private final CarUxRestrictionsManagerService mCarUxRestrictionsService; 208 private final CarOccupantZoneService mCarOccupantZoneService; 209 private final boolean mEnableActivityBlocking; 210 211 private final ComponentName mActivityBlockingActivity; 212 // Memorize the target of ABA to defend bypassing it with launching two Activities continuously. 213 private final SparseArray<TaskInfo> mBlockingActivityTargets = new SparseArray<>(); 214 private final SparseLongArray mBlockingActivityLaunchTimes = new SparseLongArray(); 215 private final boolean mPreventTemplatedAppsFromShowingDialog; 216 private final String mTemplateActivityClassName; 217 218 private final ActivityListener mActivityListener = new ActivityListener(); 219 220 // K: (logical) display id of a physical display, V: UXR change listener of this display. 221 // For multi-display, monitor UXR change on each display. 222 @GuardedBy("mLock") 223 private final SparseArray<UxRestrictionsListener> mUxRestrictionsListeners = 224 new SparseArray<>(); 225 // K: (logical) display id of a display, V: Task info of the blocking ui of this display. 226 // For multi-display, monitor blocking ui task information for each display. 227 @GuardedBy("mLock") 228 private final SparseArray<TaskInfo> mBlockingUiTaskInfoPerDisplay = new SparseArray<>(); 229 private final VendorServiceController mVendorServiceController; 230 231 // Information related to when the installed packages should be parsed for building a allow and 232 // block list 233 private final Set<String> mPackageManagerActions = Sets.newArraySet( 234 Intent.ACTION_PACKAGE_ADDED, 235 Intent.ACTION_PACKAGE_CHANGED, 236 Intent.ACTION_PACKAGE_REMOVED, 237 Intent.ACTION_PACKAGE_REPLACED); 238 239 private final PackageParsingEventReceiver mPackageParsingEventReceiver = 240 new PackageParsingEventReceiver(); 241 /** 242 * Mapping between the task ID and the last known display ID. 243 */ 244 @GuardedBy("mLock") 245 private final SparseIntArray mLastKnownDisplayIdForTask = new SparseIntArray(); 246 247 private final UserLifecycleListener mUserLifecycleListener = event -> { 248 if (!isEventOfType(TAG, event, USER_LIFECYCLE_EVENT_TYPE_SWITCHING)) { 249 return; 250 } 251 252 synchronized (mLock) { 253 resetTempAllowedActivitiesLocked(); 254 } 255 }; 256 257 private final ICarPowerPolicyListener mDisplayPowerPolicyListener = 258 new ICarPowerPolicyListener.Stub() { 259 @Override 260 public void onPolicyChanged(CarPowerPolicy policy, 261 CarPowerPolicy accumulatedPolicy) { 262 if (!policy.isComponentEnabled(PowerComponent.DISPLAY)) { 263 synchronized (mLock) { 264 resetTempAllowedActivitiesLocked(); 265 } 266 } 267 } 268 }; 269 CarPackageManagerService(Context context, CarUxRestrictionsManagerService uxRestrictionsService, CarActivityService activityService, CarOccupantZoneService carOccupantZoneService)270 public CarPackageManagerService(Context context, 271 CarUxRestrictionsManagerService uxRestrictionsService, 272 CarActivityService activityService, CarOccupantZoneService carOccupantZoneService) { 273 mContext = context; 274 mCarUxRestrictionsService = uxRestrictionsService; 275 mActivityService = activityService; 276 mCarOccupantZoneService = carOccupantZoneService; 277 mPackageManager = mContext.getPackageManager(); 278 mActivityManager = mContext.getSystemService(ActivityManager.class); 279 mWindowManagerBinder = ServiceManagerHelper.getService(Context.WINDOW_SERVICE); 280 Resources res = context.getResources(); 281 mEnableActivityBlocking = res.getBoolean(R.bool.enableActivityBlockingForSafety); 282 String blockingActivity = res.getString(R.string.activityBlockingActivity); 283 mActivityBlockingActivity = ComponentName.unflattenFromString(blockingActivity); 284 if (mEnableActivityBlocking && mActivityBlockingActivity == null) { 285 Slogf.wtf(TAG, "mActivityBlockingActivity can't be null when enabled"); 286 } 287 mAllowedAppInstallSources = Arrays.asList( 288 res.getStringArray(R.array.allowedAppInstallSources)); 289 mVendorServiceController = new VendorServiceController( 290 mContext, mHandler.getLooper()); 291 mPreventTemplatedAppsFromShowingDialog = 292 res.getBoolean(R.bool.config_preventTemplatedAppsFromShowingDialog); 293 mTemplateActivityClassName = res.getString(R.string.config_template_activity_class_name); 294 mBlockingUiCommandListenerMediator = new BlockingUiCommandListenerMediator(); 295 } 296 297 298 @Override setAppBlockingPolicy(String packageName, CarAppBlockingPolicy policy, int flags)299 public void setAppBlockingPolicy(String packageName, CarAppBlockingPolicy policy, int flags) { 300 if (DBG) { 301 Slogf.d(TAG, "policy setting from binder call, client:" + packageName); 302 } 303 doSetAppBlockingPolicy(packageName, policy, flags); 304 } 305 306 /** 307 * Restarts the requested task. If task with {@code taskId} does not exist, do nothing. 308 */ 309 @Override restartTask(int taskId)310 public void restartTask(int taskId) { 311 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.REAL_GET_TASKS) 312 != PackageManager.PERMISSION_GRANTED) { 313 throw new SecurityException( 314 "requires permission " + android.Manifest.permission.REAL_GET_TASKS); 315 } 316 mActivityService.restartTask(taskId); 317 } 318 319 @Override getCurrentDrivingSafetyRegion()320 public String getCurrentDrivingSafetyRegion() { 321 assertAppBlockingOrDrivingStatePermission(); 322 synchronized (mLock) { 323 return mCurrentDrivingSafetyRegion; 324 } 325 } 326 getComponentNameString(String packageName, String className)327 private String getComponentNameString(String packageName, String className) { 328 return packageName + '/' + className; 329 } 330 331 @Override controlOneTimeActivityBlockingBypassingAsUser(String packageName, String activityClassName, boolean bypass, @UserIdInt int userId)332 public void controlOneTimeActivityBlockingBypassingAsUser(String packageName, 333 String activityClassName, boolean bypass, @UserIdInt int userId) { 334 assertAppBlockingPermission(); 335 if (!callerCanQueryPackage(packageName)) { 336 throw new SecurityException("cannot query other package"); 337 } 338 try { 339 // Read this to check the validity of pkg / activity name. Not checking this can allow 340 // bad apps to be allowed later. 341 CarAppMetadataReader.getSupportedDrivingSafetyRegionsForActivityAsUser(mContext, 342 packageName, activityClassName, userId); 343 } catch (NameNotFoundException e) { 344 throw new ServiceSpecificException(CarPackageManager.ERROR_CODE_NO_PACKAGE, 345 e.getMessage()); 346 } 347 String componentName = getComponentNameString(packageName, activityClassName); 348 synchronized (mLock) { 349 if (bypass) { 350 mTempAllowedActivities.add(componentName); 351 } else { 352 mTempAllowedActivities.remove(componentName); 353 } 354 } 355 if (!bypass) { // block top activities if bypassing is disabled. 356 mHandler.post(this::blockTopActivitiesOnAllDisplaysIfNecessary); 357 } 358 } 359 360 @GuardedBy("mLock") resetTempAllowedActivitiesLocked()361 private void resetTempAllowedActivitiesLocked() { 362 mTempAllowedActivities.clear(); 363 } 364 365 @Override getSupportedDrivingSafetyRegionsForActivityAsUser(String packageName, String activityClassName, @UserIdInt int userId)366 public List<String> getSupportedDrivingSafetyRegionsForActivityAsUser(String packageName, 367 String activityClassName, @UserIdInt int userId) { 368 assertAppBlockingOrDrivingStatePermission(); 369 if (!callerCanQueryPackage(packageName)) { 370 throw new SecurityException("cannot query other package"); 371 } 372 long token = Binder.clearCallingIdentity(); 373 try { 374 return CarAppMetadataReader.getSupportedDrivingSafetyRegionsForActivityAsUser(mContext, 375 packageName, activityClassName, userId); 376 } catch (NameNotFoundException e) { 377 throw new ServiceSpecificException(CarPackageManager.ERROR_CODE_NO_PACKAGE, 378 e.getMessage()); 379 } finally { 380 Binder.restoreCallingIdentity(token); 381 } 382 } 383 assertAppBlockingOrDrivingStatePermission()384 private void assertAppBlockingOrDrivingStatePermission() { 385 if (mContext.checkCallingOrSelfPermission(Car.PERMISSION_CONTROL_APP_BLOCKING) 386 != PackageManager.PERMISSION_GRANTED && mContext.checkCallingOrSelfPermission( 387 Car.PERMISSION_CAR_DRIVING_STATE) != PackageManager.PERMISSION_GRANTED) { 388 throw new SecurityException( 389 "requires permission " + Car.PERMISSION_CONTROL_APP_BLOCKING + " or " 390 + Car.PERMISSION_CAR_DRIVING_STATE); 391 } 392 } 393 assertAppBlockingPermission()394 private void assertAppBlockingPermission() { 395 if (mContext.checkCallingOrSelfPermission(Car.PERMISSION_CONTROL_APP_BLOCKING) 396 != PackageManager.PERMISSION_GRANTED) { 397 throw new SecurityException( 398 "requires permission " + Car.PERMISSION_CONTROL_APP_BLOCKING); 399 } 400 } 401 doSetAppBlockingPolicy(String packageName, CarAppBlockingPolicy policy, int flags)402 private void doSetAppBlockingPolicy(String packageName, CarAppBlockingPolicy policy, 403 int flags) { 404 assertAppBlockingPermission(); 405 checkCalledByPackage(mContext, packageName); 406 if (policy == null) { 407 throw new IllegalArgumentException("policy cannot be null"); 408 } 409 if ((flags & CarPackageManager.FLAG_SET_POLICY_ADD) != 0 && 410 (flags & CarPackageManager.FLAG_SET_POLICY_REMOVE) != 0) { 411 throw new IllegalArgumentException( 412 "Cannot set both FLAG_SET_POLICY_ADD and FLAG_SET_POLICY_REMOVE flag"); 413 } 414 synchronized (mLock) { 415 if ((flags & CarPackageManager.FLAG_SET_POLICY_WAIT_FOR_CHANGE) != 0) { 416 mWaitingPolicies.add(policy); 417 } 418 } 419 mHandler.requestUpdatingPolicy(packageName, policy, flags); 420 if ((flags & CarPackageManager.FLAG_SET_POLICY_WAIT_FOR_CHANGE) != 0) { 421 synchronized (mLock) { 422 try { 423 while (mWaitingPolicies.contains(policy)) { 424 mLock.wait(); 425 } 426 } catch (InterruptedException e) { 427 // Pass it over binder call 428 throw new IllegalStateException( 429 "Interrupted while waiting for policy completion", e); 430 } 431 } 432 } 433 } 434 435 @Override isActivityDistractionOptimized(String packageName, String className)436 public boolean isActivityDistractionOptimized(String packageName, String className) { 437 if (!callerCanQueryPackage(packageName)) return false; 438 assertPackageAndClassName(packageName, className); 439 synchronized (mLock) { 440 if (DBG) { 441 Slogf.d(TAG, "isActivityDistractionOptimized" + dumpPoliciesLocked(false)); 442 } 443 444 if (mTempAllowedActivities.contains(getComponentNameString(packageName, 445 className))) { 446 return true; 447 } 448 449 for (int i = mTopActivityWithDialogPerDisplay.size() - 1; i >= 0; i--) { 450 ComponentName activityWithDialog = mTopActivityWithDialogPerDisplay.get( 451 mTopActivityWithDialogPerDisplay.keyAt(i)); 452 if (activityWithDialog.getClassName().equals(className) 453 && activityWithDialog.getPackageName().equals(packageName)) { 454 return false; 455 } 456 } 457 458 if (searchFromClientPolicyBlocklistsLocked(packageName)) { 459 return false; 460 } 461 462 if (isActivityInClientPolicyAllowlistsLocked(packageName, className)) { 463 return true; 464 } 465 466 // Check deny and allow list 467 boolean packageBlocked = mActivityDenylistPackages.contains(packageName); 468 AppBlockingPackageInfoWrapper infoWrapper = mActivityAllowlistMap.get(packageName); 469 if (!packageBlocked && infoWrapper == null) { 470 // Update cache 471 updateActivityAllowlistAndDenylistMap(packageName); 472 packageBlocked = mActivityDenylistPackages.contains(packageName); 473 infoWrapper = mActivityAllowlistMap.get(packageName); 474 } 475 476 return !packageBlocked 477 && isActivityInMapAndMatching(infoWrapper, packageName, className); 478 } 479 } 480 481 @VisibleForTesting callerCanQueryPackage(String packageName)482 boolean callerCanQueryPackage(String packageName) { 483 int callingUid = Binder.getCallingUid(); 484 if (hasPermissionGranted(QUERY_ALL_PACKAGES, callingUid)) { 485 return true; 486 } 487 String[] packages = mPackageManager.getPackagesForUid(callingUid); 488 if (packages != null && packages.length > 0) { 489 for (int i = 0; i < packages.length; i++) { 490 if (Objects.equals(packageName, packages[i])) { 491 return true; 492 } 493 } 494 } 495 496 Slogf.w(TAG, QUERY_ALL_PACKAGES + " permission is needed to query other packages."); 497 498 return false; 499 } 500 hasPermissionGranted(String permission, int uid)501 private static boolean hasPermissionGranted(String permission, int uid) { 502 return ActivityManagerHelper.checkComponentPermission(permission, uid, 503 /* owningUid= */ Process.INVALID_UID, 504 /* exported= */ true) == PackageManager.PERMISSION_GRANTED; 505 } 506 507 @Override isPendingIntentDistractionOptimized(PendingIntent pendingIntent)508 public boolean isPendingIntentDistractionOptimized(PendingIntent pendingIntent) { 509 if (!pendingIntent.isActivity()) { 510 Slogf.d(TAG, "isPendingIntentDistractionOptimized: Activity not set on the " 511 + "pending intent."); 512 return false; 513 } 514 List<ResolveInfo> infos = pendingIntent.queryIntentComponents( 515 PackageManager.MATCH_DEFAULT_ONLY); 516 if (infos.isEmpty()) { 517 Slogf.d(TAG, "isPendingIntentDistractionOptimized: No intent component found for " 518 + "the pending intent."); 519 return false; 520 } 521 if (infos.size() > 1) { 522 Slogf.d(TAG, "isPendingIntentDistractionOptimized: More than one intent component" 523 + " found for the pending intent. Considering the first one."); 524 } 525 ActivityInfo activityInfo = infos.get(0).activityInfo; 526 return isActivityDistractionOptimized(activityInfo.packageName, activityInfo.name); 527 } 528 529 @Override isServiceDistractionOptimized(String packageName, String className)530 public boolean isServiceDistractionOptimized(String packageName, String className) { 531 if (!callerCanQueryPackage(packageName)) return false; 532 533 if (packageName == null) { 534 throw new IllegalArgumentException("Package name null"); 535 } 536 synchronized (mLock) { 537 if (DBG) { 538 Slogf.d(TAG, "isServiceDistractionOptimized" + dumpPoliciesLocked(false)); 539 } 540 541 if (searchFromClientPolicyBlocklistsLocked(packageName)) { 542 return false; 543 } 544 545 if (searchFromClientPolicyAllowlistsLocked(packageName)) { 546 return true; 547 } 548 549 // Check deny and allow list 550 boolean packageBlocked = mActivityDenylistPackages.contains(packageName); 551 AppBlockingPackageInfoWrapper infoWrapper = mActivityAllowlistMap.get(packageName); 552 if (!packageBlocked && infoWrapper == null) { 553 // Update cache 554 updateActivityAllowlistAndDenylistMap(packageName); 555 packageBlocked = mActivityDenylistPackages.contains(packageName); 556 infoWrapper = mActivityAllowlistMap.get(packageName); 557 } 558 559 return !packageBlocked && infoWrapper != null && infoWrapper.info != null; 560 } 561 } 562 563 @Override isActivityBackedBySafeActivity(ComponentName activityName)564 public boolean isActivityBackedBySafeActivity(ComponentName activityName) { 565 if (activityName == null) return false; 566 if (!callerCanQueryPackage(activityName.getPackageName())) return false; 567 568 TaskInfo info = mActivityService.getTaskInfoForTopActivity(activityName); 569 if (DBG) { 570 Slogf.d(TAG, "isActivityBackedBySafeActivity: info=%s", 571 TaskInfoHelper.toString(info)); 572 } 573 if (info == null) { // not top in focused stack 574 return true; 575 } 576 if (!isUxRestrictedOnDisplay(TaskInfoHelper.getDisplayId(info))) { 577 return true; 578 } 579 if (info.baseActivity == null 580 || info.baseActivity.equals(activityName)) { // nothing below this. 581 return false; 582 } 583 return isActivityDistractionOptimized(info.baseActivity.getPackageName(), 584 info.baseActivity.getClassName()); 585 } 586 getLooper()587 public Looper getLooper() { 588 return mHandlerThread.getLooper(); 589 } 590 assertPackageAndClassName(String packageName, String className)591 private void assertPackageAndClassName(String packageName, String className) { 592 if (packageName == null) { 593 throw new IllegalArgumentException("Package name null"); 594 } 595 if (className == null) { 596 throw new IllegalArgumentException("Class name null"); 597 } 598 } 599 600 @GuardedBy("mLock") searchFromClientPolicyBlocklistsLocked(String packageName)601 private boolean searchFromClientPolicyBlocklistsLocked(String packageName) { 602 for (ClientPolicy policy : mClientPolicies.values()) { 603 AppBlockingPackageInfoWrapper wrapper = policy.mBlocklistsMap.get(packageName); 604 if (wrapper != null && wrapper.isMatching && wrapper.info != null) { 605 return true; 606 } 607 } 608 609 return false; 610 } 611 612 @GuardedBy("mLock") searchFromClientPolicyAllowlistsLocked(String packageName)613 private boolean searchFromClientPolicyAllowlistsLocked(String packageName) { 614 for (ClientPolicy policy : mClientPolicies.values()) { 615 AppBlockingPackageInfoWrapper wrapper = policy.mAllowlistsMap.get(packageName); 616 if (wrapper != null && wrapper.isMatching && wrapper.info != null) { 617 return true; 618 } 619 } 620 return false; 621 } 622 623 @GuardedBy("mLock") isActivityInClientPolicyAllowlistsLocked(String packageName, String className)624 private boolean isActivityInClientPolicyAllowlistsLocked(String packageName, String className) { 625 for (ClientPolicy policy : mClientPolicies.values()) { 626 if (isActivityInMapAndMatching(policy.mAllowlistsMap.get(packageName), packageName, 627 className)) { 628 return true; 629 } 630 } 631 return false; 632 } 633 isActivityInMapAndMatching(AppBlockingPackageInfoWrapper wrapper, String packageName, String className)634 private boolean isActivityInMapAndMatching(AppBlockingPackageInfoWrapper wrapper, 635 String packageName, String className) { 636 if (wrapper == null || !wrapper.isMatching) { 637 if (DBG) { 638 Slogf.d(TAG, "Pkg not in allowlist:" + packageName); 639 } 640 return false; 641 } 642 return wrapper.info.isActivityCovered(className); 643 } 644 645 @Override init()646 public void init() { 647 String safetyRegion = SystemProperties.get(PROPERTY_RO_DRIVING_SAFETY_REGION, ""); 648 synchronized (mLock) { 649 setDrivingSafetyRegionWithCheckLocked(safetyRegion); 650 mHandler.requestInit(); 651 } 652 UserLifecycleEventFilter userSwitchingEventFilter = new UserLifecycleEventFilter.Builder() 653 .addEventType(USER_LIFECYCLE_EVENT_TYPE_SWITCHING).build(); 654 CarLocalServices.getService(CarUserService.class).addUserLifecycleListener( 655 userSwitchingEventFilter, mUserLifecycleListener); 656 CarLocalServices.getService(CarPowerManagementService.class).addPowerPolicyListener( 657 new CarPowerPolicyFilter.Builder().setComponents(PowerComponent.DISPLAY).build(), 658 mDisplayPowerPolicyListener); 659 } 660 661 @Override release()662 public void release() { 663 CarLocalServices.getService(CarPowerManagementService.class).removePowerPolicyListener( 664 mDisplayPowerPolicyListener); 665 CarLocalServices.getService(CarUserService.class).removeUserLifecycleListener( 666 mUserLifecycleListener); 667 synchronized (mLock) { 668 mHandler.requestRelease(); 669 // wait for release do be done. This guarantees that init is done. 670 try { 671 mLock.wait(); 672 } catch (InterruptedException e) { 673 Slogf.e(TAG, "Interrupted wait during release"); 674 Thread.currentThread().interrupt(); 675 } 676 mActivityAllowlistMap.clear(); 677 mActivityDenylistPackages.clear(); 678 mClientPolicies.clear(); 679 mBlockingUiTaskInfoPerDisplay.clear(); 680 if (mProxies != null) { 681 for (AppBlockingPolicyProxy proxy : mProxies) { 682 proxy.disconnect(); 683 } 684 mProxies.clear(); 685 } 686 mWaitingPolicies.clear(); 687 resetTempAllowedActivitiesLocked(); 688 mLock.notifyAll(); 689 } 690 mContext.unregisterReceiver(mPackageParsingEventReceiver); 691 mActivityService.unregisterActivityListener(mActivityListener); 692 synchronized (mLock) { 693 for (int i = 0; i < mUxRestrictionsListeners.size(); i++) { 694 UxRestrictionsListener listener = mUxRestrictionsListeners.valueAt(i); 695 mCarUxRestrictionsService.unregisterUxRestrictionsChangeListener(listener); 696 } 697 } 698 } 699 700 @GuardedBy("mLock") setDrivingSafetyRegionWithCheckLocked(String region)701 private void setDrivingSafetyRegionWithCheckLocked(String region) { 702 if (region.isEmpty()) { 703 mCurrentDrivingSafetyRegion = CarPackageManager.DRIVING_SAFETY_REGION_ALL; 704 } else { 705 mCurrentDrivingSafetyRegion = region; 706 } 707 } 708 709 /** 710 * Reset driving stat and all dynamically added allow list so that region information for 711 * all packages are reset. This also resets one time allow list. 712 */ resetDrivingSafetyRegion(@onNull String region)713 public void resetDrivingSafetyRegion(@NonNull String region) { 714 synchronized (mLock) { 715 setDrivingSafetyRegionWithCheckLocked(region); 716 resetTempAllowedActivitiesLocked(); 717 mActivityAllowlistMap.clear(); 718 mActivityDenylistPackages.clear(); 719 } 720 } 721 722 // run from HandlerThread doHandleInit()723 private void doHandleInit() { 724 startAppBlockingPolicies(); 725 IntentFilter pkgParseIntent = new IntentFilter(); 726 for (String action : mPackageManagerActions) { 727 pkgParseIntent.addAction(action); 728 } 729 pkgParseIntent.addDataScheme("package"); 730 mContext.registerReceiverForAllUsers(mPackageParsingEventReceiver, pkgParseIntent, 731 /* broadcastPermission= */ null, /* scheduler= */ null, 732 Context.RECEIVER_NOT_EXPORTED); 733 734 // Listen to UxR changes on all displays. 735 List<CarOccupantZoneManager.OccupantZoneInfo> occupantZoneInfos = 736 mCarOccupantZoneService.getAllOccupantZones(); 737 synchronized (mLock) { 738 for (int i = 0; i < occupantZoneInfos.size(); i++) { 739 CarOccupantZoneManager.OccupantZoneInfo occupantZoneInfo = 740 occupantZoneInfos.get(i); 741 int zoneId = occupantZoneInfo.zoneId; 742 int[] displayIds = mCarOccupantZoneService.getAllDisplaysForOccupantZone(zoneId); 743 for (int j = 0; j < displayIds.length; j++) { 744 int displayId = displayIds[j]; 745 UxRestrictionsListener listener = new UxRestrictionsListener( 746 mCarUxRestrictionsService, displayId); 747 mUxRestrictionsListeners.put(displayId, listener); 748 mCarUxRestrictionsService.registerUxRestrictionsChangeListener( 749 listener, displayId); 750 } 751 } 752 } 753 754 // Update UxR listeners upon display changes. 755 mCarOccupantZoneService.registerCallback(mOccupantZoneCallback); 756 757 mVendorServiceController.init(); 758 mActivityService.registerActivityListener(mActivityListener); 759 } 760 761 private final ICarOccupantZoneCallback mOccupantZoneCallback = 762 new ICarOccupantZoneCallback.Stub() { 763 @Override 764 public void onOccupantZoneConfigChanged(int flags) throws RemoteException { 765 // Respond to display changes. 766 if ((flags & CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_DISPLAY) == 0) { 767 return; 768 } 769 if (DBG) { 770 String flagString = DebugUtils.flagsToString( 771 CarOccupantZoneManager.class, "ZONE_CONFIG_CHANGE_FLAG_", 772 flags); 773 Slogf.d(TAG, "onOccupantZoneConfigChanged: display zone change flag=%s", 774 flagString); 775 } 776 ArraySet<Integer> updatedDisplayIds = new ArraySet<>(); 777 List<CarOccupantZoneManager.OccupantZoneInfo> occupantZoneInfos = 778 mCarOccupantZoneService.getAllOccupantZones(); 779 780 synchronized (mLock) { 781 for (int i = 0; i < occupantZoneInfos.size(); i++) { 782 CarOccupantZoneManager.OccupantZoneInfo occupantZoneInfo = 783 occupantZoneInfos.get(i); 784 int zoneId = occupantZoneInfo.zoneId; 785 int[] displayIds = 786 mCarOccupantZoneService.getAllDisplaysForOccupantZone(zoneId); 787 for (int j = 0; j < displayIds.length; j++) { 788 int displayId = displayIds[j]; 789 updatedDisplayIds.add(displayId); 790 // Register UxR listener for newly added displays. 791 if (mUxRestrictionsListeners.get(displayId) == null) { 792 Slogf.d(TAG, "adding UxR listener for display %d", displayId); 793 UxRestrictionsListener listener = new UxRestrictionsListener( 794 mCarUxRestrictionsService, displayId); 795 mUxRestrictionsListeners.put(displayId, listener); 796 mCarUxRestrictionsService.registerUxRestrictionsChangeListener( 797 listener, displayId); 798 } 799 } 800 } 801 802 // Remove UxR listener for removed displays. 803 for (int i = 0; i < mUxRestrictionsListeners.size(); i++) { 804 int displayId = mUxRestrictionsListeners.keyAt(i); 805 if (!updatedDisplayIds.contains(displayId)) { 806 UxRestrictionsListener listener = 807 mUxRestrictionsListeners.valueAt(i); 808 mCarUxRestrictionsService.unregisterUxRestrictionsChangeListener( 809 listener); 810 mUxRestrictionsListeners.remove(displayId); 811 } 812 } 813 } 814 } 815 }; 816 doParseInstalledPackage(String packageName)817 private void doParseInstalledPackage(String packageName) { 818 // Delete the package from allowlist and denylist mapping 819 synchronized (mLock) { 820 mActivityDenylistPackages.remove(packageName); 821 mActivityAllowlistMap.remove(packageName); 822 } 823 824 // Generate allowlist and denylist mapping for the package 825 updateActivityAllowlistAndDenylistMap(packageName); 826 mHandler.post(this::blockTopActivitiesOnAllDisplaysIfNecessary); 827 } 828 doHandleRelease()829 private void doHandleRelease() { 830 synchronized (mLock) { 831 mVendorServiceController.release(); 832 mLock.notifyAll(); 833 } 834 } 835 doUpdatePolicy(String packageName, CarAppBlockingPolicy policy, int flags)836 private void doUpdatePolicy(String packageName, CarAppBlockingPolicy policy, int flags) { 837 if (DBG) { 838 Slogf.d(TAG, "setting policy from:" + packageName + ",policy:" + policy + ",flags:0x" 839 + Integer.toHexString(flags)); 840 } 841 AppBlockingPackageInfoWrapper[] blocklistWrapper = verifyList(policy.blacklists); 842 AppBlockingPackageInfoWrapper[] allowlistWrapper = verifyList(policy.whitelists); 843 synchronized (mLock) { 844 ClientPolicy clientPolicy = mClientPolicies.get(packageName); 845 if (clientPolicy == null) { 846 clientPolicy = new ClientPolicy(); 847 mClientPolicies.put(packageName, clientPolicy); 848 } 849 if ((flags & CarPackageManager.FLAG_SET_POLICY_ADD) != 0) { 850 clientPolicy.addToBlocklists(blocklistWrapper); 851 clientPolicy.addToAllowlists(allowlistWrapper); 852 } else if ((flags & CarPackageManager.FLAG_SET_POLICY_REMOVE) != 0) { 853 clientPolicy.removeBlocklists(blocklistWrapper); 854 clientPolicy.removeAllowlists(allowlistWrapper); 855 } else { //replace. 856 clientPolicy.replaceBlocklists(blocklistWrapper); 857 clientPolicy.replaceAllowlists(allowlistWrapper); 858 } 859 if ((flags & CarPackageManager.FLAG_SET_POLICY_WAIT_FOR_CHANGE) != 0) { 860 mWaitingPolicies.remove(policy); 861 mLock.notifyAll(); 862 } 863 if (DBG) { 864 Slogf.d(TAG, "policy set:" + dumpPoliciesLocked(false)); 865 } 866 } 867 mHandler.post(this::blockTopActivitiesOnAllDisplaysIfNecessary); 868 } 869 870 @Nullable verifyList(@ullable AppBlockingPackageInfo[] list)871 private AppBlockingPackageInfoWrapper[] verifyList(@Nullable AppBlockingPackageInfo[] list) { 872 if (list == null) { 873 return null; 874 } 875 LinkedList<AppBlockingPackageInfoWrapper> wrappers = new LinkedList<>(); 876 for (int i = 0; i < list.length; i++) { 877 AppBlockingPackageInfo info = list[i]; 878 if (info == null) { 879 continue; 880 } 881 boolean isMatching = isInstalledPackageMatching(info); 882 wrappers.add(new AppBlockingPackageInfoWrapper(info, isMatching)); 883 } 884 return wrappers.toArray(new AppBlockingPackageInfoWrapper[wrappers.size()]); 885 } 886 isInstalledPackageMatching(AppBlockingPackageInfo info)887 boolean isInstalledPackageMatching(AppBlockingPackageInfo info) { 888 PackageInfo packageInfo; 889 try { 890 packageInfo = mPackageManager.getPackageInfo(info.packageName, 891 PackageManager.GET_SIGNATURES); 892 } catch (NameNotFoundException e) { 893 return false; 894 } 895 if (packageInfo == null) { 896 return false; 897 } 898 // if it is system app and client specified the flag, do not check signature 899 if ((info.flags & AppBlockingPackageInfo.FLAG_SYSTEM_APP) == 0 || 900 (!PackageManagerHelper.isSystemApp(packageInfo.applicationInfo) 901 && !PackageManagerHelper.isUpdatedSystemApp(packageInfo.applicationInfo))) { 902 Signature[] signatures = packageInfo.signatures; 903 if (!isAnySignatureMatching(signatures, info.signatures)) { 904 return false; 905 } 906 } 907 int version = packageInfo.versionCode; 908 if (info.minRevisionCode == 0) { 909 if (info.maxRevisionCode == 0) { // all versions 910 return true; 911 } else { // only max version matters 912 return info.maxRevisionCode > version; 913 } 914 } else { // min version matters 915 if (info.maxRevisionCode == 0) { 916 return info.minRevisionCode < version; 917 } else { 918 return (info.minRevisionCode < version) && (info.maxRevisionCode > version); 919 } 920 } 921 } 922 923 /** 924 * Any signature from policy matching with package's signatures is treated as matching. 925 */ isAnySignatureMatching(Signature[] fromPackage, Signature[] fromPolicy)926 boolean isAnySignatureMatching(Signature[] fromPackage, Signature[] fromPolicy) { 927 if (fromPackage == null) { 928 return false; 929 } 930 if (fromPolicy == null) { 931 return false; 932 } 933 ArraySet<Signature> setFromPackage = new ArraySet<Signature>(); 934 for (Signature sig : fromPackage) { 935 setFromPackage.add(sig); 936 } 937 for (Signature sig : fromPolicy) { 938 if (setFromPackage.contains(sig)) { 939 return true; 940 } 941 } 942 return false; 943 } 944 getPackageInfoWrapperForUser(String packageName, @UserIdInt int userId, Map<String, Set<String>> configAllowlist, Map<String, Set<String>> configBlocklist)945 private AppBlockingPackageInfoWrapper getPackageInfoWrapperForUser(String packageName, 946 @UserIdInt int userId, Map<String, Set<String>> configAllowlist, 947 Map<String, Set<String>> configBlocklist) { 948 PackageInfo info; 949 try { 950 info = PackageManagerHelper.getPackageInfoAsUser(mPackageManager, packageName, 951 PackageManager.GET_SIGNATURES | PackageManager.GET_ACTIVITIES 952 | PackageManager.MATCH_DIRECT_BOOT_AWARE 953 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE 954 | PackageManager.MATCH_DISABLED_COMPONENTS, 955 userId); 956 } catch (NameNotFoundException e) { 957 Slogf.w(TAG, packageName + " not installed! User Id: " + userId); 958 return null; 959 } 960 961 962 if (info == null || info.applicationInfo == null) { 963 return null; 964 } 965 966 int flags = 0; 967 Set<String> activities = new ArraySet<>(); 968 969 if (PackageManagerHelper.isSystemApp(info.applicationInfo) 970 || PackageManagerHelper.isUpdatedSystemApp(info.applicationInfo)) { 971 flags = AppBlockingPackageInfo.FLAG_SYSTEM_APP; 972 } 973 974 /* 1. Check if all or some of this app is in the <activityAllowlist> or 975 <systemActivityAllowlist> in config.xml */ 976 Set<String> configActivitiesForPackage = configAllowlist.get(info.packageName); 977 if (configActivitiesForPackage != null) { 978 if (DBG) { 979 Slogf.d(TAG, info.packageName + " allowlisted"); 980 } 981 982 if (configActivitiesForPackage.isEmpty()) { 983 // Whole Pkg has been allowlisted 984 flags |= AppBlockingPackageInfo.FLAG_WHOLE_ACTIVITY; 985 // Add all activities to the allowlist 986 List<String> activitiesForPackage = getActivitiesInPackage(info); 987 if (activitiesForPackage != null) { 988 activities.addAll(activitiesForPackage); 989 } else { 990 if (DBG) { 991 Slogf.d(TAG, info.packageName + ": Activities null"); 992 } 993 } 994 } else { 995 if (DBG) { 996 Slogf.d(TAG, "Partially Allowlisted. WL Activities: " 997 + configActivitiesForPackage); 998 } 999 activities.addAll(configActivitiesForPackage); 1000 } 1001 } 1002 /* 2. If app is not listed in the config.xml check their Manifest meta-data to see if 1003 they have any Distraction Optimized(DO) activities. For non system apps, we check if the 1004 app install source was a permissible source. This prevents side-loaded apps to fake DO. 1005 Bypass the check for debug builds for development convenience. The check for activities 1006 which are already allowlisted in the config can be bypassed since the config can only be 1007 modified by the OEMs, so side-loading does not matter for such a case. */ 1008 if (!isDebugBuild() && configActivitiesForPackage == null 1009 && !PackageManagerHelper.isSystemApp(info.applicationInfo) 1010 && !PackageManagerHelper.isUpdatedSystemApp(info.applicationInfo)) { 1011 try { 1012 if (mAllowedAppInstallSources != null) { 1013 String installerName = mPackageManager.getInstallerPackageName( 1014 info.packageName); 1015 if (installerName == null || (installerName != null 1016 && !mAllowedAppInstallSources.contains(installerName))) { 1017 Slogf.w(TAG, info.packageName + " not installed from permitted sources " 1018 + (installerName == null ? "NULL" : installerName)); 1019 return null; 1020 } 1021 } 1022 } catch (IllegalArgumentException e) { 1023 Slogf.w(TAG, info.packageName + " not installed!"); 1024 return null; 1025 } 1026 } 1027 1028 try { 1029 String[] doActivities = findDistractionOptimizedActivitiesAsUser(info.packageName, 1030 userId); 1031 if (doActivities != null) { 1032 // Some of the activities in this app are Distraction Optimized. 1033 if (DBG) { 1034 for (String activity : doActivities) { 1035 Slogf.d(TAG, "adding " + activity + " from " + info.packageName 1036 + " to allowlist"); 1037 } 1038 } 1039 1040 activities.addAll(Arrays.asList(doActivities)); 1041 } 1042 } catch (NameNotFoundException e) { 1043 Slogf.w(TAG, "Error reading metadata: " + info.packageName); 1044 return null; 1045 } 1046 1047 // Nothing to add to allowlist 1048 if (activities.isEmpty()) { 1049 return null; 1050 } 1051 1052 /* 3. Check if parsed activity is in <activityBlocklist> in config.xml. Anything 1053 in blocklist should not be allowlisted, either as D.O. or by config. */ 1054 if (configBlocklist.containsKey(info.packageName)) { 1055 Set<String> configBlocklistActivities = configBlocklist.get(info.packageName); 1056 if (configBlocklistActivities.isEmpty()) { 1057 // Whole package should be blocklisted. 1058 return null; 1059 } 1060 activities.removeAll(configBlocklistActivities); 1061 } 1062 1063 Signature[] signatures; 1064 signatures = info.signatures; 1065 AppBlockingPackageInfo appBlockingInfo = new AppBlockingPackageInfo(info.packageName, 1066 /* minRevisionCode = */ 0, /* maxRevisionCode = */ 0, flags, signatures, 1067 activities.toArray(new String[activities.size()])); 1068 AppBlockingPackageInfoWrapper wrapper = new AppBlockingPackageInfoWrapper( 1069 appBlockingInfo, true); 1070 return wrapper; 1071 } 1072 1073 /** 1074 * Update map of allowlisted packages and activities of the form {pkgName, Allowlisted 1075 * activities} and set of denylisted packages. The information can come from a configuration XML 1076 * resource or from the apps marking their activities as distraction optimized. 1077 */ updateActivityAllowlistAndDenylistMap(String packageName)1078 private void updateActivityAllowlistAndDenylistMap(String packageName) { 1079 int userId = mActivityManager.getCurrentUser(); 1080 Slogf.d(TAG, "Updating allowlist and denylist mapping for package: " + packageName 1081 + " for UserId: " + userId); 1082 // Get the apps/activities that are allowlisted in the configuration XML resources. 1083 Map<String, Set<String>> configAllowlist = generateConfigAllowlist(); 1084 Map<String, Set<String>> configBlocklist = generateConfigBlocklist(); 1085 1086 AppBlockingPackageInfoWrapper wrapper = 1087 getPackageInfoWrapperForUser(packageName, userId, configAllowlist, configBlocklist); 1088 1089 if (wrapper == null && userId != UserHandle.SYSTEM.getIdentifier()) { 1090 Slogf.d(TAG, "Updating allowlist and denylist mapping for package: " + packageName 1091 + " for UserId: " + UserHandle.SYSTEM.getIdentifier()); 1092 // check package for system user, in case package is disabled for current user 1093 wrapper = getPackageInfoWrapperForUser(packageName, UserHandle.SYSTEM.getIdentifier(), 1094 configAllowlist, configBlocklist); 1095 } 1096 1097 synchronized (mLock) { 1098 if (wrapper != null) { 1099 if (DBG) { 1100 Slogf.d(TAG, "Package: " + packageName + " added in allowlist."); 1101 } 1102 mActivityAllowlistMap.put(packageName, wrapper); 1103 } else { 1104 if (DBG) { 1105 Slogf.d(TAG, "Package: " + packageName + " added in denylist."); 1106 } 1107 mActivityDenylistPackages.add(packageName); 1108 } 1109 } 1110 } 1111 generateConfigAllowlist()1112 private Map<String, Set<String>> generateConfigAllowlist() { 1113 synchronized (mLock) { 1114 if (mConfiguredAllowlistMap != null) return mConfiguredAllowlistMap; 1115 1116 Map<String, Set<String>> configAllowlist = new HashMap<>(); 1117 mConfiguredAllowlist = mContext.getString(R.string.activityAllowlist); 1118 if (mConfiguredAllowlist == null) { 1119 Slogf.w(TAG, "Allowlist is null."); 1120 } 1121 parseConfigList(mConfiguredAllowlist, configAllowlist); 1122 1123 mConfiguredSystemAllowlist = mContext.getString(R.string.systemActivityAllowlist); 1124 if (mConfiguredSystemAllowlist == null) { 1125 Slogf.w(TAG, "System allowlist is null."); 1126 } 1127 parseConfigList(mConfiguredSystemAllowlist, configAllowlist); 1128 1129 // Add the blocking overlay activity to the allowlist, since that needs to run in a 1130 // restricted state to communicate the reason an app was blocked. 1131 Set<String> defaultActivity = new ArraySet<>(); 1132 if (mActivityBlockingActivity != null) { 1133 defaultActivity.add(mActivityBlockingActivity.getClassName()); 1134 configAllowlist.put(mActivityBlockingActivity.getPackageName(), defaultActivity); 1135 } 1136 1137 mConfiguredAllowlistMap = configAllowlist; 1138 return configAllowlist; 1139 } 1140 } 1141 generateConfigBlocklist()1142 private Map<String, Set<String>> generateConfigBlocklist() { 1143 synchronized (mLock) { 1144 if (mConfiguredBlocklistMap != null) return mConfiguredBlocklistMap; 1145 1146 Map<String, Set<String>> configBlocklist = new HashMap<>(); 1147 mConfiguredBlocklist = mContext.getString(R.string.activityDenylist); 1148 if (mConfiguredBlocklist == null) { 1149 if (DBG) { 1150 Slogf.d(TAG, "Null blocklist in config"); 1151 } 1152 } 1153 parseConfigList(mConfiguredBlocklist, configBlocklist); 1154 1155 mConfiguredBlocklistMap = configBlocklist; 1156 return configBlocklist; 1157 } 1158 } 1159 isDebugBuild()1160 private boolean isDebugBuild() { 1161 return BuildHelper.isUserDebugBuild() || BuildHelper.isEngBuild(); 1162 } 1163 1164 /** 1165 * Parses the given resource and updates the input map of packages and activities. 1166 * 1167 * Key is package name and value is list of activities. Empty set implies whole package is 1168 * included. 1169 * 1170 * When there are multiple entries regarding one package, the entry with 1171 * greater scope wins. Namely if there were 2 entries such that one allowlists 1172 * an activity, and the other allowlists the entire package of the activity, 1173 * the package is allowlisted, regardless of input order. 1174 */ 1175 @VisibleForTesting parseConfigList(String configList, @NonNull Map<String, Set<String>> packageToActivityMap)1176 /* package */ void parseConfigList(String configList, 1177 @NonNull Map<String, Set<String>> packageToActivityMap) { 1178 if (configList == null) { 1179 return; 1180 } 1181 String[] entries = configList.split(PACKAGE_DELIMITER); 1182 for (String entry : entries) { 1183 String[] packageActivityPair = entry.split(PACKAGE_ACTIVITY_DELIMITER); 1184 Set<String> activities = packageToActivityMap.get(packageActivityPair[0]); 1185 boolean newPackage = false; 1186 if (activities == null) { 1187 activities = new ArraySet<>(); 1188 newPackage = true; 1189 packageToActivityMap.put(packageActivityPair[0], activities); 1190 } 1191 if (packageActivityPair.length == 1) { // whole package 1192 activities.clear(); 1193 } else if (packageActivityPair.length == 2) { 1194 // add class name only when the whole package is not allowlisted. 1195 if (newPackage || (activities.size() > 0)) { 1196 activities.add(packageActivityPair[1]); 1197 } 1198 } 1199 } 1200 } 1201 1202 @Nullable getActivitiesInPackage(PackageInfo info)1203 private List<String> getActivitiesInPackage(PackageInfo info) { 1204 if (info == null || info.activities == null) { 1205 return null; 1206 } 1207 List<String> activityList = new ArrayList<>(); 1208 for (ActivityInfo aInfo : info.activities) { 1209 activityList.add(aInfo.name); 1210 } 1211 return activityList; 1212 } 1213 1214 /** 1215 * Checks if there are any {@link CarAppBlockingPolicyService} and creates a proxy to 1216 * bind to them and retrieve the {@link CarAppBlockingPolicy} 1217 */ 1218 @VisibleForTesting startAppBlockingPolicies()1219 public void startAppBlockingPolicies() { 1220 Intent policyIntent = new Intent(); 1221 policyIntent.setAction(CarAppBlockingPolicyService.SERVICE_INTERFACE); 1222 List<ResolveInfo> policyInfos = mPackageManager.queryIntentServices(policyIntent, 0); 1223 if (policyInfos == null) { //no need to wait for service binding and retrieval. 1224 return; 1225 } 1226 LinkedList<AppBlockingPolicyProxy> proxies = new LinkedList<>(); 1227 for (ResolveInfo resolveInfo : policyInfos) { 1228 ServiceInfo serviceInfo = resolveInfo.serviceInfo; 1229 if (serviceInfo == null) { 1230 continue; 1231 } 1232 if (serviceInfo.isEnabled()) { 1233 if (mPackageManager.checkPermission(Car.PERMISSION_CONTROL_APP_BLOCKING, 1234 serviceInfo.packageName) != PackageManager.PERMISSION_GRANTED) { 1235 continue; 1236 } 1237 Slogf.i(TAG, "found policy holding service:" + serviceInfo); 1238 AppBlockingPolicyProxy proxy = new AppBlockingPolicyProxy(this, mContext, 1239 serviceInfo); 1240 proxy.connect(); 1241 proxies.add(proxy); 1242 } 1243 } 1244 synchronized (mLock) { 1245 mProxies = proxies; 1246 } 1247 } 1248 onPolicyConnectionAndSet(AppBlockingPolicyProxy proxy, CarAppBlockingPolicy policy)1249 public void onPolicyConnectionAndSet(AppBlockingPolicyProxy proxy, 1250 CarAppBlockingPolicy policy) { 1251 doHandlePolicyConnection(proxy, policy); 1252 } 1253 onPolicyConnectionFailure(AppBlockingPolicyProxy proxy)1254 public void onPolicyConnectionFailure(AppBlockingPolicyProxy proxy) { 1255 doHandlePolicyConnection(proxy, null); 1256 } 1257 doHandlePolicyConnection(AppBlockingPolicyProxy proxy, CarAppBlockingPolicy policy)1258 private void doHandlePolicyConnection(AppBlockingPolicyProxy proxy, 1259 CarAppBlockingPolicy policy) { 1260 synchronized (mLock) { 1261 if (mProxies == null) { 1262 proxy.disconnect(); 1263 return; 1264 } 1265 mProxies.remove(proxy); 1266 if (mProxies.size() == 0) { 1267 mProxies = null; 1268 } 1269 } 1270 try { 1271 if (policy != null) { 1272 if (DBG) { 1273 Slogf.d(TAG, "policy setting from policy service:" + proxy.getPackageName()); 1274 } 1275 doSetAppBlockingPolicy(proxy.getPackageName(), policy, 0); 1276 } 1277 } finally { 1278 proxy.disconnect(); 1279 } 1280 } 1281 1282 @Override 1283 @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO) dump(IndentingPrintWriter writer)1284 public void dump(IndentingPrintWriter writer) { 1285 synchronized (mLock) { 1286 writer.println("*CarPackageManagerService*"); 1287 writer.println("mEnableActivityBlocking:" + mEnableActivityBlocking); 1288 writer.println("mPreventTemplatedAppsFromShowingDialog:" 1289 + mPreventTemplatedAppsFromShowingDialog); 1290 writer.println("mTemplateActivityClassName:" + mTemplateActivityClassName); 1291 List<String> restrictions = new ArrayList<>(mUxRestrictionsListeners.size()); 1292 for (int i = 0; i < mUxRestrictionsListeners.size(); i++) { 1293 int displayId = mUxRestrictionsListeners.keyAt(i); 1294 UxRestrictionsListener listener = mUxRestrictionsListeners.valueAt(i); 1295 restrictions.add(String.format("Display %d is %s", 1296 displayId, (listener.isRestricted() ? "restricted" : "unrestricted"))); 1297 } 1298 writer.println("Display Restrictions:\n" + String.join("\n", restrictions)); 1299 writer.println(" Blocked activity log:"); 1300 mBlockedActivityLogs.dump(writer); 1301 writer.print(dumpPoliciesLocked(true)); 1302 writer.print("mCurrentDrivingSafetyRegion:"); 1303 writer.println(mCurrentDrivingSafetyRegion); 1304 writer.print("mTempAllowedActivities:"); 1305 writer.println(mTempAllowedActivities); 1306 writer.println("Car service overlay packages property name: " 1307 + PackageManagerHelper.PROPERTY_CAR_SERVICE_OVERLAY_PACKAGES); 1308 writer.println("Car service overlay packages: " 1309 + SystemProperties.get( 1310 PackageManagerHelper.PROPERTY_CAR_SERVICE_OVERLAY_PACKAGES, 1311 /* default= */ null)); 1312 mVendorServiceController.dump(writer); 1313 mBlockingUiCommandListenerMediator.dump(writer); 1314 } 1315 } 1316 1317 @Override 1318 @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO) dumpProto(ProtoOutputStream proto)1319 public void dumpProto(ProtoOutputStream proto) {} 1320 1321 @GuardedBy("mLock") dumpPoliciesLocked(boolean dumpAll)1322 private String dumpPoliciesLocked(boolean dumpAll) { 1323 StringBuilder sb = new StringBuilder(); 1324 if (dumpAll) { 1325 sb.append("**System allowlist**\n"); 1326 for (AppBlockingPackageInfoWrapper wrapper : mActivityAllowlistMap.values()) { 1327 sb.append(wrapper.toString() + "\n"); 1328 } 1329 } 1330 sb.append("**Client Policies**\n"); 1331 for (Entry<String, ClientPolicy> entry : mClientPolicies.entrySet()) { 1332 sb.append("Client:" + entry.getKey() + "\n"); 1333 sb.append(" allowlists:\n"); 1334 for (AppBlockingPackageInfoWrapper wrapper : entry.getValue().mAllowlistsMap.values()) { 1335 sb.append(wrapper.toString() + "\n"); 1336 } 1337 sb.append(" blocklists:\n"); 1338 for (AppBlockingPackageInfoWrapper wrapper : entry.getValue().mBlocklistsMap.values()) { 1339 sb.append(wrapper.toString() + "\n"); 1340 } 1341 } 1342 sb.append("**Unprocessed policy services**\n"); 1343 if (mProxies != null) { 1344 for (AppBlockingPolicyProxy proxy : mProxies) { 1345 sb.append(proxy.toString() + "\n"); 1346 } 1347 } 1348 sb.append("**Allowlist string in resource**\n"); 1349 sb.append(mConfiguredAllowlist + "\n"); 1350 1351 sb.append("**System allowlist string in resource**\n"); 1352 sb.append(mConfiguredSystemAllowlist + "\n"); 1353 1354 sb.append("**Blocklist string in resource**\n"); 1355 sb.append(mConfiguredBlocklist + "\n"); 1356 1357 sb.append("**Allowlist map from resource**\n"); 1358 sb.append(mConfiguredAllowlistMap + "\n"); 1359 1360 sb.append("**Blocklist from resource**\n"); 1361 sb.append(mConfiguredBlocklist + "\n"); 1362 1363 return sb.toString(); 1364 } 1365 1366 /** 1367 * Returns whether UX restrictions is required for the given display. 1368 * 1369 * Non-physical display will use restrictions for {@link Display#DEFAULT_DISPLAY}. 1370 */ isUxRestrictedOnDisplay(int displayId)1371 private boolean isUxRestrictedOnDisplay(int displayId) { 1372 UxRestrictionsListener listenerForTopTaskDisplay; 1373 synchronized (mLock) { 1374 if (mUxRestrictionsListeners.indexOfKey(displayId) < 0) { 1375 Slogf.w(TAG, 1376 "Cannot find UxR listener for display %d, using UxR on default display", 1377 displayId); 1378 listenerForTopTaskDisplay = mUxRestrictionsListeners.get(Display.DEFAULT_DISPLAY); 1379 if (listenerForTopTaskDisplay == null) { 1380 // This should never happen. 1381 Slogf.e(TAG, "Missing listener for default display."); 1382 return true; 1383 } 1384 } else { 1385 listenerForTopTaskDisplay = mUxRestrictionsListeners.get(displayId); 1386 } 1387 } 1388 1389 return listenerForTopTaskDisplay.isRestricted(); 1390 } 1391 1392 /** 1393 * Blocks top activities on all displays if necessary. 1394 */ blockTopActivitiesOnAllDisplaysIfNecessary()1395 private void blockTopActivitiesOnAllDisplaysIfNecessary() { 1396 List<? extends TaskInfo> visibleTasks = mActivityService.getVisibleTasksInternal(); 1397 ArrayList<Integer> restrictedDisplayIds = new ArrayList<>(); 1398 synchronized (mLock) { 1399 for (int i = 0; i < mUxRestrictionsListeners.size(); i++) { 1400 int displayId = mUxRestrictionsListeners.keyAt(i); 1401 UxRestrictionsListener listener = mUxRestrictionsListeners.valueAt(i); 1402 if (listener.isRestricted()) { 1403 if (DBG) { 1404 Slogf.d(TAG, "Display %d is in a UxRestricted state.", 1405 displayId); 1406 } 1407 restrictedDisplayIds.add(displayId); 1408 } else { 1409 if (DBG) { 1410 Slogf.d(TAG, "Display %d is not in a UxRestricted state, not blocking.", 1411 displayId); 1412 } 1413 } 1414 } 1415 } 1416 1417 // Block activities on a display if it is in a Ux restricted state. 1418 for (int i = 0; i < restrictedDisplayIds.size(); i++) { 1419 int displayId = restrictedDisplayIds.get(i); 1420 if (DBG) { 1421 Slogf.d(TAG, "Initiating activity blocking on display %d.", displayId); 1422 } 1423 blockTopActivitiesOnDisplayIfNecessary(visibleTasks, displayId); 1424 } 1425 } 1426 1427 /** 1428 * Blocks top activities on the given display if necessary. 1429 */ blockTopActivitiesOnDisplayIfNecessary(List<? extends TaskInfo> visibleTasks, int displayId)1430 private void blockTopActivitiesOnDisplayIfNecessary(List<? extends TaskInfo> visibleTasks, 1431 int displayId) { 1432 Set<Integer> rootTasksBlocked = new ArraySet<>(); 1433 for (TaskInfo topTask : visibleTasks) { 1434 if (topTask == null) { 1435 Slogf.e(TAG, "Top tasks contains null."); 1436 continue; 1437 } 1438 1439 int displayIdOfTask = TaskInfoHelper.getDisplayId(topTask); 1440 if (displayIdOfTask != displayId) { 1441 // Only block activities on the given display. Skip if it's not the given 1442 // display. 1443 continue; 1444 } 1445 1446 if (rootTasksBlocked.contains(TaskInfoHelper.geParentTaskId(topTask))) { 1447 // Root task already blocked. No need to launch another ABA 1448 if (DBG) { 1449 Slogf.d(TAG, "Root task %d has already been blocked.", 1450 TaskInfoHelper.geParentTaskId(topTask)); 1451 } 1452 continue; 1453 } 1454 1455 boolean blocked = blockTopActivity(topTask); 1456 if (blocked) { 1457 if (DBG) { 1458 Slogf.d(TAG, "Display %d has been blocked. Root task id: %d", 1459 displayIdOfTask, TaskInfoHelper.geParentTaskId(topTask)); 1460 } 1461 // When root tasks are not used, the value of parent root task would be -1. 1462 // It is okay to add it to this list as it would help to skip all the tasks 1463 // which are blocked but not parented to root task. 1464 rootTasksBlocked.add(TaskInfoHelper.geParentTaskId(topTask)); 1465 } 1466 } 1467 } 1468 1469 /** 1470 * Blocks the top activity if it's on a Ux restricted display. 1471 * 1472 * @return {@code true} if the {@code topTask} was blocked, {@code false} otherwise. 1473 */ blockTopActivityIfNecessary(TaskInfo topTask)1474 private boolean blockTopActivityIfNecessary(TaskInfo topTask) { 1475 int displayId = TaskInfoHelper.getDisplayId(topTask); 1476 synchronized (mLock) { 1477 if (!Objects.equals(mActivityBlockingActivity, topTask.topActivity) 1478 && mTopActivityWithDialogPerDisplay.contains(displayId) 1479 && !topTask.topActivity.equals( 1480 mTopActivityWithDialogPerDisplay.get(displayId))) { 1481 // Clear top activity-with-dialog if the activity has changed on this display. 1482 mTopActivityWithDialogPerDisplay.remove(displayId); 1483 } 1484 } 1485 if (isUxRestrictedOnDisplay(displayId)) { 1486 return doBlockTopActivityIfNotAllowed(displayId, topTask); 1487 } 1488 return false; 1489 } 1490 1491 /** 1492 * Blocks the top activity if not allowed. 1493 * 1494 * @return {@code true} if the {@code topTask} was blocked, {@code false} otherwise. 1495 */ blockTopActivity(TaskInfo topTask)1496 private boolean blockTopActivity(TaskInfo topTask) { 1497 int displayId = TaskInfoHelper.getDisplayId(topTask); 1498 synchronized (mLock) { 1499 if (!Objects.equals(mActivityBlockingActivity, topTask.topActivity) 1500 && mTopActivityWithDialogPerDisplay.contains(displayId) 1501 && !topTask.topActivity.equals( 1502 mTopActivityWithDialogPerDisplay.get(displayId))) { 1503 // Clear top activity-with-dialog if the activity has changed on this display. 1504 mTopActivityWithDialogPerDisplay.remove(displayId); 1505 } 1506 } 1507 1508 return doBlockTopActivityIfNotAllowed(displayId, topTask); 1509 } 1510 1511 /** 1512 * @return {@code true} if the {@code topTask} was blocked, {@code false} otherwise. 1513 */ doBlockTopActivityIfNotAllowed(int displayId, TaskInfo topTask)1514 private boolean doBlockTopActivityIfNotAllowed(int displayId, TaskInfo topTask) { 1515 if (isBlockingUiTask(topTask)) { 1516 // If topTask is already ActivityBlockingActivity, treat it as already blocked. 1517 return true; 1518 } 1519 boolean allowed = isActivityAllowed(topTask); 1520 if (DBG) { 1521 Slogf.d(TAG, "new activity:" + topTask.toString() + " allowed:" + allowed); 1522 } 1523 if (allowed) { 1524 return false; 1525 } 1526 if (!mEnableActivityBlocking) { 1527 Slogf.d(TAG, "Current activity " + topTask.topActivity 1528 + " not allowed, blocking disabled."); 1529 return false; 1530 } 1531 if (DBG) { 1532 Slogf.d(TAG, "Current activity " + topTask.topActivity 1533 + " not allowed, will block."); 1534 } 1535 // TaskMonitor based on TaskOrganizer reflects only the actually launched tasks, 1536 // (TaskStackChangeListener reflects the internal state of ActivityTaskManagerService) 1537 // So it takes some time to recognize the ActivityBlockingActivity is shown. 1538 // This guard is to prevent from launching ABA repeatedly until it is shown. 1539 TaskInfo blockingActivityTarget = mBlockingActivityTargets.get(displayId); 1540 if (blockingActivityTarget != null && topTask.taskId == blockingActivityTarget.taskId) { 1541 long blockingActivityLaunchTime = mBlockingActivityLaunchTimes.get(displayId); 1542 if (SystemClock.uptimeMillis() - blockingActivityLaunchTime < ABA_LAUNCH_TIMEOUT_MS) { 1543 Slogf.d(TAG, "Waiting for BlockingActivity to be shown: displayId=%d", displayId); 1544 return false; 1545 } 1546 } 1547 1548 // Figure out the root task of blocked task. 1549 ComponentName rootTaskActivityName = topTask.baseActivity; 1550 1551 boolean isRootDO = false; 1552 if (rootTaskActivityName != null) { 1553 isRootDO = isActivityDistractionOptimized( 1554 rootTaskActivityName.getPackageName(), rootTaskActivityName.getClassName()); 1555 } 1556 1557 Intent newActivityIntent = createBlockingActivityIntent( 1558 mActivityBlockingActivity, TaskInfoHelper.getDisplayId(topTask), 1559 topTask.topActivity.flattenToShortString(), topTask.taskId, 1560 rootTaskActivityName.flattenToString(), isRootDO); 1561 1562 // Intent contains all info to debug what is blocked - log into both logcat and dumpsys. 1563 String log = "Starting blocking activity with intent: " + newActivityIntent.toUri(0); 1564 if (Slogf.isLoggable(TAG, Log.INFO)) { 1565 Slogf.i(TAG, log); 1566 } 1567 mBlockedActivityLogs.log(log); 1568 mBlockingActivityLaunchTimes.put(displayId, SystemClock.uptimeMillis()); 1569 mBlockingActivityTargets.put(displayId, topTask); 1570 mActivityService.blockActivity(topTask, newActivityIntent); 1571 return true; 1572 } 1573 isActivityAllowed(TaskInfo topTaskInfoContainer)1574 private boolean isActivityAllowed(TaskInfo topTaskInfoContainer) { 1575 ComponentName activityName = topTaskInfoContainer.topActivity; 1576 boolean isDistractionOptimized = isActivityDistractionOptimized( 1577 activityName.getPackageName(), 1578 activityName.getClassName()); 1579 if (!isDistractionOptimized) { 1580 return false; 1581 } 1582 return !(mPreventTemplatedAppsFromShowingDialog 1583 && isTemplateActivity(activityName) 1584 && isActivityShowingADialogOnDisplay(activityName, 1585 TaskInfoHelper.getDisplayId(topTaskInfoContainer))); 1586 } 1587 isTemplateActivity(ComponentName activityName)1588 private boolean isTemplateActivity(ComponentName activityName) { 1589 // TODO(b/191263486): Finalise on how to detect the templated activities. 1590 return activityName.getClassName().equals(mTemplateActivityClassName); 1591 } 1592 isActivityShowingADialogOnDisplay(ComponentName activityName, int displayId)1593 private boolean isActivityShowingADialogOnDisplay(ComponentName activityName, int displayId) { 1594 String output = dumpWindows(); 1595 List<WindowDumpParser.Window> appWindows = 1596 WindowDumpParser.getParsedAppWindows(output, activityName.getPackageName()); 1597 // TODO(b/192354699): Handle case where an activity can have multiple instances on the same 1598 // display. 1599 int totalAppWindows = appWindows.size(); 1600 String firstActivityRecord = null; 1601 int numTopActivityAppWindowsOnDisplay = 0; 1602 for (int i = 0; i < totalAppWindows; i++) { 1603 WindowDumpParser.Window appWindow = appWindows.get(i); 1604 if (appWindow.getDisplayId() != displayId) { 1605 continue; 1606 } 1607 if (TextUtils.isEmpty(appWindow.getActivityRecord())) { 1608 continue; 1609 } 1610 if (firstActivityRecord == null) { 1611 firstActivityRecord = appWindow.getActivityRecord(); 1612 } 1613 if (firstActivityRecord.equals(appWindow.getActivityRecord())) { 1614 numTopActivityAppWindowsOnDisplay++; 1615 } 1616 } 1617 Slogf.d(TAG, "Top activity = " + activityName); 1618 Slogf.d(TAG, "Number of app widows of top activity = " + numTopActivityAppWindowsOnDisplay); 1619 boolean isShowingADialog = numTopActivityAppWindowsOnDisplay > 1; 1620 synchronized (mLock) { 1621 if (isShowingADialog) { 1622 mTopActivityWithDialogPerDisplay.put(displayId, activityName); 1623 } else { 1624 mTopActivityWithDialogPerDisplay.remove(displayId); 1625 } 1626 } 1627 return isShowingADialog; 1628 } 1629 dumpWindows()1630 private String dumpWindows() { 1631 try { 1632 ParcelFileDescriptor[] fileDescriptors = ParcelFileDescriptor.createSocketPair(); 1633 mWindowManagerBinder.dump( 1634 fileDescriptors[0].getFileDescriptor(), WINDOW_DUMP_ARGUMENTS); 1635 fileDescriptors[0].close(); 1636 StringBuilder outputBuilder = new StringBuilder(); 1637 try (BufferedReader reader = new BufferedReader( 1638 new FileReader(fileDescriptors[1].getFileDescriptor()))) { 1639 String line; 1640 while ((line = reader.readLine()) != null) { 1641 outputBuilder.append(line).append("\n"); 1642 } 1643 } 1644 fileDescriptors[1].close(); 1645 return outputBuilder.toString(); 1646 } catch (IOException | RemoteException e) { 1647 throw new RuntimeException(e); 1648 } 1649 } 1650 1651 /** 1652 * Creates an intent to start blocking activity. 1653 * 1654 * @param blockingActivity the activity to launch 1655 * @param blockedActivity the activity being blocked 1656 * @param blockedTaskId the blocked task id, which contains the blocked activity 1657 * @param taskRootActivity root activity of the blocked task 1658 * @param isRootDo denotes if the root activity is distraction optimised 1659 * @return an intent to launch the blocking activity. 1660 */ createBlockingActivityIntent(ComponentName blockingActivity, int displayId, String blockedActivity, int blockedTaskId, String taskRootActivity, boolean isRootDo)1661 private static Intent createBlockingActivityIntent(ComponentName blockingActivity, 1662 int displayId, String blockedActivity, int blockedTaskId, String taskRootActivity, 1663 boolean isRootDo) { 1664 Intent newActivityIntent = new Intent(); 1665 newActivityIntent.setFlags( 1666 Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); 1667 newActivityIntent.setComponent(blockingActivity); 1668 newActivityIntent.putExtra( 1669 BLOCKING_INTENT_EXTRA_DISPLAY_ID, displayId); 1670 newActivityIntent.putExtra( 1671 BLOCKING_INTENT_EXTRA_BLOCKED_ACTIVITY_NAME, blockedActivity); 1672 newActivityIntent.putExtra( 1673 BLOCKING_INTENT_EXTRA_BLOCKED_TASK_ID, blockedTaskId); 1674 newActivityIntent.putExtra( 1675 BLOCKING_INTENT_EXTRA_ROOT_ACTIVITY_NAME, taskRootActivity); 1676 newActivityIntent.putExtra( 1677 BLOCKING_INTENT_EXTRA_IS_ROOT_ACTIVITY_DO, isRootDo); 1678 1679 return newActivityIntent; 1680 } 1681 1682 /** 1683 * Enable/Disable activity blocking by correspondingly enabling/disabling broadcasting UXR 1684 * changes in {@link CarUxRestrictionsManagerService}. This is only available in 1685 * engineering builds for development convenience. 1686 */ 1687 @Override setEnableActivityBlocking(boolean enable)1688 public void setEnableActivityBlocking(boolean enable) { 1689 if (!isDebugBuild()) { 1690 Slogf.e(TAG, "Cannot enable/disable activity blocking"); 1691 return; 1692 } 1693 1694 // Check if the caller has the same signature as that of the car service. 1695 if (mPackageManager.checkSignatures(Process.myUid(), Binder.getCallingUid()) 1696 != PackageManager.SIGNATURE_MATCH) { 1697 throw new SecurityException( 1698 "Caller " + mPackageManager.getNameForUid(Binder.getCallingUid()) 1699 + " does not have the right signature"); 1700 } 1701 mCarUxRestrictionsService.setUxRChangeBroadcastEnabled(enable); 1702 } 1703 1704 @Override getTargetCarVersion(String packageName)1705 public CarVersion getTargetCarVersion(String packageName) { 1706 return getTargetCarVersion(Binder.getCallingUserHandle(), packageName); 1707 } 1708 1709 @Override getSelfTargetCarVersion(String packageName)1710 public CarVersion getSelfTargetCarVersion(String packageName) { 1711 checkCalledByPackage(mContext, packageName); 1712 1713 return getTargetCarVersion(Binder.getCallingUserHandle(), packageName); 1714 } 1715 1716 /** 1717 * Public, as it's also used by {@code ICarImpl}. 1718 */ getTargetCarVersion(UserHandle user, String packageName)1719 public CarVersion getTargetCarVersion(UserHandle user, String packageName) { 1720 Context context = mContext.createContextAsUser(user, /* flags= */ 0); 1721 return getTargetCarVersion(context, packageName); 1722 } 1723 1724 /** 1725 * Used by {@code CarShellCommand} as well. 1726 */ 1727 @Nullable getTargetCarVersion(Context context, String packageName)1728 public static CarVersion getTargetCarVersion(Context context, String packageName) { 1729 String permission = android.Manifest.permission.QUERY_ALL_PACKAGES; 1730 if (context.checkCallingOrSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) { 1731 Slogf.w(TAG, "getTargetCarVersion(%s): UID %d doesn't have %s permission", 1732 packageName, Binder.getCallingUid(), permission); 1733 throw new SecurityException("requires permission " + permission); 1734 } 1735 ApplicationInfo info = null; 1736 try { 1737 info = context.getPackageManager().getApplicationInfo(packageName, 1738 PackageManager.ApplicationInfoFlags.of(PackageManager.GET_META_DATA)); 1739 } catch (NameNotFoundException e) { 1740 if (DBG) { 1741 Slogf.d(TAG, "getTargetCarVersion(%s, %s): not found: %s", context.getUser(), 1742 packageName, e); 1743 } 1744 throw new ServiceSpecificException(CarPackageManager.ERROR_CODE_NO_PACKAGE, 1745 e.getMessage()); 1746 } 1747 return CarVersionParser.getTargetCarVersion(info); 1748 } 1749 1750 /** 1751 * Get the distraction optimized activities for the given package. 1752 * 1753 * @param pkgName Name of the package 1754 * @return Array of the distraction optimized activities in the package 1755 */ 1756 @Nullable getDistractionOptimizedActivities(String pkgName)1757 public String[] getDistractionOptimizedActivities(String pkgName) { 1758 try { 1759 return findDistractionOptimizedActivitiesAsUser(pkgName, 1760 mActivityManager.getCurrentUser()); 1761 } catch (NameNotFoundException e) { 1762 return null; 1763 } 1764 } 1765 1766 @Override requiresDisplayCompat(String packageName)1767 public boolean requiresDisplayCompat(String packageName) { 1768 if (!callerCanQueryPackage(packageName)) { 1769 throw new SecurityException("requires permission " + QUERY_ALL_PACKAGES); 1770 } 1771 int callingUid = Binder.getCallingUid(); 1772 if (!hasPermissionGranted(PERMISSION_MANAGE_DISPLAY_COMPATIBILITY, callingUid)) { 1773 throw new SecurityException("requires permission " 1774 + PERMISSION_MANAGE_DISPLAY_COMPATIBILITY); 1775 } 1776 return CarServiceHelperWrapper.getInstance().requiresDisplayCompat( 1777 Objects.requireNonNull(packageName, "packageName cannot be Null")); 1778 } 1779 1780 @Override requiresDisplayCompatForUser(String packageName, int userId)1781 public boolean requiresDisplayCompatForUser(String packageName, int userId) { 1782 if (!callerCanQueryPackage(packageName)) { 1783 throw new SecurityException("requires permission " + QUERY_ALL_PACKAGES); 1784 } 1785 int callingUid = Binder.getCallingUid(); 1786 if (!hasPermissionGranted(PERMISSION_MANAGE_DISPLAY_COMPATIBILITY, callingUid)) { 1787 throw new SecurityException("requires permission " 1788 + PERMISSION_MANAGE_DISPLAY_COMPATIBILITY); 1789 } 1790 return CarServiceHelperWrapper.getInstance().requiresDisplayCompatForUser( 1791 Objects.requireNonNull(packageName, "packageName cannot be Null"), userId); 1792 } 1793 findDistractionOptimizedActivitiesAsUser(String pkgName, int userId)1794 private String[] findDistractionOptimizedActivitiesAsUser(String pkgName, int userId) 1795 throws NameNotFoundException { 1796 String regionString; 1797 synchronized (mLock) { 1798 regionString = mCurrentDrivingSafetyRegion; 1799 } 1800 return CarAppMetadataReader.findDistractionOptimizedActivitiesAsUser(mContext, pkgName, 1801 userId, regionString); 1802 } 1803 1804 /** 1805 * Reading policy and setting policy can take time. Run it in a separate handler thread. 1806 */ 1807 private static final class PackageHandler extends Handler { 1808 private static final String TAG = CarLog.tagFor(CarPackageManagerService.class); 1809 1810 private static final int MSG_INIT = 0; 1811 private static final int MSG_PARSE_PKG = 1; 1812 private static final int MSG_UPDATE_POLICY = 2; 1813 private static final int MSG_RELEASE = 3; 1814 1815 private final WeakReference<CarPackageManagerService> mService; 1816 PackageHandler(Looper looper, CarPackageManagerService service)1817 private PackageHandler(Looper looper, CarPackageManagerService service) { 1818 super(looper); 1819 mService = new WeakReference<CarPackageManagerService>(service); 1820 } 1821 requestInit()1822 private void requestInit() { 1823 Message msg = obtainMessage(MSG_INIT); 1824 sendMessage(msg); 1825 } 1826 requestRelease()1827 private void requestRelease() { 1828 removeMessages(MSG_UPDATE_POLICY); 1829 Message msg = obtainMessage(MSG_RELEASE); 1830 sendMessage(msg); 1831 } 1832 requestUpdatingPolicy(String packageName, CarAppBlockingPolicy policy, int flags)1833 private void requestUpdatingPolicy(String packageName, CarAppBlockingPolicy policy, 1834 int flags) { 1835 Pair<String, CarAppBlockingPolicy> pair = new Pair<>(packageName, policy); 1836 Message msg = obtainMessage(MSG_UPDATE_POLICY, flags, 0, pair); 1837 sendMessage(msg); 1838 } 1839 requestParsingInstalledPkg(String packageName)1840 private void requestParsingInstalledPkg(String packageName) { 1841 Message msg = obtainMessage(MSG_PARSE_PKG, packageName); 1842 sendMessage(msg); 1843 } 1844 1845 @Override handleMessage(Message msg)1846 public void handleMessage(Message msg) { 1847 CarPackageManagerService service = mService.get(); 1848 if (service == null) { 1849 Slogf.i(TAG, "handleMessage null service"); 1850 return; 1851 } 1852 switch (msg.what) { 1853 case MSG_INIT: 1854 service.doHandleInit(); 1855 break; 1856 case MSG_PARSE_PKG: 1857 service.doParseInstalledPackage((String) msg.obj); 1858 break; 1859 case MSG_UPDATE_POLICY: 1860 Pair<String, CarAppBlockingPolicy> pair = 1861 (Pair<String, CarAppBlockingPolicy>) msg.obj; 1862 service.doUpdatePolicy(pair.first, pair.second, msg.arg1); 1863 break; 1864 case MSG_RELEASE: 1865 service.doHandleRelease(); 1866 break; 1867 default: 1868 break; 1869 } 1870 } 1871 } 1872 1873 private static class AppBlockingPackageInfoWrapper { 1874 private final AppBlockingPackageInfo info; 1875 /** 1876 * Whether the current info is matching with the target package in system. Mismatch can 1877 * happen for version out of range or signature mismatch. 1878 */ 1879 private boolean isMatching; 1880 AppBlockingPackageInfoWrapper(AppBlockingPackageInfo info, boolean isMatching)1881 private AppBlockingPackageInfoWrapper(AppBlockingPackageInfo info, boolean isMatching) { 1882 this.info = info; 1883 this.isMatching = isMatching; 1884 } 1885 1886 @Override toString()1887 public String toString() { 1888 return "AppBlockingPackageInfoWrapper [info=" + info + ", isMatching=" + isMatching + 1889 "]"; 1890 } 1891 } 1892 1893 /** 1894 * Client policy holder per each client. Should be accessed with CarpackageManagerService.this 1895 * held. 1896 */ 1897 private static class ClientPolicy { 1898 private final HashMap<String, AppBlockingPackageInfoWrapper> mAllowlistsMap = 1899 new HashMap<>(); 1900 private final HashMap<String, AppBlockingPackageInfoWrapper> mBlocklistsMap = 1901 new HashMap<>(); 1902 replaceAllowlists(AppBlockingPackageInfoWrapper[] allowlists)1903 private void replaceAllowlists(AppBlockingPackageInfoWrapper[] allowlists) { 1904 mAllowlistsMap.clear(); 1905 addToAllowlists(allowlists); 1906 } 1907 addToAllowlists(AppBlockingPackageInfoWrapper[] allowlists)1908 private void addToAllowlists(AppBlockingPackageInfoWrapper[] allowlists) { 1909 if (allowlists == null) { 1910 return; 1911 } 1912 for (AppBlockingPackageInfoWrapper wrapper : allowlists) { 1913 if (wrapper != null) { 1914 mAllowlistsMap.put(wrapper.info.packageName, wrapper); 1915 } 1916 } 1917 } 1918 removeAllowlists(AppBlockingPackageInfoWrapper[] allowlists)1919 private void removeAllowlists(AppBlockingPackageInfoWrapper[] allowlists) { 1920 if (allowlists == null) { 1921 return; 1922 } 1923 for (AppBlockingPackageInfoWrapper wrapper : allowlists) { 1924 if (wrapper != null) { 1925 mAllowlistsMap.remove(wrapper.info.packageName); 1926 } 1927 } 1928 } 1929 replaceBlocklists(AppBlockingPackageInfoWrapper[] blocklists)1930 private void replaceBlocklists(AppBlockingPackageInfoWrapper[] blocklists) { 1931 mBlocklistsMap.clear(); 1932 addToBlocklists(blocklists); 1933 } 1934 addToBlocklists(AppBlockingPackageInfoWrapper[] blocklists)1935 private void addToBlocklists(AppBlockingPackageInfoWrapper[] blocklists) { 1936 if (blocklists == null) { 1937 return; 1938 } 1939 for (AppBlockingPackageInfoWrapper wrapper : blocklists) { 1940 if (wrapper != null) { 1941 mBlocklistsMap.put(wrapper.info.packageName, wrapper); 1942 } 1943 } 1944 } 1945 removeBlocklists(AppBlockingPackageInfoWrapper[] blocklists)1946 private void removeBlocklists(AppBlockingPackageInfoWrapper[] blocklists) { 1947 if (blocklists == null) { 1948 return; 1949 } 1950 for (AppBlockingPackageInfoWrapper wrapper : blocklists) { 1951 if (wrapper != null) { 1952 mBlocklistsMap.remove(wrapper.info.packageName); 1953 } 1954 } 1955 } 1956 } 1957 1958 private class ActivityListener implements CarActivityService.ActivityListener { 1959 @Override onActivityCameOnTop(TaskInfo topTask)1960 public void onActivityCameOnTop(TaskInfo topTask) { 1961 if (topTask == null) { 1962 Slogf.e(TAG, "Received callback with null top task."); 1963 return; 1964 } 1965 boolean isBlockingActivity = Objects.equals(mActivityBlockingActivity, 1966 topTask.topActivity); 1967 synchronized (mLock) { 1968 if (isBlockingActivity) { 1969 // This is to keep track of the blocking ui taskInfo. 1970 mBlockingUiTaskInfoPerDisplay.put(TaskInfoHelper.getDisplayId(topTask), 1971 topTask); 1972 } 1973 mLastKnownDisplayIdForTask.put(topTask.taskId, 1974 TaskInfoHelper.getDisplayId(topTask)); 1975 } 1976 blockTopActivityIfNecessary(topTask); 1977 } 1978 1979 // TODO(b/358905871): Verify if onTaskInfoChanged required to trigger finishing of 1980 // blocking ui. 1981 @Override onTaskVanished(TaskInfo taskInfo)1982 public void onTaskVanished(TaskInfo taskInfo) { 1983 if (taskInfo == null) { 1984 Slogf.e(TAG, "Received callback with null task info."); 1985 return; 1986 } 1987 int lastKnownDisplayId; 1988 synchronized (mLock) { 1989 // Only update the array if display Id for the task is valid since display Id can 1990 // often be invalid when the task has vanished. 1991 if (TaskInfoHelper.getDisplayId(taskInfo) != Display.INVALID_DISPLAY) { 1992 mLastKnownDisplayIdForTask.put(taskInfo.taskId, 1993 TaskInfoHelper.getDisplayId(taskInfo)); 1994 } 1995 lastKnownDisplayId = mLastKnownDisplayIdForTask.get(taskInfo.taskId); 1996 } 1997 // Only finish the blocking ui if it is visible and the activity that is being 1998 // blocked has vanished which could have crashed due to which there is a need for 1999 // blocking ui to finish. 2000 if (isBlockingUiVisible(lastKnownDisplayId) && isBlockedActivityTarget( 2001 lastKnownDisplayId, taskInfo)) { 2002 if (DBG) { 2003 Slogf.d(TAG, 2004 "Finish blocking ui callback due to task %s which was blocked on " 2005 + "display id %d.", taskInfo.taskId, lastKnownDisplayId); 2006 } 2007 mHandler.post(() -> finishBlockingUi(taskInfo)); 2008 cleanUpBlockingUiInformation(lastKnownDisplayId); 2009 } else if (isBlockingUiTask(taskInfo)) { 2010 if (DBG) { 2011 Slogf.d(TAG, "Blocking ui has vanished on display id %d.", lastKnownDisplayId); 2012 } 2013 cleanUpBlockingUiInformation(lastKnownDisplayId); 2014 } 2015 } 2016 } 2017 2018 /** 2019 * Cleans up blocking ui information since either the blocking ui itself finished or the task 2020 * that was being blocked by the blocking ui finished. In both the cases, the blocking ui will 2021 * be finishing itself, so clean up the information. Since blocking ui is finished, also clean 2022 * up the {@code mBlockingUiTaskInfoPerDisplay}. 2023 */ cleanUpBlockingUiInformation(int lastKnownDisplayId)2024 private void cleanUpBlockingUiInformation(int lastKnownDisplayId) { 2025 if (mBlockingActivityTargets.contains(lastKnownDisplayId)) { 2026 mBlockingActivityLaunchTimes.put(lastKnownDisplayId, 0); 2027 mBlockingActivityTargets.delete(lastKnownDisplayId); 2028 } 2029 synchronized (mLock) { 2030 mBlockingUiTaskInfoPerDisplay.delete(lastKnownDisplayId); 2031 } 2032 } 2033 2034 /** 2035 * Checks if the {@link TaskInfo} is the blocking ui. 2036 * 2037 * @return {@code true} if blocking ui is the {@link TaskInfo}, {@code false} otherwise. 2038 */ isBlockingUiTask(TaskInfo taskInfo)2039 private boolean isBlockingUiTask(TaskInfo taskInfo) { 2040 return taskInfo.topActivity != null && taskInfo.topActivity.equals( 2041 mActivityBlockingActivity); 2042 } 2043 2044 /** 2045 * Checks if blocking ui is visible on that {@code displayId}. 2046 * 2047 * @param displayId the display id of the {@link TaskInfo}. 2048 * @return {@code true} if the blocking ui is visible, {@code false} otherwise. 2049 */ isBlockingUiVisible(int displayId)2050 private boolean isBlockingUiVisible(int displayId) { 2051 synchronized (mLock) { 2052 return mBlockingUiTaskInfoPerDisplay.get(displayId) != null && TaskInfoHelper.isVisible( 2053 mBlockingUiTaskInfoPerDisplay.get(displayId)); 2054 } 2055 } 2056 2057 /** 2058 * Check if this stack change came from the blocked {@code taskInfo} in 2059 * {@code mBlockingActivityTargets} for {@code displayId}. Ignore other activities since they 2060 * cannot can cause a visibility change for the blocked activity target. 2061 * 2062 * <p>Note that {@code mBlockingActivityTargets} for the display id can be null due to a race 2063 * condition when an NDO activity and the blocking ui is finishing at the same time since 2064 * {@link #cleanUpBlockingUiInformation} is called from various places. 2065 * 2066 * @param displayId the display id of the {@link TaskInfo}. 2067 * @param taskInfo {@link TaskInfo} due to which the task stack changed. 2068 * @return {@code true} if this stack change came from blocked {@code taskInfo} for 2069 * {@code displayId}, {@code false} otherwise. 2070 */ isBlockedActivityTarget(int displayId, TaskInfo taskInfo)2071 private boolean isBlockedActivityTarget(int displayId, TaskInfo taskInfo) { 2072 return mBlockingActivityTargets.get(displayId) != null 2073 && mBlockingActivityTargets.get(displayId).taskId == taskInfo.taskId; 2074 } 2075 2076 /** 2077 * Registers the {@link ICarBlockingUiCommandListener} listening for the commands to control the 2078 * blocking ui. 2079 * 2080 * @param listener listener to register. 2081 * @param displayId display Id with which the listener is associated. 2082 */ registerBlockingUiCommandListener(ICarBlockingUiCommandListener listener, int displayId)2083 public void registerBlockingUiCommandListener(ICarBlockingUiCommandListener listener, 2084 int displayId) { 2085 ensurePermission(); 2086 mBlockingUiCommandListenerMediator.registerBlockingUiCommandListener(listener, displayId); 2087 } 2088 2089 /** 2090 * Unregisters the {@link ICarBlockingUiCommandListener}. 2091 * 2092 * @param listener listener to unregister. 2093 */ unregisterBlockingUiCommandListener(ICarBlockingUiCommandListener listener)2094 public void unregisterBlockingUiCommandListener(ICarBlockingUiCommandListener listener) { 2095 ensurePermission(); 2096 mBlockingUiCommandListenerMediator.unregisterBlockingUiCommandListener(listener); 2097 } 2098 2099 /** 2100 * Broadcast the finish command to listeners. 2101 * 2102 * @param taskInfo the {@link TaskInfo} due to which finish is broadcast to the listeners. 2103 */ finishBlockingUi(TaskInfo taskInfo)2104 public void finishBlockingUi(TaskInfo taskInfo) { 2105 ensurePermission(); 2106 int displayId = getLastKnownDisplayIdForTask(taskInfo.taskId); 2107 mBlockingUiCommandListenerMediator.finishBlockingUi(taskInfo, displayId); 2108 cleanUpLastKnownDisplayIdForTask(taskInfo); 2109 } 2110 2111 /** 2112 * Returns the last known display Id for the given {@link TaskInfo}. 2113 */ getLastKnownDisplayIdForTask(int taskId)2114 private int getLastKnownDisplayIdForTask(int taskId) { 2115 synchronized (mLock) { 2116 return mLastKnownDisplayIdForTask.get(taskId); 2117 } 2118 } 2119 2120 /** 2121 * Removes the task from {@code mLastKnownDisplayIdForTask}. 2122 */ cleanUpLastKnownDisplayIdForTask(TaskInfo taskInfo)2123 private void cleanUpLastKnownDisplayIdForTask(TaskInfo taskInfo) { 2124 synchronized (mLock) { 2125 // This can happen when the task has not been removed from mLastKnownDisplayIdForTask 2126 // when the task vanishes in onTaskVanished. 2127 mLastKnownDisplayIdForTask.delete(taskInfo.taskId); 2128 } 2129 } 2130 2131 /** 2132 * Get number of registered callbacks for the display ID. 2133 * 2134 * @param displayId display Id with which the listener is associated. 2135 * @return number of registered callbacks for the given {@code displayId}. 2136 */ 2137 @VisibleForTesting getCarBlockingUiCommandListenerRegisteredCallbacksForDisplay(int displayId)2138 public int getCarBlockingUiCommandListenerRegisteredCallbacksForDisplay(int displayId) { 2139 return mBlockingUiCommandListenerMediator 2140 .getCarBlockingUiCommandListenerRegisteredCallbacksForDisplay(displayId); 2141 } 2142 2143 /** Ensure permission is granted. */ ensurePermission()2144 private void ensurePermission() { 2145 if (mContext.checkCallingOrSelfPermission(Car.PERMISSION_REGISTER_CAR_SYSTEM_UI_PROXY) 2146 != PackageManager.PERMISSION_GRANTED) { 2147 throw new SecurityException( 2148 "requires permission " + Car.PERMISSION_REGISTER_CAR_SYSTEM_UI_PROXY); 2149 } 2150 } 2151 2152 /** 2153 * Listens to the UX restrictions from {@link CarUxRestrictionsManagerService} and initiates 2154 * checking if the foreground Activity should be blocked. 2155 */ 2156 private class UxRestrictionsListener extends ICarUxRestrictionsChangeListener.Stub { 2157 @GuardedBy("mLock") 2158 @Nullable 2159 private CarUxRestrictions mCurrentUxRestrictions; 2160 private final CarUxRestrictionsManagerService uxRestrictionsService; 2161 private final int mDisplayId; 2162 UxRestrictionsListener(CarUxRestrictionsManagerService service, int displayId)2163 UxRestrictionsListener(CarUxRestrictionsManagerService service, int displayId) { 2164 uxRestrictionsService = service; 2165 mDisplayId = displayId; 2166 } 2167 2168 @Override onUxRestrictionsChanged(CarUxRestrictions restrictions)2169 public void onUxRestrictionsChanged(CarUxRestrictions restrictions) { 2170 if (DBG) { 2171 Slogf.d(TAG, "Received uxr restrictions: Requires DO? %b : %d on display %d", 2172 restrictions.isRequiresDistractionOptimization(), 2173 restrictions.getActiveRestrictions(), mDisplayId); 2174 } 2175 2176 // Check if top activities need blocking on this display. 2177 boolean shouldCheck = false; 2178 synchronized (mLock) { 2179 mCurrentUxRestrictions = new CarUxRestrictions(restrictions); 2180 shouldCheck = mCurrentUxRestrictions.isRequiresDistractionOptimization(); 2181 } 2182 2183 if (DBG) { 2184 Slogf.d(TAG, "Should check top tasks for blocking on display %d?: " + shouldCheck, 2185 mDisplayId); 2186 } 2187 2188 if (shouldCheck) { 2189 // Each UxRestrictionsListener is only responsible for blocking activities on their 2190 // own display. 2191 mHandler.post(() -> blockTopActivitiesOnDisplayIfNecessary( 2192 mActivityService.getVisibleTasksInternal(), mDisplayId)); 2193 } 2194 } 2195 isRestricted()2196 private boolean isRestricted() { 2197 // If current restrictions is null, try querying the service, once. 2198 synchronized (mLock) { 2199 if (mCurrentUxRestrictions == null) { 2200 mCurrentUxRestrictions = uxRestrictionsService.getCurrentUxRestrictions( 2201 mDisplayId); 2202 } 2203 if (mCurrentUxRestrictions != null) { 2204 return mCurrentUxRestrictions.isRequiresDistractionOptimization(); 2205 } 2206 } 2207 2208 // If restriction information is still not available (could happen during bootup), 2209 // return not restricted. This maintains parity with previous implementation but needs 2210 // a revisit as we test more. 2211 return false; 2212 } 2213 } 2214 2215 /** 2216 * Called when a window change event is received by the {@link CarSafetyAccessibilityService}. 2217 */ 2218 @VisibleForTesting onWindowChangeEvent(@onNull AccessibilityEvent event)2219 void onWindowChangeEvent(@NonNull AccessibilityEvent event) { 2220 boolean receivedFromActivityBlockingActivity = 2221 event.getPackageName() != null && event.getClassName() != null 2222 && mActivityBlockingActivity.getPackageName().contentEquals( 2223 event.getPackageName()) 2224 && mActivityBlockingActivity.getClassName().contentEquals( 2225 event.getClassName()); 2226 if (!receivedFromActivityBlockingActivity) { 2227 int displayId = event.getDisplayId(); 2228 if (isUxRestrictedOnDisplay(displayId)) { 2229 if (DBG) { 2230 Slogf.d(TAG, "onWindowChange event from package %s on Ux restricted display %d," 2231 + " checking activity blocking", event.getPackageName(), displayId); 2232 } 2233 // Schedule activity blocking with mHandler to ensure there is no concurrent 2234 // activity blocking. 2235 mHandler.post(() -> 2236 blockTopActivitiesOnDisplayIfNecessary( 2237 mActivityService.getVisibleTasksInternal(), displayId)); 2238 } 2239 } else { 2240 Slogf.d(TAG, "Discarded onWindowChangeEvent received from " 2241 + "ActivityBlockingActivity"); 2242 } 2243 } 2244 2245 /** 2246 * Listens to the package install/uninstall events to know when to initiate parsing 2247 * installed packages. 2248 */ 2249 private class PackageParsingEventReceiver extends BroadcastReceiver { 2250 @Override onReceive(Context context, Intent intent)2251 public void onReceive(Context context, Intent intent) { 2252 if (intent == null || intent.getAction() == null) { 2253 return; 2254 } 2255 if (DBG) { 2256 Slogf.d(TAG, "PackageParsingEventReceiver Received " + intent.getAction()); 2257 } 2258 String action = intent.getAction(); 2259 if (isPackageManagerAction(action)) { 2260 // send a delayed message so if we received multiple related intents, we parse 2261 // only once. 2262 logEventChange(intent); 2263 String packageName = getPackageName(intent); 2264 mHandler.requestParsingInstalledPkg(packageName); 2265 } 2266 } 2267 getPackageName(Intent intent)2268 private String getPackageName(Intent intent) { 2269 // For mPackageManagerActions, data should contain package name. 2270 String dataString = intent.getDataString(); 2271 if (dataString == null) return null; 2272 2273 String scheme = intent.getScheme(); 2274 if (!Objects.equals(scheme, "package")) return null; 2275 2276 String[] splitData = intent.getDataString().split(":"); 2277 if (splitData.length < 2) return null; 2278 2279 return splitData[1]; 2280 } 2281 isPackageManagerAction(String action)2282 private boolean isPackageManagerAction(String action) { 2283 return mPackageManagerActions.contains(action); 2284 } 2285 2286 /** 2287 * Convenience log function to log what changed. Logs only when more debug logs 2288 * are needed - DBG needs to be true 2289 */ logEventChange(Intent intent)2290 private void logEventChange(Intent intent) { 2291 if (intent == null) { 2292 return; 2293 } 2294 if (DBG) { 2295 String packageName = intent.getData().getSchemeSpecificPart(); 2296 Slogf.d(TAG, "Pkg Changed:" + packageName); 2297 String action = intent.getAction(); 2298 if (action == null) { 2299 return; 2300 } 2301 if (action.equals(Intent.ACTION_PACKAGE_CHANGED)) { 2302 Slogf.d(TAG, "Changed components"); 2303 String[] cc = intent 2304 .getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST); 2305 if (cc != null) { 2306 for (String c : cc) { 2307 Slogf.d(TAG, c); 2308 } 2309 } 2310 } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED) 2311 || action.equals(Intent.ACTION_PACKAGE_ADDED)) { 2312 Slogf.d(TAG, action + " Replacing?: " 2313 + intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)); 2314 } 2315 } 2316 } 2317 } 2318 } 2319