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