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 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.annotation.UserIdInt; 24 import android.app.ActivityManager; 25 import android.app.ActivityTaskManager.RootTaskInfo; 26 import android.app.PendingIntent; 27 import android.car.Car; 28 import android.car.content.pm.AppBlockingPackageInfo; 29 import android.car.content.pm.CarAppBlockingPolicy; 30 import android.car.content.pm.CarAppBlockingPolicyService; 31 import android.car.content.pm.CarPackageManager; 32 import android.car.content.pm.ICarPackageManager; 33 import android.car.drivingstate.CarUxRestrictions; 34 import android.car.drivingstate.ICarUxRestrictionsChangeListener; 35 import android.car.hardware.power.CarPowerPolicy; 36 import android.car.hardware.power.CarPowerPolicyFilter; 37 import android.car.hardware.power.ICarPowerPolicyListener; 38 import android.car.hardware.power.PowerComponent; 39 import android.car.user.CarUserManager; 40 import android.content.BroadcastReceiver; 41 import android.content.ComponentName; 42 import android.content.Context; 43 import android.content.Intent; 44 import android.content.IntentFilter; 45 import android.content.pm.ActivityInfo; 46 import android.content.pm.PackageInfo; 47 import android.content.pm.PackageManager; 48 import android.content.pm.PackageManager.NameNotFoundException; 49 import android.content.pm.ResolveInfo; 50 import android.content.pm.ServiceInfo; 51 import android.content.pm.Signature; 52 import android.content.res.Resources; 53 import android.hardware.display.DisplayManager; 54 import android.os.Binder; 55 import android.os.Build; 56 import android.os.Handler; 57 import android.os.HandlerThread; 58 import android.os.IBinder; 59 import android.os.Looper; 60 import android.os.Message; 61 import android.os.ParcelFileDescriptor; 62 import android.os.Process; 63 import android.os.RemoteException; 64 import android.os.ServiceManager; 65 import android.os.ServiceSpecificException; 66 import android.os.SystemProperties; 67 import android.os.UserHandle; 68 import android.text.TextUtils; 69 import android.util.ArraySet; 70 import android.util.IndentingPrintWriter; 71 import android.util.LocalLog; 72 import android.util.Log; 73 import android.util.Pair; 74 import android.util.Slog; 75 import android.util.SparseArray; 76 import android.view.Display; 77 import android.view.DisplayAddress; 78 79 import com.android.car.CarLocalServices; 80 import com.android.car.CarLog; 81 import com.android.car.CarServiceBase; 82 import com.android.car.CarServiceUtils; 83 import com.android.car.CarUxRestrictionsManagerService; 84 import com.android.car.R; 85 import com.android.car.SystemActivityMonitoringService; 86 import com.android.car.SystemActivityMonitoringService.TopTaskInfoContainer; 87 import com.android.car.power.CarPowerManagementService; 88 import com.android.car.user.CarUserService; 89 import com.android.internal.annotations.GuardedBy; 90 import com.android.internal.annotations.VisibleForTesting; 91 import com.android.server.utils.Slogf; 92 93 import com.google.android.collect.Sets; 94 95 import java.io.BufferedReader; 96 import java.io.FileReader; 97 import java.io.IOException; 98 import java.lang.ref.WeakReference; 99 import java.util.ArrayList; 100 import java.util.Arrays; 101 import java.util.HashMap; 102 import java.util.HashSet; 103 import java.util.LinkedList; 104 import java.util.List; 105 import java.util.Map; 106 import java.util.Map.Entry; 107 import java.util.Objects; 108 import java.util.Set; 109 110 public class CarPackageManagerService extends ICarPackageManager.Stub implements CarServiceBase { 111 112 static final boolean DBG = false; 113 114 private static final String TAG = CarLog.tagFor(CarPackageManagerService.class); 115 116 // Delimiters to parse packages and activities in the configuration XML resource. 117 private static final String PACKAGE_DELIMITER = ","; 118 private static final String PACKAGE_ACTIVITY_DELIMITER = "/"; 119 private static final int LOG_SIZE = 20; 120 private static final String[] WINDOW_DUMP_ARGUMENTS = new String[]{"windows"}; 121 122 private static final String PROPERTY_RO_DRIVING_SAFETY_REGION = 123 "ro.android.car.drivingsafetyregion"; 124 125 private final Context mContext; 126 private final SystemActivityMonitoringService mSystemActivityMonitoringService; 127 private final PackageManager mPackageManager; 128 private final ActivityManager mActivityManager; 129 private final DisplayManager mDisplayManager; 130 private final IBinder mWindowManagerBinder; 131 132 private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread( 133 getClass().getSimpleName()); 134 private final PackageHandler mHandler = new PackageHandler(mHandlerThread.getLooper(), this); 135 private final Object mLock = new Object(); 136 137 // For dumpsys logging. 138 private final LocalLog mBlockedActivityLogs = new LocalLog(LOG_SIZE); 139 140 // Store the allowlist and blocklist strings from the resource file. 141 private String mConfiguredAllowlist; 142 private String mConfiguredSystemAllowlist; 143 private String mConfiguredBlocklist; 144 @GuardedBy("mLock") 145 private Map<String, Set<String>> mConfiguredAllowlistMap; 146 @GuardedBy("mLock") 147 private Map<String, Set<String>> mConfiguredBlocklistMap; 148 149 private final List<String> mAllowedAppInstallSources; 150 151 @GuardedBy("mLock") 152 private final SparseArray<ComponentName> mTopActivityWithDialogPerDisplay = new SparseArray<>(); 153 154 /** 155 * Hold policy set from policy service or client. 156 * Key: packageName of policy service 157 */ 158 @GuardedBy("mLock") 159 private final HashMap<String, ClientPolicy> mClientPolicies = new HashMap<>(); 160 @GuardedBy("mLock") 161 private HashMap<String, AppBlockingPackageInfoWrapper> mActivityAllowlistMap = new HashMap<>(); 162 @GuardedBy("mLock") 163 private HashSet<String> mActivityDenylistPackages = new HashSet<String>(); 164 165 @GuardedBy("mLock") 166 private LinkedList<AppBlockingPolicyProxy> mProxies; 167 168 @GuardedBy("mLock") 169 private final LinkedList<CarAppBlockingPolicy> mWaitingPolicies = new LinkedList<>(); 170 171 @GuardedBy("mLock") 172 private String mCurrentDrivingSafetyRegion = CarPackageManager.DRIVING_SAFETY_REGION_ALL; 173 // Package name + '/' + className format 174 @GuardedBy("mLock") 175 private final ArraySet<String> mTempAllowedActivities = new ArraySet<>(); 176 177 private final CarUxRestrictionsManagerService mCarUxRestrictionsService; 178 private final boolean mEnableActivityBlocking; 179 180 private final ComponentName mActivityBlockingActivity; 181 private final boolean mPreventTemplatedAppsFromShowingDialog; 182 private final String mTemplateActivityClassName; 183 184 private final ActivityLaunchListener mActivityLaunchListener = new ActivityLaunchListener(); 185 186 // K: (logical) display id of a physical display, V: UXR change listener of this display. 187 // For multi-display, monitor UXR change on each display. 188 private final SparseArray<UxRestrictionsListener> mUxRestrictionsListeners = 189 new SparseArray<>(); 190 private final VendorServiceController mVendorServiceController; 191 192 // Information related to when the installed packages should be parsed for building a allow and 193 // block list 194 private final Set<String> mPackageManagerActions = Sets.newArraySet( 195 Intent.ACTION_PACKAGE_ADDED, 196 Intent.ACTION_PACKAGE_CHANGED, 197 Intent.ACTION_PACKAGE_REMOVED, 198 Intent.ACTION_PACKAGE_REPLACED); 199 200 private final PackageParsingEventReceiver mPackageParsingEventReceiver = 201 new PackageParsingEventReceiver(); 202 203 /** 204 * Name of blocked activity. 205 * 206 * @hide 207 */ 208 public static final String BLOCKING_INTENT_EXTRA_BLOCKED_ACTIVITY_NAME = "blocked_activity"; 209 /** 210 * int task id of the blocked task. 211 * 212 * @hide 213 */ 214 public static final String BLOCKING_INTENT_EXTRA_BLOCKED_TASK_ID = "blocked_task_id"; 215 /** 216 * Name of root activity of blocked task. 217 * 218 * @hide 219 */ 220 public static final String BLOCKING_INTENT_EXTRA_ROOT_ACTIVITY_NAME = "root_activity_name"; 221 /** 222 * Boolean indicating whether the root activity is distraction-optimized (DO). 223 * Blocking screen should show a button to restart the task if {@code true}. 224 * 225 * @hide 226 */ 227 public static final String BLOCKING_INTENT_EXTRA_IS_ROOT_ACTIVITY_DO = "is_root_activity_do"; 228 229 /** 230 * int display id of the blocked task. 231 * 232 * @hide 233 */ 234 public static final String BLOCKING_INTENT_EXTRA_DISPLAY_ID = "display_id"; 235 236 private final CarUserManager.UserLifecycleListener mUserLifecycleListener = 237 new CarUserManager.UserLifecycleListener() { 238 @Override 239 public void onEvent(CarUserManager.UserLifecycleEvent event) { 240 if (event.getEventType() 241 == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) { 242 synchronized (mLock) { 243 resetTempAllowedActivitiesLocked(); 244 } 245 } 246 } 247 }; 248 249 private final ICarPowerPolicyListener mDisplayPowerPolicyListener = 250 new ICarPowerPolicyListener.Stub() { 251 @Override 252 public void onPolicyChanged(CarPowerPolicy policy, 253 CarPowerPolicy accumulatedPolicy) { 254 if (!policy.isComponentEnabled(PowerComponent.DISPLAY)) { 255 synchronized (mLock) { 256 resetTempAllowedActivitiesLocked(); 257 } 258 } 259 } 260 }; 261 CarPackageManagerService(Context context, CarUxRestrictionsManagerService uxRestrictionsService, SystemActivityMonitoringService systemActivityMonitoringService)262 public CarPackageManagerService(Context context, 263 CarUxRestrictionsManagerService uxRestrictionsService, 264 SystemActivityMonitoringService systemActivityMonitoringService) { 265 mContext = context; 266 mCarUxRestrictionsService = uxRestrictionsService; 267 mSystemActivityMonitoringService = systemActivityMonitoringService; 268 mPackageManager = mContext.getPackageManager(); 269 mActivityManager = mContext.getSystemService(ActivityManager.class); 270 mDisplayManager = mContext.getSystemService(DisplayManager.class); 271 mWindowManagerBinder = ServiceManager.getService(Context.WINDOW_SERVICE); 272 Resources res = context.getResources(); 273 mEnableActivityBlocking = res.getBoolean(R.bool.enableActivityBlockingForSafety); 274 String blockingActivity = res.getString(R.string.activityBlockingActivity); 275 mActivityBlockingActivity = ComponentName.unflattenFromString(blockingActivity); 276 if (mEnableActivityBlocking && mActivityBlockingActivity == null) { 277 Slogf.wtf(TAG, "mActivityBlockingActivity can't be null when enabled"); 278 } 279 mAllowedAppInstallSources = Arrays.asList( 280 res.getStringArray(R.array.allowedAppInstallSources)); 281 mVendorServiceController = new VendorServiceController( 282 mContext, mHandler.getLooper()); 283 mPreventTemplatedAppsFromShowingDialog = 284 res.getBoolean(R.bool.config_preventTemplatedAppsFromShowingDialog); 285 mTemplateActivityClassName = res.getString(R.string.config_template_activity_class_name); 286 } 287 288 289 @Override setAppBlockingPolicy(String packageName, CarAppBlockingPolicy policy, int flags)290 public void setAppBlockingPolicy(String packageName, CarAppBlockingPolicy policy, int flags) { 291 if (Log.isLoggable(TAG, Log.DEBUG)) { 292 Slog.d(TAG, "policy setting from binder call, client:" + packageName); 293 } 294 doSetAppBlockingPolicy(packageName, policy, flags); 295 } 296 297 /** 298 * Restarts the requested task. If task with {@code taskId} does not exist, do nothing. 299 */ 300 @Override restartTask(int taskId)301 public void restartTask(int taskId) { 302 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.REAL_GET_TASKS) 303 != PackageManager.PERMISSION_GRANTED) { 304 throw new SecurityException( 305 "requires permission " + android.Manifest.permission.REAL_GET_TASKS); 306 } 307 mSystemActivityMonitoringService.restartTask(taskId); 308 } 309 310 @Override getCurrentDrivingSafetyRegion()311 public String getCurrentDrivingSafetyRegion() { 312 assertAppBlockingOrDrivingStatePermission(); 313 synchronized (mLock) { 314 return mCurrentDrivingSafetyRegion; 315 } 316 } 317 getComponentNameString(String packageName, String className)318 private String getComponentNameString(String packageName, String className) { 319 return packageName + '/' + className; 320 } 321 322 @Override controlOneTimeActivityBlockingBypassingAsUser(String packageName, String activityClassName, boolean bypass, @UserIdInt int userId)323 public void controlOneTimeActivityBlockingBypassingAsUser(String packageName, 324 String activityClassName, boolean bypass, @UserIdInt int userId) { 325 assertAppBlockingPermission(); 326 if (!callerCanQueryPackage(packageName)) { 327 throw new SecurityException("cannot query other package"); 328 } 329 try { 330 // Read this to check the validity of pkg / activity name. Not checking this can allow 331 // bad apps to be allowed later. 332 CarAppMetadataReader.getSupportedDrivingSafetyRegionsForActivityAsUser(mContext, 333 packageName, activityClassName, userId); 334 } catch (NameNotFoundException e) { 335 throw new ServiceSpecificException(CarPackageManager.ERROR_CODE_NO_PACKAGE, 336 e.getMessage()); 337 } 338 String componentName = getComponentNameString(packageName, activityClassName); 339 synchronized (mLock) { 340 if (bypass) { 341 mTempAllowedActivities.add(componentName); 342 } else { 343 mTempAllowedActivities.remove(componentName); 344 } 345 } 346 if (!bypass) { // block top activities if bypassing is disabled. 347 blockTopActivitiesIfNecessary(); 348 } 349 } 350 351 @GuardedBy("mLock") resetTempAllowedActivitiesLocked()352 private void resetTempAllowedActivitiesLocked() { 353 mTempAllowedActivities.clear(); 354 } 355 356 @Override getSupportedDrivingSafetyRegionsForActivityAsUser(String packageName, String activityClassName, @UserIdInt int userId)357 public List<String> getSupportedDrivingSafetyRegionsForActivityAsUser(String packageName, 358 String activityClassName, @UserIdInt int userId) { 359 assertAppBlockingOrDrivingStatePermission(); 360 if (!callerCanQueryPackage(packageName)) { 361 throw new SecurityException("cannot query other package"); 362 } 363 long token = Binder.clearCallingIdentity(); 364 try { 365 return CarAppMetadataReader.getSupportedDrivingSafetyRegionsForActivityAsUser(mContext, 366 packageName, activityClassName, userId); 367 } catch (NameNotFoundException e) { 368 throw new ServiceSpecificException(CarPackageManager.ERROR_CODE_NO_PACKAGE, 369 e.getMessage()); 370 } finally { 371 Binder.restoreCallingIdentity(token); 372 } 373 } 374 assertAppBlockingOrDrivingStatePermission()375 private void assertAppBlockingOrDrivingStatePermission() { 376 if (mContext.checkCallingOrSelfPermission(Car.PERMISSION_CONTROL_APP_BLOCKING) 377 != PackageManager.PERMISSION_GRANTED && mContext.checkCallingOrSelfPermission( 378 Car.PERMISSION_CAR_DRIVING_STATE) != PackageManager.PERMISSION_GRANTED) { 379 throw new SecurityException( 380 "requires permission " + Car.PERMISSION_CONTROL_APP_BLOCKING + " or " 381 + Car.PERMISSION_CAR_DRIVING_STATE); 382 } 383 } 384 assertAppBlockingPermission()385 private void assertAppBlockingPermission() { 386 if (mContext.checkCallingOrSelfPermission(Car.PERMISSION_CONTROL_APP_BLOCKING) 387 != PackageManager.PERMISSION_GRANTED) { 388 throw new SecurityException( 389 "requires permission " + Car.PERMISSION_CONTROL_APP_BLOCKING); 390 } 391 } 392 doSetAppBlockingPolicy(String packageName, CarAppBlockingPolicy policy, int flags)393 private void doSetAppBlockingPolicy(String packageName, CarAppBlockingPolicy policy, 394 int flags) { 395 assertAppBlockingPermission(); 396 CarServiceUtils.assertPackageName(mContext, packageName); 397 if (policy == null) { 398 throw new IllegalArgumentException("policy cannot be null"); 399 } 400 if ((flags & CarPackageManager.FLAG_SET_POLICY_ADD) != 0 && 401 (flags & CarPackageManager.FLAG_SET_POLICY_REMOVE) != 0) { 402 throw new IllegalArgumentException( 403 "Cannot set both FLAG_SET_POLICY_ADD and FLAG_SET_POLICY_REMOVE flag"); 404 } 405 synchronized (mLock) { 406 if ((flags & CarPackageManager.FLAG_SET_POLICY_WAIT_FOR_CHANGE) != 0) { 407 mWaitingPolicies.add(policy); 408 } 409 } 410 mHandler.requestUpdatingPolicy(packageName, policy, flags); 411 if ((flags & CarPackageManager.FLAG_SET_POLICY_WAIT_FOR_CHANGE) != 0) { 412 synchronized (mLock) { 413 try { 414 while (mWaitingPolicies.contains(policy)) { 415 mLock.wait(); 416 } 417 } catch (InterruptedException e) { 418 // Pass it over binder call 419 throw new IllegalStateException( 420 "Interrupted while waiting for policy completion", e); 421 } 422 } 423 } 424 } 425 426 @Override isActivityDistractionOptimized(String packageName, String className)427 public boolean isActivityDistractionOptimized(String packageName, String className) { 428 if (!callerCanQueryPackage(packageName)) return false; 429 assertPackageAndClassName(packageName, className); 430 synchronized (mLock) { 431 if (Log.isLoggable(TAG, Log.DEBUG)) { 432 Slog.d(TAG, "isActivityDistractionOptimized" + dumpPoliciesLocked(false)); 433 } 434 435 if (mTempAllowedActivities.contains(getComponentNameString(packageName, 436 className))) { 437 return true; 438 } 439 440 for (int i = mTopActivityWithDialogPerDisplay.size() - 1; i >= 0; i--) { 441 ComponentName activityWithDialog = mTopActivityWithDialogPerDisplay.get( 442 mTopActivityWithDialogPerDisplay.keyAt(i)); 443 if (activityWithDialog.getClassName().equals(className) 444 && activityWithDialog.getPackageName().equals(packageName)) { 445 return false; 446 } 447 } 448 449 if (searchFromClientPolicyBlocklistsLocked(packageName)) { 450 return false; 451 } 452 453 if (isActivityInClientPolicyAllowlistsLocked(packageName, className)) { 454 return true; 455 } 456 457 // Check deny and allow list 458 boolean packageBlocked = mActivityDenylistPackages.contains(packageName); 459 AppBlockingPackageInfoWrapper infoWrapper = mActivityAllowlistMap.get(packageName); 460 if (!packageBlocked && infoWrapper == null) { 461 // Update cache 462 updateActivityAllowlistAndDenylistMap(packageName); 463 packageBlocked = mActivityDenylistPackages.contains(packageName); 464 infoWrapper = mActivityAllowlistMap.get(packageName); 465 } 466 467 if (packageBlocked 468 || !isActivityInMapAndMatching(infoWrapper, packageName, className)) { 469 return false; 470 } 471 472 return true; 473 } 474 } 475 476 @VisibleForTesting callerCanQueryPackage(String packageName)477 boolean callerCanQueryPackage(String packageName) { 478 int callingUid = Binder.getCallingUid(); 479 if (hasPermissionGranted(QUERY_ALL_PACKAGES, callingUid)) { 480 return true; 481 } 482 String[] packages = mPackageManager.getPackagesForUid(callingUid); 483 if (packages != null && packages.length > 0) { 484 for (int i = 0; i < packages.length; i++) { 485 if (Objects.equals(packageName, packages[i])) { 486 return true; 487 } 488 } 489 } 490 491 Slog.w(TAG, QUERY_ALL_PACKAGES + " permission is needed to query other packages."); 492 493 return false; 494 } 495 hasPermissionGranted(String permission, int uid)496 private static boolean hasPermissionGranted(String permission, int uid) { 497 return ActivityManager.checkComponentPermission(permission, uid, 498 /* owningUid= */ Process.INVALID_UID, 499 /* exported= */ true) == PackageManager.PERMISSION_GRANTED; 500 } 501 502 @Override isPendingIntentDistractionOptimized(PendingIntent pendingIntent)503 public boolean isPendingIntentDistractionOptimized(PendingIntent pendingIntent) { 504 ResolveInfo info = mPackageManager.resolveActivity( 505 pendingIntent.getIntent(), PackageManager.MATCH_DEFAULT_ONLY); 506 if (info == null) return false; 507 ActivityInfo activityInfo = info.activityInfo; 508 return isActivityDistractionOptimized(activityInfo.packageName, activityInfo.name); 509 } 510 511 @Override isServiceDistractionOptimized(String packageName, String className)512 public boolean isServiceDistractionOptimized(String packageName, String className) { 513 if (!callerCanQueryPackage(packageName)) return false; 514 515 if (packageName == null) { 516 throw new IllegalArgumentException("Package name null"); 517 } 518 synchronized (mLock) { 519 if (Log.isLoggable(TAG, Log.DEBUG)) { 520 Slog.d(TAG, "isServiceDistractionOptimized" + dumpPoliciesLocked(false)); 521 } 522 523 if (searchFromClientPolicyBlocklistsLocked(packageName)) { 524 return false; 525 } 526 527 if (searchFromClientPolicyAllowlistsLocked(packageName)) { 528 return true; 529 } 530 531 // Check deny and allow list 532 boolean packageBlocked = mActivityDenylistPackages.contains(packageName); 533 AppBlockingPackageInfoWrapper infoWrapper = mActivityAllowlistMap.get(packageName); 534 if (!packageBlocked && infoWrapper == null) { 535 // Update cache 536 updateActivityAllowlistAndDenylistMap(packageName); 537 packageBlocked = mActivityDenylistPackages.contains(packageName); 538 infoWrapper = mActivityAllowlistMap.get(packageName); 539 } 540 541 if (packageBlocked || infoWrapper == null || infoWrapper.info == null) { 542 return false; 543 } 544 545 return true; 546 } 547 } 548 549 @Override isActivityBackedBySafeActivity(ComponentName activityName)550 public boolean isActivityBackedBySafeActivity(ComponentName activityName) { 551 if (activityName == null) return false; 552 if (!callerCanQueryPackage(activityName.getPackageName())) return false; 553 554 RootTaskInfo info = mSystemActivityMonitoringService.getFocusedStackForTopActivity( 555 activityName); 556 if (info == null) { // not top in focused stack 557 return true; 558 } 559 if (!isUxRestrictedOnDisplay(info.displayId)) { 560 return true; 561 } 562 if (info.childTaskNames.length <= 1) { // nothing below this. 563 return false; 564 } 565 ComponentName activityBehind = ComponentName.unflattenFromString( 566 info.childTaskNames[info.childTaskNames.length - 2]); 567 return isActivityDistractionOptimized(activityBehind.getPackageName(), 568 activityBehind.getClassName()); 569 } 570 getLooper()571 public Looper getLooper() { 572 return mHandlerThread.getLooper(); 573 } 574 assertPackageAndClassName(String packageName, String className)575 private void assertPackageAndClassName(String packageName, String className) { 576 if (packageName == null) { 577 throw new IllegalArgumentException("Package name null"); 578 } 579 if (className == null) { 580 throw new IllegalArgumentException("Class name null"); 581 } 582 } 583 584 @GuardedBy("mLock") searchFromClientPolicyBlocklistsLocked(String packageName)585 private boolean searchFromClientPolicyBlocklistsLocked(String packageName) { 586 for (ClientPolicy policy : mClientPolicies.values()) { 587 AppBlockingPackageInfoWrapper wrapper = policy.mBlocklistsMap.get(packageName); 588 if (wrapper != null && wrapper.isMatching && wrapper.info != null) { 589 return true; 590 } 591 } 592 593 return false; 594 } 595 596 @GuardedBy("mLock") searchFromClientPolicyAllowlistsLocked(String packageName)597 private boolean searchFromClientPolicyAllowlistsLocked(String packageName) { 598 for (ClientPolicy policy : mClientPolicies.values()) { 599 AppBlockingPackageInfoWrapper wrapper = policy.mAllowlistsMap.get(packageName); 600 if (wrapper != null && wrapper.isMatching && wrapper.info != null) { 601 return true; 602 } 603 } 604 return false; 605 } 606 607 @GuardedBy("mLock") isActivityInClientPolicyAllowlistsLocked(String packageName, String className)608 private boolean isActivityInClientPolicyAllowlistsLocked(String packageName, String className) { 609 for (ClientPolicy policy : mClientPolicies.values()) { 610 if (isActivityInMapAndMatching(policy.mAllowlistsMap.get(packageName), packageName, 611 className)) { 612 return true; 613 } 614 } 615 return false; 616 } 617 isActivityInMapAndMatching(AppBlockingPackageInfoWrapper wrapper, String packageName, String className)618 private boolean isActivityInMapAndMatching(AppBlockingPackageInfoWrapper wrapper, 619 String packageName, String className) { 620 if (wrapper == null || !wrapper.isMatching) { 621 if (Log.isLoggable(TAG, Log.DEBUG)) { 622 Slog.d(TAG, "Pkg not in allowlist:" + packageName); 623 } 624 return false; 625 } 626 return wrapper.info.isActivityCovered(className); 627 } 628 629 @Override init()630 public void init() { 631 String safetyRegion = SystemProperties.get(PROPERTY_RO_DRIVING_SAFETY_REGION, ""); 632 synchronized (mLock) { 633 setDrivingSafetyRegionWithCheckLocked(safetyRegion); 634 mHandler.requestInit(); 635 } 636 CarLocalServices.getService(CarUserService.class).addUserLifecycleListener( 637 mUserLifecycleListener); 638 CarLocalServices.getService(CarPowerManagementService.class).addPowerPolicyListener( 639 new CarPowerPolicyFilter.Builder().setComponents(PowerComponent.DISPLAY).build(), 640 mDisplayPowerPolicyListener); 641 } 642 643 @Override release()644 public void release() { 645 CarLocalServices.getService(CarPowerManagementService.class).removePowerPolicyListener( 646 mDisplayPowerPolicyListener); 647 CarLocalServices.getService(CarUserService.class).removeUserLifecycleListener( 648 mUserLifecycleListener); 649 synchronized (mLock) { 650 mHandler.requestRelease(); 651 // wait for release do be done. This guarantees that init is done. 652 try { 653 mLock.wait(); 654 } catch (InterruptedException e) { 655 Slog.e(TAG, "Interrupted wait during release"); 656 Thread.currentThread().interrupt(); 657 } 658 mActivityAllowlistMap.clear(); 659 mActivityDenylistPackages.clear(); 660 mClientPolicies.clear(); 661 if (mProxies != null) { 662 for (AppBlockingPolicyProxy proxy : mProxies) { 663 proxy.disconnect(); 664 } 665 mProxies.clear(); 666 } 667 mWaitingPolicies.clear(); 668 resetTempAllowedActivitiesLocked(); 669 mLock.notifyAll(); 670 } 671 mContext.unregisterReceiver(mPackageParsingEventReceiver); 672 mSystemActivityMonitoringService.registerActivityLaunchListener(null); 673 for (int i = 0; i < mUxRestrictionsListeners.size(); i++) { 674 UxRestrictionsListener listener = mUxRestrictionsListeners.valueAt(i); 675 mCarUxRestrictionsService.unregisterUxRestrictionsChangeListener(listener); 676 } 677 } 678 679 @GuardedBy("mLock") setDrivingSafetyRegionWithCheckLocked(String region)680 private void setDrivingSafetyRegionWithCheckLocked(String region) { 681 if (region.isEmpty()) { 682 mCurrentDrivingSafetyRegion = CarPackageManager.DRIVING_SAFETY_REGION_ALL; 683 } else { 684 mCurrentDrivingSafetyRegion = region; 685 } 686 } 687 688 /** 689 * Reset driving stat and all dynamically added allow list so that region information for 690 * all packages are reset. This also resets one time allow list. 691 */ resetDrivingSafetyRegion(@onNull String region)692 public void resetDrivingSafetyRegion(@NonNull String region) { 693 synchronized (mLock) { 694 setDrivingSafetyRegionWithCheckLocked(region); 695 resetTempAllowedActivitiesLocked(); 696 mActivityAllowlistMap.clear(); 697 mActivityDenylistPackages.clear(); 698 } 699 } 700 701 // run from HandlerThread doHandleInit()702 private void doHandleInit() { 703 startAppBlockingPolicies(); 704 IntentFilter pkgParseIntent = new IntentFilter(); 705 for (String action : mPackageManagerActions) { 706 pkgParseIntent.addAction(action); 707 } 708 pkgParseIntent.addDataScheme("package"); 709 mContext.registerReceiverAsUser(mPackageParsingEventReceiver, UserHandle.ALL, 710 pkgParseIntent, null, null); 711 712 List<Display> physicalDisplays = getPhysicalDisplays(); 713 714 // Assume default display (display 0) is always a physical display. 715 Display defaultDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY); 716 if (!physicalDisplays.contains(defaultDisplay)) { 717 if (Log.isLoggable(TAG, Log.INFO)) { 718 Slog.i(TAG, "Adding default display to physical displays."); 719 } 720 physicalDisplays.add(defaultDisplay); 721 } 722 for (Display physicalDisplay : physicalDisplays) { 723 int displayId = physicalDisplay.getDisplayId(); 724 UxRestrictionsListener listener = new UxRestrictionsListener(mCarUxRestrictionsService); 725 mUxRestrictionsListeners.put(displayId, listener); 726 mCarUxRestrictionsService.registerUxRestrictionsChangeListener(listener, displayId); 727 } 728 mVendorServiceController.init(); 729 mSystemActivityMonitoringService.registerActivityLaunchListener(mActivityLaunchListener); 730 } 731 doParseInstalledPackage(String packageName)732 private void doParseInstalledPackage(String packageName) { 733 // Delete the package from allowlist and denylist mapping 734 synchronized (mLock) { 735 mActivityDenylistPackages.remove(packageName); 736 mActivityAllowlistMap.remove(packageName); 737 } 738 739 // Generate allowlist and denylist mapping for the package 740 updateActivityAllowlistAndDenylistMap(packageName); 741 blockTopActivitiesIfNecessary(); 742 } 743 doHandleRelease()744 private void doHandleRelease() { 745 synchronized (mLock) { 746 mVendorServiceController.release(); 747 mLock.notifyAll(); 748 } 749 } 750 doUpdatePolicy(String packageName, CarAppBlockingPolicy policy, int flags)751 private void doUpdatePolicy(String packageName, CarAppBlockingPolicy policy, int flags) { 752 if (Log.isLoggable(TAG, Log.DEBUG)) { 753 Slog.d(TAG, "setting policy from:" + packageName + ",policy:" + policy + ",flags:0x" 754 + Integer.toHexString(flags)); 755 } 756 AppBlockingPackageInfoWrapper[] blocklistWrapper = verifyList(policy.blacklists); 757 AppBlockingPackageInfoWrapper[] allowlistWrapper = verifyList(policy.whitelists); 758 synchronized (mLock) { 759 ClientPolicy clientPolicy = mClientPolicies.get(packageName); 760 if (clientPolicy == null) { 761 clientPolicy = new ClientPolicy(); 762 mClientPolicies.put(packageName, clientPolicy); 763 } 764 if ((flags & CarPackageManager.FLAG_SET_POLICY_ADD) != 0) { 765 clientPolicy.addToBlocklists(blocklistWrapper); 766 clientPolicy.addToAllowlists(allowlistWrapper); 767 } else if ((flags & CarPackageManager.FLAG_SET_POLICY_REMOVE) != 0) { 768 clientPolicy.removeBlocklists(blocklistWrapper); 769 clientPolicy.removeAllowlists(allowlistWrapper); 770 } else { //replace. 771 clientPolicy.replaceBlocklists(blocklistWrapper); 772 clientPolicy.replaceAllowlists(allowlistWrapper); 773 } 774 if ((flags & CarPackageManager.FLAG_SET_POLICY_WAIT_FOR_CHANGE) != 0) { 775 mWaitingPolicies.remove(policy); 776 mLock.notifyAll(); 777 } 778 if (Log.isLoggable(TAG, Log.DEBUG)) { 779 Slog.d(TAG, "policy set:" + dumpPoliciesLocked(false)); 780 } 781 } 782 blockTopActivitiesIfNecessary(); 783 } 784 verifyList(AppBlockingPackageInfo[] list)785 private AppBlockingPackageInfoWrapper[] verifyList(AppBlockingPackageInfo[] list) { 786 if (list == null) { 787 return null; 788 } 789 LinkedList<AppBlockingPackageInfoWrapper> wrappers = new LinkedList<>(); 790 for (int i = 0; i < list.length; i++) { 791 AppBlockingPackageInfo info = list[i]; 792 if (info == null) { 793 continue; 794 } 795 boolean isMatching = isInstalledPackageMatching(info); 796 wrappers.add(new AppBlockingPackageInfoWrapper(info, isMatching)); 797 } 798 return wrappers.toArray(new AppBlockingPackageInfoWrapper[wrappers.size()]); 799 } 800 isInstalledPackageMatching(AppBlockingPackageInfo info)801 boolean isInstalledPackageMatching(AppBlockingPackageInfo info) { 802 PackageInfo packageInfo; 803 try { 804 packageInfo = mPackageManager.getPackageInfo(info.packageName, 805 PackageManager.GET_SIGNATURES); 806 } catch (NameNotFoundException e) { 807 return false; 808 } 809 if (packageInfo == null) { 810 return false; 811 } 812 // if it is system app and client specified the flag, do not check signature 813 if ((info.flags & AppBlockingPackageInfo.FLAG_SYSTEM_APP) == 0 || 814 (!packageInfo.applicationInfo.isSystemApp() && 815 !packageInfo.applicationInfo.isUpdatedSystemApp())) { 816 Signature[] signatures = packageInfo.signatures; 817 if (!isAnySignatureMatching(signatures, info.signatures)) { 818 return false; 819 } 820 } 821 int version = packageInfo.versionCode; 822 if (info.minRevisionCode == 0) { 823 if (info.maxRevisionCode == 0) { // all versions 824 return true; 825 } else { // only max version matters 826 return info.maxRevisionCode > version; 827 } 828 } else { // min version matters 829 if (info.maxRevisionCode == 0) { 830 return info.minRevisionCode < version; 831 } else { 832 return (info.minRevisionCode < version) && (info.maxRevisionCode > version); 833 } 834 } 835 } 836 837 /** 838 * Any signature from policy matching with package's signatures is treated as matching. 839 */ isAnySignatureMatching(Signature[] fromPackage, Signature[] fromPolicy)840 boolean isAnySignatureMatching(Signature[] fromPackage, Signature[] fromPolicy) { 841 if (fromPackage == null) { 842 return false; 843 } 844 if (fromPolicy == null) { 845 return false; 846 } 847 ArraySet<Signature> setFromPackage = new ArraySet<Signature>(); 848 for (Signature sig : fromPackage) { 849 setFromPackage.add(sig); 850 } 851 for (Signature sig : fromPolicy) { 852 if (setFromPackage.contains(sig)) { 853 return true; 854 } 855 } 856 return false; 857 } 858 getPackageInfoWrapperForUser(String packageName, @UserIdInt int userId, Map<String, Set<String>> configAllowlist, Map<String, Set<String>> configBlocklist)859 private AppBlockingPackageInfoWrapper getPackageInfoWrapperForUser(String packageName, 860 @UserIdInt int userId, Map<String, Set<String>> configAllowlist, 861 Map<String, Set<String>> configBlocklist) { 862 PackageInfo info; 863 try { 864 info = mPackageManager.getPackageInfoAsUser(packageName, 865 PackageManager.GET_SIGNATURES | PackageManager.GET_ACTIVITIES 866 | PackageManager.MATCH_DIRECT_BOOT_AWARE 867 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE 868 | PackageManager.MATCH_DISABLED_COMPONENTS, 869 userId); 870 } catch (NameNotFoundException e) { 871 Slog.w(TAG, packageName + " not installed! User Id: " + userId); 872 return null; 873 } 874 875 876 if (info == null || info.applicationInfo == null) { 877 return null; 878 } 879 880 int flags = 0; 881 Set<String> activities = new ArraySet<>(); 882 883 if (info.applicationInfo.isSystemApp() 884 || info.applicationInfo.isUpdatedSystemApp()) { 885 flags = AppBlockingPackageInfo.FLAG_SYSTEM_APP; 886 } 887 888 /* 1. Check if all or some of this app is in the <activityAllowlist> or 889 <systemActivityAllowlist> in config.xml */ 890 Set<String> configActivitiesForPackage = configAllowlist.get(info.packageName); 891 if (configActivitiesForPackage != null) { 892 if (Log.isLoggable(TAG, Log.DEBUG)) { 893 Slog.d(TAG, info.packageName + " allowlisted"); 894 } 895 896 if (configActivitiesForPackage.isEmpty()) { 897 // Whole Pkg has been allowlisted 898 flags |= AppBlockingPackageInfo.FLAG_WHOLE_ACTIVITY; 899 // Add all activities to the allowlist 900 List<String> activitiesForPackage = getActivitiesInPackage(info); 901 if (activitiesForPackage != null) { 902 activities.addAll(activitiesForPackage); 903 } else { 904 if (Log.isLoggable(TAG, Log.DEBUG)) { 905 Slog.d(TAG, info.packageName + ": Activities null"); 906 } 907 } 908 } else { 909 if (Log.isLoggable(TAG, Log.DEBUG)) { 910 Slog.d(TAG, "Partially Allowlisted. WL Activities: " 911 + configActivitiesForPackage); 912 } 913 activities.addAll(configActivitiesForPackage); 914 } 915 } 916 /* 2. If app is not listed in the config.xml check their Manifest meta-data to 917 see if they have any Distraction Optimized(DO) activities. 918 For non system apps, we check if the app install source was a permittable 919 source. This prevents side-loaded apps to fake DO. Bypass the check 920 for debug builds for development convenience. */ 921 if (!isDebugBuild() 922 && !info.applicationInfo.isSystemApp() 923 && !info.applicationInfo.isUpdatedSystemApp()) { 924 try { 925 if (mAllowedAppInstallSources != null) { 926 String installerName = mPackageManager.getInstallerPackageName( 927 info.packageName); 928 if (installerName == null || (installerName != null 929 && !mAllowedAppInstallSources.contains(installerName))) { 930 Slog.w(TAG, 931 info.packageName + " not installed from permitted sources " 932 + (installerName == null ? "NULL" : installerName)); 933 return null; 934 } 935 } 936 } catch (IllegalArgumentException e) { 937 Slog.w(TAG, info.packageName + " not installed!"); 938 return null; 939 } 940 } 941 942 try { 943 String[] doActivities = findDistractionOptimizedActivitiesAsUser(info.packageName, 944 userId); 945 if (doActivities != null) { 946 // Some of the activities in this app are Distraction Optimized. 947 if (Log.isLoggable(TAG, Log.DEBUG)) { 948 for (String activity : doActivities) { 949 Slog.d(TAG, "adding " + activity + " from " + info.packageName 950 + " to allowlist"); 951 } 952 } 953 954 activities.addAll(Arrays.asList(doActivities)); 955 } 956 } catch (NameNotFoundException e) { 957 Slog.w(TAG, "Error reading metadata: " + info.packageName); 958 return null; 959 } 960 961 // Nothing to add to allowlist 962 if (activities.isEmpty()) { 963 return null; 964 } 965 966 /* 3. Check if parsed activity is in <activityBlocklist> in config.xml. Anything 967 in blocklist should not be allowlisted, either as D.O. or by config. */ 968 if (configBlocklist.containsKey(info.packageName)) { 969 Set<String> configBlocklistActivities = configBlocklist.get(info.packageName); 970 if (configBlocklistActivities.isEmpty()) { 971 // Whole package should be blocklisted. 972 return null; 973 } 974 activities.removeAll(configBlocklistActivities); 975 } 976 977 Signature[] signatures; 978 signatures = info.signatures; 979 AppBlockingPackageInfo appBlockingInfo = new AppBlockingPackageInfo(info.packageName, 980 /* minRevisionCode = */ 0, /* maxRevisionCode = */ 0, flags, signatures, 981 activities.toArray(new String[activities.size()])); 982 AppBlockingPackageInfoWrapper wrapper = new AppBlockingPackageInfoWrapper( 983 appBlockingInfo, true); 984 return wrapper; 985 } 986 987 /** 988 * Update map of allowlisted packages and activities of the form {pkgName, Allowlisted 989 * activities} and set of denylisted packages. The information can come from a configuration XML 990 * resource or from the apps marking their activities as distraction optimized. 991 */ updateActivityAllowlistAndDenylistMap(String packageName)992 private void updateActivityAllowlistAndDenylistMap(String packageName) { 993 int userId = mActivityManager.getCurrentUser(); 994 Slog.d(TAG, "Updating allowlist and denylist mapping for package: " + packageName 995 + " for UserId: " + userId); 996 // Get the apps/activities that are allowlisted in the configuration XML resources. 997 Map<String, Set<String>> configAllowlist = generateConfigAllowlist(); 998 Map<String, Set<String>> configBlocklist = generateConfigBlocklist(); 999 1000 AppBlockingPackageInfoWrapper wrapper = 1001 getPackageInfoWrapperForUser(packageName, userId, configAllowlist, configBlocklist); 1002 1003 if (wrapper == null && userId != UserHandle.USER_SYSTEM) { 1004 Slog.d(TAG, "Updating allowlist and denylist mapping for package: " + packageName 1005 + " for UserId: " + UserHandle.USER_SYSTEM); 1006 // check package for system user, in case package is disabled for current user 1007 wrapper = getPackageInfoWrapperForUser(packageName, UserHandle.USER_SYSTEM, 1008 configAllowlist, configBlocklist); 1009 } 1010 1011 synchronized (mLock) { 1012 if (wrapper != null) { 1013 if (DBG) { 1014 Slog.d(TAG, "Package: " + packageName + " added in allowlist."); 1015 } 1016 mActivityAllowlistMap.put(packageName, wrapper); 1017 } else { 1018 if (DBG) { 1019 Slog.d(TAG, "Package: " + packageName + " added in denylist."); 1020 } 1021 mActivityDenylistPackages.add(packageName); 1022 } 1023 } 1024 } 1025 generateConfigAllowlist()1026 private Map<String, Set<String>> generateConfigAllowlist() { 1027 synchronized (mLock) { 1028 if (mConfiguredAllowlistMap != null) return mConfiguredAllowlistMap; 1029 1030 Map<String, Set<String>> configAllowlist = new HashMap<>(); 1031 mConfiguredAllowlist = mContext.getString(R.string.activityAllowlist); 1032 if (mConfiguredAllowlist == null) { 1033 Slog.w(TAG, "Allowlist is null."); 1034 } 1035 parseConfigList(mConfiguredAllowlist, configAllowlist); 1036 1037 mConfiguredSystemAllowlist = mContext.getString(R.string.systemActivityAllowlist); 1038 if (mConfiguredSystemAllowlist == null) { 1039 Slog.w(TAG, "System allowlist is null."); 1040 } 1041 parseConfigList(mConfiguredSystemAllowlist, configAllowlist); 1042 1043 // Add the blocking overlay activity to the allowlist, since that needs to run in a 1044 // restricted state to communicate the reason an app was blocked. 1045 Set<String> defaultActivity = new ArraySet<>(); 1046 if (mActivityBlockingActivity != null) { 1047 defaultActivity.add(mActivityBlockingActivity.getClassName()); 1048 configAllowlist.put(mActivityBlockingActivity.getPackageName(), defaultActivity); 1049 } 1050 1051 mConfiguredAllowlistMap = configAllowlist; 1052 return configAllowlist; 1053 } 1054 } 1055 generateConfigBlocklist()1056 private Map<String, Set<String>> generateConfigBlocklist() { 1057 synchronized (mLock) { 1058 if (mConfiguredBlocklistMap != null) return mConfiguredBlocklistMap; 1059 1060 Map<String, Set<String>> configBlocklist = new HashMap<>(); 1061 mConfiguredBlocklist = mContext.getString(R.string.activityDenylist); 1062 if (mConfiguredBlocklist == null) { 1063 if (Log.isLoggable(TAG, Log.DEBUG)) { 1064 Slog.d(TAG, "Null blocklist in config"); 1065 } 1066 } 1067 parseConfigList(mConfiguredBlocklist, configBlocklist); 1068 1069 mConfiguredBlocklistMap = configBlocklist; 1070 return configBlocklist; 1071 } 1072 } 1073 isDebugBuild()1074 private boolean isDebugBuild() { 1075 return Build.IS_USERDEBUG || Build.IS_ENG; 1076 } 1077 1078 /** 1079 * Parses the given resource and updates the input map of packages and activities. 1080 * 1081 * Key is package name and value is list of activities. Empty set implies whole package is 1082 * included. 1083 * 1084 * When there are multiple entries regarding one package, the entry with 1085 * greater scope wins. Namely if there were 2 entries such that one allowlists 1086 * an activity, and the other allowlists the entire package of the activity, 1087 * the package is allowlisted, regardless of input order. 1088 */ 1089 @VisibleForTesting parseConfigList(String configList, @NonNull Map<String, Set<String>> packageToActivityMap)1090 /* package */ void parseConfigList(String configList, 1091 @NonNull Map<String, Set<String>> packageToActivityMap) { 1092 if (configList == null) { 1093 return; 1094 } 1095 String[] entries = configList.split(PACKAGE_DELIMITER); 1096 for (String entry : entries) { 1097 String[] packageActivityPair = entry.split(PACKAGE_ACTIVITY_DELIMITER); 1098 Set<String> activities = packageToActivityMap.get(packageActivityPair[0]); 1099 boolean newPackage = false; 1100 if (activities == null) { 1101 activities = new ArraySet<>(); 1102 newPackage = true; 1103 packageToActivityMap.put(packageActivityPair[0], activities); 1104 } 1105 if (packageActivityPair.length == 1) { // whole package 1106 activities.clear(); 1107 } else if (packageActivityPair.length == 2) { 1108 // add class name only when the whole package is not allowlisted. 1109 if (newPackage || (activities.size() > 0)) { 1110 activities.add(packageActivityPair[1]); 1111 } 1112 } 1113 } 1114 } 1115 1116 @Nullable getActivitiesInPackage(PackageInfo info)1117 private List<String> getActivitiesInPackage(PackageInfo info) { 1118 if (info == null || info.activities == null) { 1119 return null; 1120 } 1121 List<String> activityList = new ArrayList<>(); 1122 for (ActivityInfo aInfo : info.activities) { 1123 activityList.add(aInfo.name); 1124 } 1125 return activityList; 1126 } 1127 1128 /** 1129 * Checks if there are any {@link CarAppBlockingPolicyService} and creates a proxy to 1130 * bind to them and retrieve the {@link CarAppBlockingPolicy} 1131 */ 1132 @VisibleForTesting startAppBlockingPolicies()1133 public void startAppBlockingPolicies() { 1134 Intent policyIntent = new Intent(); 1135 policyIntent.setAction(CarAppBlockingPolicyService.SERVICE_INTERFACE); 1136 List<ResolveInfo> policyInfos = mPackageManager.queryIntentServices(policyIntent, 0); 1137 if (policyInfos == null) { //no need to wait for service binding and retrieval. 1138 return; 1139 } 1140 LinkedList<AppBlockingPolicyProxy> proxies = new LinkedList<>(); 1141 for (ResolveInfo resolveInfo : policyInfos) { 1142 ServiceInfo serviceInfo = resolveInfo.serviceInfo; 1143 if (serviceInfo == null) { 1144 continue; 1145 } 1146 if (serviceInfo.isEnabled()) { 1147 if (mPackageManager.checkPermission(Car.PERMISSION_CONTROL_APP_BLOCKING, 1148 serviceInfo.packageName) != PackageManager.PERMISSION_GRANTED) { 1149 continue; 1150 } 1151 Slog.i(TAG, "found policy holding service:" + serviceInfo); 1152 AppBlockingPolicyProxy proxy = new AppBlockingPolicyProxy(this, mContext, 1153 serviceInfo); 1154 proxy.connect(); 1155 proxies.add(proxy); 1156 } 1157 } 1158 synchronized (mLock) { 1159 mProxies = proxies; 1160 } 1161 } 1162 onPolicyConnectionAndSet(AppBlockingPolicyProxy proxy, CarAppBlockingPolicy policy)1163 public void onPolicyConnectionAndSet(AppBlockingPolicyProxy proxy, 1164 CarAppBlockingPolicy policy) { 1165 doHandlePolicyConnection(proxy, policy); 1166 } 1167 onPolicyConnectionFailure(AppBlockingPolicyProxy proxy)1168 public void onPolicyConnectionFailure(AppBlockingPolicyProxy proxy) { 1169 doHandlePolicyConnection(proxy, null); 1170 } 1171 doHandlePolicyConnection(AppBlockingPolicyProxy proxy, CarAppBlockingPolicy policy)1172 private void doHandlePolicyConnection(AppBlockingPolicyProxy proxy, 1173 CarAppBlockingPolicy policy) { 1174 synchronized (mLock) { 1175 if (mProxies == null) { 1176 proxy.disconnect(); 1177 return; 1178 } 1179 mProxies.remove(proxy); 1180 if (mProxies.size() == 0) { 1181 mProxies = null; 1182 } 1183 } 1184 try { 1185 if (policy != null) { 1186 if (Log.isLoggable(TAG, Log.DEBUG)) { 1187 Slog.d(TAG, "policy setting from policy service:" + proxy.getPackageName()); 1188 } 1189 doSetAppBlockingPolicy(proxy.getPackageName(), policy, 0); 1190 } 1191 } finally { 1192 proxy.disconnect(); 1193 } 1194 } 1195 1196 @Override dump(IndentingPrintWriter writer)1197 public void dump(IndentingPrintWriter writer) { 1198 synchronized (mLock) { 1199 writer.println("*CarPackageManagerService*"); 1200 writer.println("mEnableActivityBlocking:" + mEnableActivityBlocking); 1201 writer.println("mPreventTemplatedAppsFromShowingDialog:" 1202 + mPreventTemplatedAppsFromShowingDialog); 1203 writer.println("mTemplateActivityClassName:" + mTemplateActivityClassName); 1204 List<String> restrictions = new ArrayList<>(mUxRestrictionsListeners.size()); 1205 for (int i = 0; i < mUxRestrictionsListeners.size(); i++) { 1206 int displayId = mUxRestrictionsListeners.keyAt(i); 1207 UxRestrictionsListener listener = mUxRestrictionsListeners.valueAt(i); 1208 restrictions.add(String.format("Display %d is %s", 1209 displayId, (listener.isRestricted() ? "restricted" : "unrestricted"))); 1210 } 1211 writer.println("Display Restrictions:\n" + String.join("\n", restrictions)); 1212 writer.println(" Blocked activity log:"); 1213 mBlockedActivityLogs.dump(writer); 1214 writer.print(dumpPoliciesLocked(true)); 1215 writer.print("mCurrentDrivingSafetyRegion:"); 1216 writer.println(mCurrentDrivingSafetyRegion); 1217 writer.print("mTempAllowedActivities:"); 1218 writer.println(mTempAllowedActivities); 1219 } 1220 } 1221 1222 @GuardedBy("mLock") dumpPoliciesLocked(boolean dumpAll)1223 private String dumpPoliciesLocked(boolean dumpAll) { 1224 StringBuilder sb = new StringBuilder(); 1225 if (dumpAll) { 1226 sb.append("**System allowlist**\n"); 1227 for (AppBlockingPackageInfoWrapper wrapper : mActivityAllowlistMap.values()) { 1228 sb.append(wrapper.toString() + "\n"); 1229 } 1230 } 1231 sb.append("**Client Policies**\n"); 1232 for (Entry<String, ClientPolicy> entry : mClientPolicies.entrySet()) { 1233 sb.append("Client:" + entry.getKey() + "\n"); 1234 sb.append(" allowlists:\n"); 1235 for (AppBlockingPackageInfoWrapper wrapper : entry.getValue().mAllowlistsMap.values()) { 1236 sb.append(wrapper.toString() + "\n"); 1237 } 1238 sb.append(" blocklists:\n"); 1239 for (AppBlockingPackageInfoWrapper wrapper : entry.getValue().mBlocklistsMap.values()) { 1240 sb.append(wrapper.toString() + "\n"); 1241 } 1242 } 1243 sb.append("**Unprocessed policy services**\n"); 1244 if (mProxies != null) { 1245 for (AppBlockingPolicyProxy proxy : mProxies) { 1246 sb.append(proxy.toString() + "\n"); 1247 } 1248 } 1249 sb.append("**Allowlist string in resource**\n"); 1250 sb.append(mConfiguredAllowlist + "\n"); 1251 1252 sb.append("**System allowlist string in resource**\n"); 1253 sb.append(mConfiguredSystemAllowlist + "\n"); 1254 1255 sb.append("**Blocklist string in resource**\n"); 1256 sb.append(mConfiguredBlocklist + "\n"); 1257 1258 sb.append("**Allowlist map from resource**\n"); 1259 sb.append(mConfiguredAllowlistMap + "\n"); 1260 1261 sb.append("**Blocklist from resource**\n"); 1262 sb.append(mConfiguredBlocklist + "\n"); 1263 1264 return sb.toString(); 1265 } 1266 1267 /** 1268 * Returns display with physical address. 1269 */ getPhysicalDisplays()1270 private List<Display> getPhysicalDisplays() { 1271 List<Display> displays = new ArrayList<>(); 1272 for (Display display : mDisplayManager.getDisplays()) { 1273 if (display.getAddress() instanceof DisplayAddress.Physical) { 1274 displays.add(display); 1275 } 1276 } 1277 return displays; 1278 } 1279 1280 /** 1281 * Returns whether UX restrictions is required for display. 1282 * 1283 * Non-physical display will use restrictions for {@link Display#DEFAULT_DISPLAY}. 1284 */ isUxRestrictedOnDisplay(int displayId)1285 private boolean isUxRestrictedOnDisplay(int displayId) { 1286 UxRestrictionsListener listenerForTopTaskDisplay; 1287 if (mUxRestrictionsListeners.indexOfKey(displayId) < 0) { 1288 listenerForTopTaskDisplay = mUxRestrictionsListeners.get(Display.DEFAULT_DISPLAY); 1289 if (listenerForTopTaskDisplay == null) { 1290 // This should never happen. 1291 Slog.e(TAG, "Missing listener for default display."); 1292 return true; 1293 } 1294 } else { 1295 listenerForTopTaskDisplay = mUxRestrictionsListeners.get(displayId); 1296 } 1297 1298 return listenerForTopTaskDisplay.isRestricted(); 1299 } 1300 blockTopActivitiesIfNecessary()1301 private void blockTopActivitiesIfNecessary() { 1302 List<TopTaskInfoContainer> topTasks = mSystemActivityMonitoringService.getTopTasks(); 1303 for (TopTaskInfoContainer topTask : topTasks) { 1304 if (topTask == null) { 1305 Slog.e(TAG, "Top tasks contains null."); 1306 continue; 1307 } 1308 blockTopActivityIfNecessary(topTask); 1309 } 1310 } 1311 blockTopActivityIfNecessary(TopTaskInfoContainer topTask)1312 private void blockTopActivityIfNecessary(TopTaskInfoContainer topTask) { 1313 synchronized (mLock) { 1314 if (!Objects.equals(mActivityBlockingActivity, topTask.topActivity) 1315 && mTopActivityWithDialogPerDisplay.contains(topTask.displayId) 1316 && !topTask.topActivity.equals( 1317 mTopActivityWithDialogPerDisplay.get(topTask.displayId))) { 1318 // Clear top activity-with-dialog if the activity has changed on this display. 1319 mTopActivityWithDialogPerDisplay.remove(topTask.displayId); 1320 } 1321 } 1322 if (isUxRestrictedOnDisplay(topTask.displayId)) { 1323 doBlockTopActivityIfNotAllowed(topTask); 1324 } 1325 } 1326 doBlockTopActivityIfNotAllowed(TopTaskInfoContainer topTask)1327 private void doBlockTopActivityIfNotAllowed(TopTaskInfoContainer topTask) { 1328 if (topTask.topActivity == null) { 1329 return; 1330 } 1331 boolean allowed = isActivityAllowed(topTask); 1332 if (Log.isLoggable(TAG, Log.DEBUG)) { 1333 Slog.d(TAG, "new activity:" + topTask.toString() + " allowed:" + allowed); 1334 } 1335 if (allowed) { 1336 return; 1337 } 1338 if (!mEnableActivityBlocking) { 1339 Slog.d(TAG, "Current activity " + topTask.topActivity 1340 + " not allowed, blocking disabled. Number of tasks in stack:" 1341 + topTask.taskInfo.childTaskIds.length); 1342 return; 1343 } 1344 if (Log.isLoggable(TAG, Log.DEBUG)) { 1345 Slog.d(TAG, "Current activity " + topTask.topActivity 1346 + " not allowed, will block, number of tasks in stack:" 1347 + topTask.taskInfo.childTaskIds.length); 1348 } 1349 1350 // Figure out the root activity of blocked task. 1351 String taskRootActivity = null; 1352 for (int i = 0; i < topTask.taskInfo.childTaskIds.length; i++) { 1353 // topTask.taskId is the task that should be blocked. 1354 if (topTask.taskInfo.childTaskIds[i] == topTask.taskId) { 1355 // stackInfo represents an ActivityStack. Its fields taskIds and taskNames 1356 // are 1:1 mapped, where taskNames is the name of root activity in this task. 1357 taskRootActivity = topTask.taskInfo.childTaskNames[i]; 1358 break; 1359 } 1360 } 1361 1362 boolean isRootDO = false; 1363 if (taskRootActivity != null) { 1364 ComponentName taskRootComponentName = 1365 ComponentName.unflattenFromString(taskRootActivity); 1366 isRootDO = isActivityDistractionOptimized( 1367 taskRootComponentName.getPackageName(), taskRootComponentName.getClassName()); 1368 } 1369 1370 Intent newActivityIntent = createBlockingActivityIntent( 1371 mActivityBlockingActivity, topTask.displayId, 1372 topTask.topActivity.flattenToShortString(), topTask.taskId, taskRootActivity, 1373 isRootDO); 1374 1375 // Intent contains all info to debug what is blocked - log into both logcat and dumpsys. 1376 String log = "Starting blocking activity with intent: " + newActivityIntent.toUri(0); 1377 if (Log.isLoggable(TAG, Log.INFO)) { 1378 Slog.i(TAG, log); 1379 } 1380 mBlockedActivityLogs.log(log); 1381 mSystemActivityMonitoringService.blockActivity(topTask, newActivityIntent); 1382 } 1383 isActivityAllowed(TopTaskInfoContainer topTaskInfoContainer)1384 private boolean isActivityAllowed(TopTaskInfoContainer topTaskInfoContainer) { 1385 ComponentName activityName = topTaskInfoContainer.topActivity; 1386 boolean isDistractionOptimized = isActivityDistractionOptimized( 1387 activityName.getPackageName(), 1388 activityName.getClassName()); 1389 if (!isDistractionOptimized) { 1390 return false; 1391 } 1392 return !(mPreventTemplatedAppsFromShowingDialog 1393 && isTemplateActivity(activityName) 1394 && isActivityShowingADialogOnDisplay(activityName, topTaskInfoContainer.displayId)); 1395 } 1396 isTemplateActivity(ComponentName activityName)1397 private boolean isTemplateActivity(ComponentName activityName) { 1398 // TODO(b/191263486): Finalise on how to detect the templated activities. 1399 return activityName.getClassName().equals(mTemplateActivityClassName); 1400 } 1401 isActivityShowingADialogOnDisplay(ComponentName activityName, int displayId)1402 private boolean isActivityShowingADialogOnDisplay(ComponentName activityName, int displayId) { 1403 String output = dumpWindows(); 1404 List<WindowDumpParser.Window> appWindows = 1405 WindowDumpParser.getParsedAppWindows(output, activityName.getPackageName()); 1406 // TODO(b/192354699): Handle case where an activity can have multiple instances on the same 1407 // display. 1408 int totalAppWindows = appWindows.size(); 1409 String firstActivityRecord = null; 1410 int numTopActivityAppWindowsOnDisplay = 0; 1411 for (int i = 0; i < totalAppWindows; i++) { 1412 WindowDumpParser.Window appWindow = appWindows.get(i); 1413 if (appWindow.getDisplayId() != displayId) { 1414 continue; 1415 } 1416 if (TextUtils.isEmpty(appWindow.getActivityRecord())) { 1417 continue; 1418 } 1419 if (firstActivityRecord == null) { 1420 firstActivityRecord = appWindow.getActivityRecord(); 1421 } 1422 if (firstActivityRecord.equals(appWindow.getActivityRecord())) { 1423 numTopActivityAppWindowsOnDisplay++; 1424 } 1425 } 1426 Slogf.d(TAG, "Top activity = " + activityName); 1427 Slogf.d(TAG, "Number of app widows of top activity = " + numTopActivityAppWindowsOnDisplay); 1428 boolean isShowingADialog = numTopActivityAppWindowsOnDisplay > 1; 1429 synchronized (mLock) { 1430 if (isShowingADialog) { 1431 mTopActivityWithDialogPerDisplay.put(displayId, activityName); 1432 } else { 1433 mTopActivityWithDialogPerDisplay.remove(displayId); 1434 } 1435 } 1436 return isShowingADialog; 1437 } 1438 dumpWindows()1439 private String dumpWindows() { 1440 try { 1441 ParcelFileDescriptor[] fileDescriptors = ParcelFileDescriptor.createSocketPair(); 1442 mWindowManagerBinder.dump( 1443 fileDescriptors[0].getFileDescriptor(), WINDOW_DUMP_ARGUMENTS); 1444 fileDescriptors[0].close(); 1445 StringBuilder outputBuilder = new StringBuilder(); 1446 BufferedReader reader = new BufferedReader( 1447 new FileReader(fileDescriptors[1].getFileDescriptor())); 1448 String line; 1449 while ((line = reader.readLine()) != null) { 1450 outputBuilder.append(line).append("\n"); 1451 } 1452 reader.close(); 1453 fileDescriptors[1].close(); 1454 return outputBuilder.toString(); 1455 } catch (IOException | RemoteException e) { 1456 throw new RuntimeException(e); 1457 } 1458 } 1459 1460 /** 1461 * Creates an intent to start blocking activity. 1462 * 1463 * @param blockingActivity the activity to launch 1464 * @param blockedActivity the activity being blocked 1465 * @param blockedTaskId the blocked task id, which contains the blocked activity 1466 * @param taskRootActivity root activity of the blocked task 1467 * @param isRootDo denotes if the root activity is distraction optimised 1468 * @return an intent to launch the blocking activity. 1469 */ createBlockingActivityIntent(ComponentName blockingActivity, int displayId, String blockedActivity, int blockedTaskId, String taskRootActivity, boolean isRootDo)1470 private static Intent createBlockingActivityIntent(ComponentName blockingActivity, 1471 int displayId, String blockedActivity, int blockedTaskId, String taskRootActivity, 1472 boolean isRootDo) { 1473 Intent newActivityIntent = new Intent(); 1474 newActivityIntent.setFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); 1475 newActivityIntent.setComponent(blockingActivity); 1476 newActivityIntent.putExtra( 1477 BLOCKING_INTENT_EXTRA_DISPLAY_ID, displayId); 1478 newActivityIntent.putExtra( 1479 BLOCKING_INTENT_EXTRA_BLOCKED_ACTIVITY_NAME, blockedActivity); 1480 newActivityIntent.putExtra( 1481 BLOCKING_INTENT_EXTRA_BLOCKED_TASK_ID, blockedTaskId); 1482 newActivityIntent.putExtra( 1483 BLOCKING_INTENT_EXTRA_ROOT_ACTIVITY_NAME, taskRootActivity); 1484 newActivityIntent.putExtra( 1485 BLOCKING_INTENT_EXTRA_IS_ROOT_ACTIVITY_DO, isRootDo); 1486 1487 return newActivityIntent; 1488 } 1489 1490 /** 1491 * Enable/Disable activity blocking by correspondingly enabling/disabling broadcasting UXR 1492 * changes in {@link CarUxRestrictionsManagerService}. This is only available in 1493 * engineering builds for development convenience. 1494 */ 1495 @Override setEnableActivityBlocking(boolean enable)1496 public void setEnableActivityBlocking(boolean enable) { 1497 if (!isDebugBuild()) { 1498 Slog.e(TAG, "Cannot enable/disable activity blocking"); 1499 return; 1500 } 1501 1502 // Check if the caller has the same signature as that of the car service. 1503 if (mPackageManager.checkSignatures(Process.myUid(), Binder.getCallingUid()) 1504 != PackageManager.SIGNATURE_MATCH) { 1505 throw new SecurityException( 1506 "Caller " + mPackageManager.getNameForUid(Binder.getCallingUid()) 1507 + " does not have the right signature"); 1508 } 1509 mCarUxRestrictionsService.setUxRChangeBroadcastEnabled(enable); 1510 } 1511 1512 /** 1513 * Get the distraction optimized activities for the given package. 1514 * 1515 * @param pkgName Name of the package 1516 * @return Array of the distraction optimized activities in the package 1517 */ 1518 @Nullable getDistractionOptimizedActivities(String pkgName)1519 public String[] getDistractionOptimizedActivities(String pkgName) { 1520 try { 1521 return findDistractionOptimizedActivitiesAsUser(pkgName, 1522 mActivityManager.getCurrentUser()); 1523 } catch (NameNotFoundException e) { 1524 return null; 1525 } 1526 } 1527 findDistractionOptimizedActivitiesAsUser(String pkgName, int userId)1528 private String[] findDistractionOptimizedActivitiesAsUser(String pkgName, int userId) 1529 throws NameNotFoundException { 1530 String regionString; 1531 synchronized (mLock) { 1532 regionString = mCurrentDrivingSafetyRegion; 1533 } 1534 return CarAppMetadataReader.findDistractionOptimizedActivitiesAsUser(mContext, pkgName, 1535 userId, regionString); 1536 } 1537 1538 /** 1539 * Reading policy and setting policy can take time. Run it in a separate handler thread. 1540 */ 1541 private static final class PackageHandler extends Handler { 1542 private static final String TAG = CarLog.tagFor(CarPackageManagerService.class); 1543 1544 private static final int MSG_INIT = 0; 1545 private static final int MSG_PARSE_PKG = 1; 1546 private static final int MSG_UPDATE_POLICY = 2; 1547 private static final int MSG_RELEASE = 3; 1548 1549 private final WeakReference<CarPackageManagerService> mService; 1550 PackageHandler(Looper looper, CarPackageManagerService service)1551 private PackageHandler(Looper looper, CarPackageManagerService service) { 1552 super(looper); 1553 mService = new WeakReference<CarPackageManagerService>(service); 1554 } 1555 requestInit()1556 private void requestInit() { 1557 Message msg = obtainMessage(MSG_INIT); 1558 sendMessage(msg); 1559 } 1560 requestRelease()1561 private void requestRelease() { 1562 removeMessages(MSG_UPDATE_POLICY); 1563 Message msg = obtainMessage(MSG_RELEASE); 1564 sendMessage(msg); 1565 } 1566 requestUpdatingPolicy(String packageName, CarAppBlockingPolicy policy, int flags)1567 private void requestUpdatingPolicy(String packageName, CarAppBlockingPolicy policy, 1568 int flags) { 1569 Pair<String, CarAppBlockingPolicy> pair = new Pair<>(packageName, policy); 1570 Message msg = obtainMessage(MSG_UPDATE_POLICY, flags, 0, pair); 1571 sendMessage(msg); 1572 } 1573 requestParsingInstalledPkg(String packageName)1574 private void requestParsingInstalledPkg(String packageName) { 1575 Message msg = obtainMessage(MSG_PARSE_PKG, packageName); 1576 sendMessage(msg); 1577 } 1578 1579 @Override handleMessage(Message msg)1580 public void handleMessage(Message msg) { 1581 CarPackageManagerService service = mService.get(); 1582 if (service == null) { 1583 Slog.i(TAG, "handleMessage null service"); 1584 return; 1585 } 1586 switch (msg.what) { 1587 case MSG_INIT: 1588 service.doHandleInit(); 1589 break; 1590 case MSG_PARSE_PKG: 1591 service.doParseInstalledPackage((String) msg.obj); 1592 break; 1593 case MSG_UPDATE_POLICY: 1594 Pair<String, CarAppBlockingPolicy> pair = 1595 (Pair<String, CarAppBlockingPolicy>) msg.obj; 1596 service.doUpdatePolicy(pair.first, pair.second, msg.arg1); 1597 break; 1598 case MSG_RELEASE: 1599 service.doHandleRelease(); 1600 break; 1601 } 1602 } 1603 } 1604 1605 private static class AppBlockingPackageInfoWrapper { 1606 private final AppBlockingPackageInfo info; 1607 /** 1608 * Whether the current info is matching with the target package in system. Mismatch can 1609 * happen for version out of range or signature mismatch. 1610 */ 1611 private boolean isMatching; 1612 AppBlockingPackageInfoWrapper(AppBlockingPackageInfo info, boolean isMatching)1613 private AppBlockingPackageInfoWrapper(AppBlockingPackageInfo info, boolean isMatching) { 1614 this.info = info; 1615 this.isMatching = isMatching; 1616 } 1617 1618 @Override toString()1619 public String toString() { 1620 return "AppBlockingPackageInfoWrapper [info=" + info + ", isMatching=" + isMatching + 1621 "]"; 1622 } 1623 } 1624 1625 /** 1626 * Client policy holder per each client. Should be accessed with CarpackageManagerService.this 1627 * held. 1628 */ 1629 private static class ClientPolicy { 1630 private final HashMap<String, AppBlockingPackageInfoWrapper> mAllowlistsMap = 1631 new HashMap<>(); 1632 private final HashMap<String, AppBlockingPackageInfoWrapper> mBlocklistsMap = 1633 new HashMap<>(); 1634 replaceAllowlists(AppBlockingPackageInfoWrapper[] allowlists)1635 private void replaceAllowlists(AppBlockingPackageInfoWrapper[] allowlists) { 1636 mAllowlistsMap.clear(); 1637 addToAllowlists(allowlists); 1638 } 1639 addToAllowlists(AppBlockingPackageInfoWrapper[] allowlists)1640 private void addToAllowlists(AppBlockingPackageInfoWrapper[] allowlists) { 1641 if (allowlists == null) { 1642 return; 1643 } 1644 for (AppBlockingPackageInfoWrapper wrapper : allowlists) { 1645 if (wrapper != null) { 1646 mAllowlistsMap.put(wrapper.info.packageName, wrapper); 1647 } 1648 } 1649 } 1650 removeAllowlists(AppBlockingPackageInfoWrapper[] allowlists)1651 private void removeAllowlists(AppBlockingPackageInfoWrapper[] allowlists) { 1652 if (allowlists == null) { 1653 return; 1654 } 1655 for (AppBlockingPackageInfoWrapper wrapper : allowlists) { 1656 if (wrapper != null) { 1657 mAllowlistsMap.remove(wrapper.info.packageName); 1658 } 1659 } 1660 } 1661 replaceBlocklists(AppBlockingPackageInfoWrapper[] blocklists)1662 private void replaceBlocklists(AppBlockingPackageInfoWrapper[] blocklists) { 1663 mBlocklistsMap.clear(); 1664 addToBlocklists(blocklists); 1665 } 1666 addToBlocklists(AppBlockingPackageInfoWrapper[] blocklists)1667 private void addToBlocklists(AppBlockingPackageInfoWrapper[] blocklists) { 1668 if (blocklists == null) { 1669 return; 1670 } 1671 for (AppBlockingPackageInfoWrapper wrapper : blocklists) { 1672 if (wrapper != null) { 1673 mBlocklistsMap.put(wrapper.info.packageName, wrapper); 1674 } 1675 } 1676 } 1677 removeBlocklists(AppBlockingPackageInfoWrapper[] blocklists)1678 private void removeBlocklists(AppBlockingPackageInfoWrapper[] blocklists) { 1679 if (blocklists == null) { 1680 return; 1681 } 1682 for (AppBlockingPackageInfoWrapper wrapper : blocklists) { 1683 if (wrapper != null) { 1684 mBlocklistsMap.remove(wrapper.info.packageName); 1685 } 1686 } 1687 } 1688 } 1689 1690 private class ActivityLaunchListener 1691 implements SystemActivityMonitoringService.ActivityLaunchListener { 1692 @Override onActivityLaunch(TopTaskInfoContainer topTask)1693 public void onActivityLaunch(TopTaskInfoContainer topTask) { 1694 if (topTask == null) { 1695 Slog.e(TAG, "Received callback with null top task."); 1696 return; 1697 } 1698 blockTopActivityIfNecessary(topTask); 1699 } 1700 } 1701 1702 /** 1703 * Listens to the UX restrictions from {@link CarUxRestrictionsManagerService} and initiates 1704 * checking if the foreground Activity should be blocked. 1705 */ 1706 private class UxRestrictionsListener extends ICarUxRestrictionsChangeListener.Stub { 1707 @GuardedBy("mLock") 1708 @Nullable 1709 private CarUxRestrictions mCurrentUxRestrictions; 1710 private final CarUxRestrictionsManagerService uxRestrictionsService; 1711 UxRestrictionsListener(CarUxRestrictionsManagerService service)1712 public UxRestrictionsListener(CarUxRestrictionsManagerService service) { 1713 uxRestrictionsService = service; 1714 } 1715 1716 @Override onUxRestrictionsChanged(CarUxRestrictions restrictions)1717 public void onUxRestrictionsChanged(CarUxRestrictions restrictions) { 1718 if (Log.isLoggable(TAG, Log.DEBUG)) { 1719 Slog.d(TAG, "Received uxr restrictions: " 1720 + restrictions.isRequiresDistractionOptimization() + " : " 1721 + restrictions.getActiveRestrictions()); 1722 } 1723 1724 synchronized (mLock) { 1725 mCurrentUxRestrictions = new CarUxRestrictions(restrictions); 1726 } 1727 checkIfTopActivityNeedsBlocking(); 1728 } 1729 checkIfTopActivityNeedsBlocking()1730 private void checkIfTopActivityNeedsBlocking() { 1731 boolean shouldCheck = false; 1732 synchronized (mLock) { 1733 if (mCurrentUxRestrictions != null 1734 && mCurrentUxRestrictions.isRequiresDistractionOptimization()) { 1735 shouldCheck = true; 1736 } 1737 } 1738 if (Log.isLoggable(TAG, Log.DEBUG)) { 1739 Slog.d(TAG, "Should check top tasks?: " + shouldCheck); 1740 } 1741 if (shouldCheck) { 1742 // Loop over all top tasks to ensure tasks on virtual display can also be blocked. 1743 blockTopActivitiesIfNecessary(); 1744 } 1745 } 1746 isRestricted()1747 private boolean isRestricted() { 1748 // if current restrictions is null, try querying the service, once. 1749 synchronized (mLock) { 1750 if (mCurrentUxRestrictions == null) { 1751 mCurrentUxRestrictions = uxRestrictionsService.getCurrentUxRestrictions(); 1752 } 1753 if (mCurrentUxRestrictions != null) { 1754 return mCurrentUxRestrictions.isRequiresDistractionOptimization(); 1755 } 1756 } 1757 1758 // If restriction information is still not available (could happen during bootup), 1759 // return not restricted. This maintains parity with previous implementation but needs 1760 // a revisit as we test more. 1761 return false; 1762 } 1763 } 1764 1765 /** 1766 * Called when a window change event is received by the {@link CarSafetyAccessibilityService}. 1767 */ 1768 @VisibleForTesting onWindowChangeEvent()1769 void onWindowChangeEvent() { 1770 Slogf.d(TAG, "onWindowChange event received"); 1771 mHandlerThread.getThreadHandler().post(() -> blockTopActivitiesIfNecessary()); 1772 } 1773 1774 /** 1775 * Listens to the package install/uninstall events to know when to initiate parsing 1776 * installed packages. 1777 */ 1778 private class PackageParsingEventReceiver extends BroadcastReceiver { 1779 @Override onReceive(Context context, Intent intent)1780 public void onReceive(Context context, Intent intent) { 1781 if (intent == null || intent.getAction() == null) { 1782 return; 1783 } 1784 if (Log.isLoggable(TAG, Log.DEBUG)) { 1785 Slog.d(TAG, "PackageParsingEventReceiver Received " + intent.getAction()); 1786 } 1787 String action = intent.getAction(); 1788 if (isPackageManagerAction(action)) { 1789 // send a delayed message so if we received multiple related intents, we parse 1790 // only once. 1791 logEventChange(intent); 1792 String packageName = getPackageName(intent); 1793 mHandler.requestParsingInstalledPkg(packageName); 1794 } 1795 } 1796 getPackageName(Intent intent)1797 private String getPackageName(Intent intent) { 1798 // For mPackageManagerActions, data should contain package name. 1799 String dataString = intent.getDataString(); 1800 if (dataString == null) return null; 1801 1802 String scheme = intent.getScheme(); 1803 if (!scheme.equals("package")) return null; 1804 1805 String[] splitData = intent.getDataString().split(":"); 1806 if (splitData.length < 2) return null; 1807 1808 return splitData[1]; 1809 } 1810 isPackageManagerAction(String action)1811 private boolean isPackageManagerAction(String action) { 1812 return mPackageManagerActions.contains(action); 1813 } 1814 1815 /** 1816 * Convenience log function to log what changed. Logs only when more debug logs 1817 * are needed - DBG_POLICY_CHECK needs to be true 1818 */ logEventChange(Intent intent)1819 private void logEventChange(Intent intent) { 1820 if (intent == null) { 1821 return; 1822 } 1823 if (Log.isLoggable(TAG, Log.DEBUG)) { 1824 String packageName = intent.getData().getSchemeSpecificPart(); 1825 Slog.d(TAG, "Pkg Changed:" + packageName); 1826 String action = intent.getAction(); 1827 if (action == null) { 1828 return; 1829 } 1830 if (action.equals(Intent.ACTION_PACKAGE_CHANGED)) { 1831 Slog.d(TAG, "Changed components"); 1832 String[] cc = intent 1833 .getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST); 1834 if (cc != null) { 1835 for (String c : cc) { 1836 Slog.d(TAG, c); 1837 } 1838 } 1839 } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED) 1840 || action.equals(Intent.ACTION_PACKAGE_ADDED)) { 1841 Slog.d(TAG, action + " Replacing?: " 1842 + intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)); 1843 } 1844 } 1845 } 1846 } 1847 } 1848