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