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 android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.app.ActivityManager; 22 import android.app.ActivityManager.StackInfo; 23 import android.car.Car; 24 import android.car.content.pm.AppBlockingPackageInfo; 25 import android.car.content.pm.CarAppBlockingPolicy; 26 import android.car.content.pm.CarAppBlockingPolicyService; 27 import android.car.content.pm.CarPackageManager; 28 import android.car.content.pm.ICarPackageManager; 29 import android.car.drivingstate.CarUxRestrictions; 30 import android.car.drivingstate.ICarUxRestrictionsChangeListener; 31 import android.car.userlib.CarUserManagerHelper; 32 import android.content.BroadcastReceiver; 33 import android.content.ComponentName; 34 import android.content.Context; 35 import android.content.Intent; 36 import android.content.IntentFilter; 37 import android.content.pm.ActivityInfo; 38 import android.content.pm.PackageInfo; 39 import android.content.pm.PackageManager; 40 import android.content.pm.PackageManager.NameNotFoundException; 41 import android.content.pm.ResolveInfo; 42 import android.content.pm.ServiceInfo; 43 import android.content.pm.Signature; 44 import android.content.res.Resources; 45 import android.hardware.display.DisplayManager; 46 import android.os.Binder; 47 import android.os.Build; 48 import android.os.Handler; 49 import android.os.HandlerThread; 50 import android.os.Looper; 51 import android.os.Message; 52 import android.os.Process; 53 import android.os.UserHandle; 54 import android.text.format.DateFormat; 55 import android.util.ArraySet; 56 import android.util.Log; 57 import android.util.Pair; 58 import android.util.SparseArray; 59 import android.view.Display; 60 import android.view.DisplayAddress; 61 62 import com.android.car.CarLog; 63 import com.android.car.CarServiceBase; 64 import com.android.car.CarServiceUtils; 65 import com.android.car.CarUxRestrictionsManagerService; 66 import com.android.car.R; 67 import com.android.car.SystemActivityMonitoringService; 68 import com.android.car.SystemActivityMonitoringService.TopTaskInfoContainer; 69 import com.android.internal.annotations.GuardedBy; 70 import com.android.internal.annotations.VisibleForTesting; 71 72 import com.google.android.collect.Sets; 73 74 import java.io.PrintWriter; 75 import java.util.ArrayList; 76 import java.util.Arrays; 77 import java.util.HashMap; 78 import java.util.LinkedList; 79 import java.util.List; 80 import java.util.Map; 81 import java.util.Map.Entry; 82 import java.util.Set; 83 84 public class CarPackageManagerService extends ICarPackageManager.Stub implements CarServiceBase { 85 private static final boolean DBG_POLICY_SET = false; 86 private static final boolean DBG_POLICY_CHECK = false; 87 private static final boolean DBG_POLICY_ENFORCEMENT = false; 88 // Delimiters to parse packages and activities in the configuration XML resource. 89 private static final String PACKAGE_DELIMITER = ","; 90 private static final String PACKAGE_ACTIVITY_DELIMITER = "/"; 91 private static final int LOG_SIZE = 20; 92 93 private final Context mContext; 94 private final SystemActivityMonitoringService mSystemActivityMonitoringService; 95 private final PackageManager mPackageManager; 96 private final ActivityManager mActivityManager; 97 private final DisplayManager mDisplayManager; 98 99 private final HandlerThread mHandlerThread; 100 private final PackageHandler mHandler; 101 102 // For dumpsys logging. 103 private final LinkedList<String> mBlockedActivityLogs = new LinkedList<>(); 104 105 // Store the allowlist and denylist strings from the resource file. 106 private String mConfiguredWhitelist; 107 private String mConfiguredSystemWhitelist; 108 private String mConfiguredBlacklist; 109 private final List<String> mAllowedAppInstallSources; 110 111 /** 112 * Hold policy set from policy service or client. 113 * Key: packageName of policy service 114 */ 115 @GuardedBy("this") 116 private final HashMap<String, ClientPolicy> mClientPolicies = new HashMap<>(); 117 @GuardedBy("this") 118 private HashMap<String, AppBlockingPackageInfoWrapper> mActivityWhitelistMap = new HashMap<>(); 119 @GuardedBy("this") 120 private LinkedList<AppBlockingPolicyProxy> mProxies; 121 122 @GuardedBy("this") 123 private final LinkedList<CarAppBlockingPolicy> mWaitingPolicies = new LinkedList<>(); 124 125 private final CarUxRestrictionsManagerService mCarUxRestrictionsService; 126 private boolean mEnableActivityBlocking; 127 private final ComponentName mActivityBlockingActivity; 128 129 private final ActivityLaunchListener mActivityLaunchListener = new ActivityLaunchListener(); 130 // K: (logical) display id of a physical display, V: UXR change listener of this display. 131 // For multi-display, monitor UXR change on each display. 132 private final SparseArray<UxRestrictionsListener> mUxRestrictionsListeners = 133 new SparseArray<>(); 134 private final VendorServiceController mVendorServiceController; 135 136 // Information related to when the installed packages should be parsed for building a white and 137 // denylist 138 private final Set<String> mPackageManagerActions = Sets.newArraySet( 139 Intent.ACTION_PACKAGE_ADDED, 140 Intent.ACTION_PACKAGE_CHANGED, 141 Intent.ACTION_PACKAGE_REMOVED, 142 Intent.ACTION_PACKAGE_REPLACED); 143 144 private final PackageParsingEventReceiver mPackageParsingEventReceiver = 145 new PackageParsingEventReceiver(); 146 private final UserSwitchedEventReceiver mUserSwitchedEventReceiver = 147 new UserSwitchedEventReceiver(); 148 149 // To track if the packages have been parsed for building white/black lists. If we haven't had 150 // received any intents (boot complete or package changed), then the allowlist is null leading 151 // to blocking everything. So, no blocking until we have had a chance to parse the packages. 152 private boolean mHasParsedPackages; 153 154 /** 155 * Name of blocked activity. 156 * 157 * @hide 158 */ 159 public static final String BLOCKING_INTENT_EXTRA_BLOCKED_ACTIVITY_NAME = "blocked_activity"; 160 /** 161 * int task id of the blocked task. 162 * 163 * @hide 164 */ 165 public static final String BLOCKING_INTENT_EXTRA_BLOCKED_TASK_ID = "blocked_task_id"; 166 /** 167 * Name of root activity of blocked task. 168 * 169 * @hide 170 */ 171 public static final String BLOCKING_INTENT_EXTRA_ROOT_ACTIVITY_NAME = "root_activity_name"; 172 /** 173 * Boolean indicating whether the root activity is distraction-optimized (DO). 174 * Blocking screen should show a button to restart the task if {@code true}. 175 * 176 * @hide 177 */ 178 public static final String BLOCKING_INTENT_EXTRA_IS_ROOT_ACTIVITY_DO = "is_root_activity_do"; 179 180 /** 181 * int display id of the blocked task. 182 * 183 * @hide 184 */ 185 public static final String BLOCKING_INTENT_EXTRA_DISPLAY_ID = "display_id"; 186 CarPackageManagerService(Context context, CarUxRestrictionsManagerService uxRestrictionsService, SystemActivityMonitoringService systemActivityMonitoringService, CarUserManagerHelper carUserManagerHelper)187 public CarPackageManagerService(Context context, 188 CarUxRestrictionsManagerService uxRestrictionsService, 189 SystemActivityMonitoringService systemActivityMonitoringService, 190 CarUserManagerHelper carUserManagerHelper) { 191 mContext = context; 192 mCarUxRestrictionsService = uxRestrictionsService; 193 mSystemActivityMonitoringService = systemActivityMonitoringService; 194 mPackageManager = mContext.getPackageManager(); 195 mActivityManager = mContext.getSystemService(ActivityManager.class); 196 mDisplayManager = mContext.getSystemService(DisplayManager.class); 197 mHandlerThread = new HandlerThread(CarLog.TAG_PACKAGE); 198 mHandlerThread.start(); 199 mHandler = new PackageHandler(mHandlerThread.getLooper()); 200 Resources res = context.getResources(); 201 mEnableActivityBlocking = res.getBoolean(R.bool.enableActivityBlockingForSafety); 202 String blockingActivity = res.getString(R.string.activityBlockingActivity); 203 mActivityBlockingActivity = ComponentName.unflattenFromString(blockingActivity); 204 mAllowedAppInstallSources = Arrays.asList( 205 res.getStringArray(R.array.allowedAppInstallSources)); 206 mVendorServiceController = new VendorServiceController( 207 mContext, mHandler.getLooper(), carUserManagerHelper); 208 } 209 210 211 @Override setAppBlockingPolicy(String packageName, CarAppBlockingPolicy policy, int flags)212 public void setAppBlockingPolicy(String packageName, CarAppBlockingPolicy policy, int flags) { 213 if (DBG_POLICY_SET) { 214 Log.i(CarLog.TAG_PACKAGE, "policy setting from binder call, client:" + packageName); 215 } 216 doSetAppBlockingPolicy(packageName, policy, flags); 217 } 218 219 /** 220 * Restarts the requested task. If task with {@code taskId} does not exist, do nothing. 221 */ 222 @Override restartTask(int taskId)223 public void restartTask(int taskId) { 224 mSystemActivityMonitoringService.restartTask(taskId); 225 } 226 doSetAppBlockingPolicy(String packageName, CarAppBlockingPolicy policy, int flags)227 private void doSetAppBlockingPolicy(String packageName, CarAppBlockingPolicy policy, 228 int flags) { 229 if (mContext.checkCallingOrSelfPermission(Car.PERMISSION_CONTROL_APP_BLOCKING) 230 != PackageManager.PERMISSION_GRANTED) { 231 throw new SecurityException( 232 "requires permission " + Car.PERMISSION_CONTROL_APP_BLOCKING); 233 } 234 CarServiceUtils.assertPackageName(mContext, packageName); 235 if (policy == null) { 236 throw new IllegalArgumentException("policy cannot be null"); 237 } 238 if ((flags & CarPackageManager.FLAG_SET_POLICY_ADD) != 0 && 239 (flags & CarPackageManager.FLAG_SET_POLICY_REMOVE) != 0) { 240 throw new IllegalArgumentException( 241 "Cannot set both FLAG_SET_POLICY_ADD and FLAG_SET_POLICY_REMOVE flag"); 242 } 243 synchronized (this) { 244 if ((flags & CarPackageManager.FLAG_SET_POLICY_WAIT_FOR_CHANGE) != 0) { 245 mWaitingPolicies.add(policy); 246 } 247 } 248 mHandler.requestUpdatingPolicy(packageName, policy, flags); 249 if ((flags & CarPackageManager.FLAG_SET_POLICY_WAIT_FOR_CHANGE) != 0) { 250 synchronized (this) { 251 try { 252 while (mWaitingPolicies.contains(policy)) { 253 wait(); 254 } 255 } catch (InterruptedException e) { 256 // Pass it over binder call 257 throw new IllegalStateException( 258 "Interrupted while waiting for policy completion", e); 259 } 260 } 261 } 262 } 263 264 @Override isActivityDistractionOptimized(String packageName, String className)265 public boolean isActivityDistractionOptimized(String packageName, String className) { 266 assertPackageAndClassName(packageName, className); 267 synchronized (this) { 268 if (DBG_POLICY_CHECK) { 269 Log.i(CarLog.TAG_PACKAGE, "isActivityDistractionOptimized" 270 + dumpPoliciesLocked(false)); 271 } 272 AppBlockingPackageInfo info = searchFromBlacklistsLocked(packageName); 273 if (info != null) { 274 return false; 275 } 276 return isActivityInWhitelistsLocked(packageName, className); 277 } 278 } 279 280 @Override isServiceDistractionOptimized(String packageName, String className)281 public boolean isServiceDistractionOptimized(String packageName, String className) { 282 if (packageName == null) { 283 throw new IllegalArgumentException("Package name null"); 284 } 285 synchronized (this) { 286 if (DBG_POLICY_CHECK) { 287 Log.i(CarLog.TAG_PACKAGE, "isServiceDistractionOptimized" 288 + dumpPoliciesLocked(false)); 289 } 290 AppBlockingPackageInfo info = searchFromBlacklistsLocked(packageName); 291 if (info != null) { 292 return false; 293 } 294 info = searchFromWhitelistsLocked(packageName); 295 if (info != null) { 296 return true; 297 } 298 } 299 return false; 300 } 301 302 @Override isActivityBackedBySafeActivity(ComponentName activityName)303 public boolean isActivityBackedBySafeActivity(ComponentName activityName) { 304 StackInfo info = mSystemActivityMonitoringService.getFocusedStackForTopActivity( 305 activityName); 306 if (info == null) { // not top in focused stack 307 return true; 308 } 309 if (!isUxRestrictedOnDisplay(info.displayId)) { 310 return true; 311 } 312 if (info.taskNames.length <= 1) { // nothing below this. 313 return false; 314 } 315 ComponentName activityBehind = ComponentName.unflattenFromString( 316 info.taskNames[info.taskNames.length - 2]); 317 return isActivityDistractionOptimized(activityBehind.getPackageName(), 318 activityBehind.getClassName()); 319 } 320 getLooper()321 public Looper getLooper() { 322 return mHandlerThread.getLooper(); 323 } 324 assertPackageAndClassName(String packageName, String className)325 private void assertPackageAndClassName(String packageName, String className) { 326 if (packageName == null) { 327 throw new IllegalArgumentException("Package name null"); 328 } 329 if (className == null) { 330 throw new IllegalArgumentException("Class name null"); 331 } 332 } 333 334 @GuardedBy("this") searchFromBlacklistsLocked(String packageName)335 private AppBlockingPackageInfo searchFromBlacklistsLocked(String packageName) { 336 for (ClientPolicy policy : mClientPolicies.values()) { 337 AppBlockingPackageInfoWrapper wrapper = policy.blacklistsMap.get(packageName); 338 if (wrapper != null && wrapper.isMatching) { 339 return wrapper.info; 340 } 341 } 342 return null; 343 } 344 345 @GuardedBy("this") searchFromWhitelistsLocked(String packageName)346 private AppBlockingPackageInfo searchFromWhitelistsLocked(String packageName) { 347 for (ClientPolicy policy : mClientPolicies.values()) { 348 AppBlockingPackageInfoWrapper wrapper = policy.whitelistsMap.get(packageName); 349 if (wrapper != null && wrapper.isMatching) { 350 return wrapper.info; 351 } 352 } 353 AppBlockingPackageInfoWrapper wrapper = mActivityWhitelistMap.get(packageName); 354 return (wrapper != null) ? wrapper.info : null; 355 } 356 357 @GuardedBy("this") isActivityInWhitelistsLocked(String packageName, String className)358 private boolean isActivityInWhitelistsLocked(String packageName, String className) { 359 for (ClientPolicy policy : mClientPolicies.values()) { 360 if (isActivityInMapAndMatching(policy.whitelistsMap, packageName, className)) { 361 return true; 362 } 363 } 364 return isActivityInMapAndMatching(mActivityWhitelistMap, packageName, className); 365 } 366 isActivityInMapAndMatching(HashMap<String, AppBlockingPackageInfoWrapper> map, String packageName, String className)367 private boolean isActivityInMapAndMatching(HashMap<String, AppBlockingPackageInfoWrapper> map, 368 String packageName, String className) { 369 AppBlockingPackageInfoWrapper wrapper = map.get(packageName); 370 if (wrapper == null || !wrapper.isMatching) { 371 if (DBG_POLICY_CHECK) { 372 Log.d(CarLog.TAG_PACKAGE, "Pkg not in whitelist:" + packageName); 373 } 374 return false; 375 } 376 return wrapper.info.isActivityCovered(className); 377 } 378 379 @Override init()380 public void init() { 381 synchronized (this) { 382 mHandler.requestInit(); 383 } 384 } 385 386 @Override release()387 public void release() { 388 synchronized (this) { 389 mHandler.requestRelease(); 390 // wait for release do be done. This guarantees that init is done. 391 try { 392 wait(); 393 } catch (InterruptedException e) { 394 } 395 mHasParsedPackages = false; 396 mActivityWhitelistMap.clear(); 397 mClientPolicies.clear(); 398 if (mProxies != null) { 399 for (AppBlockingPolicyProxy proxy : mProxies) { 400 proxy.disconnect(); 401 } 402 mProxies.clear(); 403 } 404 mWaitingPolicies.clear(); 405 notifyAll(); 406 } 407 mContext.unregisterReceiver(mPackageParsingEventReceiver); 408 mContext.unregisterReceiver(mUserSwitchedEventReceiver); 409 mSystemActivityMonitoringService.registerActivityLaunchListener(null); 410 for (int i = 0; i < mUxRestrictionsListeners.size(); i++) { 411 UxRestrictionsListener listener = mUxRestrictionsListeners.valueAt(i); 412 mCarUxRestrictionsService.unregisterUxRestrictionsChangeListener(listener); 413 } 414 } 415 416 // run from HandlerThread doHandleInit()417 private void doHandleInit() { 418 startAppBlockingPolicies(); 419 IntentFilter intent = new IntentFilter(); 420 intent.addAction(Intent.ACTION_USER_SWITCHED); 421 mContext.registerReceiver(mUserSwitchedEventReceiver, intent); 422 IntentFilter pkgParseIntent = new IntentFilter(); 423 for (String action : mPackageManagerActions) { 424 pkgParseIntent.addAction(action); 425 } 426 pkgParseIntent.addDataScheme("package"); 427 mContext.registerReceiverAsUser(mPackageParsingEventReceiver, UserHandle.ALL, 428 pkgParseIntent, null, null); 429 430 List<Display> physicalDisplays = getPhysicalDisplays(); 431 432 // Assume default display (display 0) is always a physical display. 433 Display defaultDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY); 434 if (!physicalDisplays.contains(defaultDisplay)) { 435 if (Log.isLoggable(CarLog.TAG_PACKAGE, Log.INFO)) { 436 Log.i(CarLog.TAG_PACKAGE, "Adding default display to physical displays."); 437 } 438 physicalDisplays.add(defaultDisplay); 439 } 440 for (Display physicalDisplay : physicalDisplays) { 441 int displayId = physicalDisplay.getDisplayId(); 442 UxRestrictionsListener listener = new UxRestrictionsListener(mCarUxRestrictionsService); 443 mUxRestrictionsListeners.put(displayId, listener); 444 mCarUxRestrictionsService.registerUxRestrictionsChangeListener(listener, displayId); 445 } 446 mVendorServiceController.init(); 447 } 448 doParseInstalledPackages()449 private void doParseInstalledPackages() { 450 int userId = mActivityManager.getCurrentUser(); 451 generateActivityWhitelistMap(userId); 452 synchronized (this) { 453 mHasParsedPackages = true; 454 } 455 // Once the activity launch listener is registered we attempt to block any non-allowlisted 456 // activities that are launched. For this reason, we need to wait until after the allowlist 457 // has been created. 458 mSystemActivityMonitoringService.registerActivityLaunchListener(mActivityLaunchListener); 459 blockTopActivitiesIfNecessary(); 460 } 461 doHandleRelease()462 private synchronized void doHandleRelease() { 463 mVendorServiceController.release(); 464 notifyAll(); 465 } 466 doUpdatePolicy(String packageName, CarAppBlockingPolicy policy, int flags)467 private void doUpdatePolicy(String packageName, CarAppBlockingPolicy policy, int flags) { 468 if (DBG_POLICY_SET) { 469 Log.i(CarLog.TAG_PACKAGE, "setting policy from:" + packageName + ",policy:" + policy + 470 ",flags:0x" + Integer.toHexString(flags)); 471 } 472 AppBlockingPackageInfoWrapper[] blacklistWrapper = verifyList(policy.blacklists); 473 AppBlockingPackageInfoWrapper[] whitelistWrapper = verifyList(policy.whitelists); 474 synchronized (this) { 475 ClientPolicy clientPolicy = mClientPolicies.get(packageName); 476 if (clientPolicy == null) { 477 clientPolicy = new ClientPolicy(); 478 mClientPolicies.put(packageName, clientPolicy); 479 } 480 if ((flags & CarPackageManager.FLAG_SET_POLICY_ADD) != 0) { 481 clientPolicy.addToBlacklists(blacklistWrapper); 482 clientPolicy.addToWhitelists(whitelistWrapper); 483 } else if ((flags & CarPackageManager.FLAG_SET_POLICY_REMOVE) != 0) { 484 clientPolicy.removeBlacklists(blacklistWrapper); 485 clientPolicy.removeWhitelists(whitelistWrapper); 486 } else { //replace. 487 clientPolicy.replaceBlacklists(blacklistWrapper); 488 clientPolicy.replaceWhitelists(whitelistWrapper); 489 } 490 if ((flags & CarPackageManager.FLAG_SET_POLICY_WAIT_FOR_CHANGE) != 0) { 491 mWaitingPolicies.remove(policy); 492 notifyAll(); 493 } 494 if (DBG_POLICY_SET) { 495 Log.i(CarLog.TAG_PACKAGE, "policy set:" + dumpPoliciesLocked(false)); 496 } 497 } 498 blockTopActivitiesIfNecessary(); 499 } 500 verifyList(AppBlockingPackageInfo[] list)501 private AppBlockingPackageInfoWrapper[] verifyList(AppBlockingPackageInfo[] list) { 502 if (list == null) { 503 return null; 504 } 505 LinkedList<AppBlockingPackageInfoWrapper> wrappers = new LinkedList<>(); 506 for (int i = 0; i < list.length; i++) { 507 AppBlockingPackageInfo info = list[i]; 508 if (info == null) { 509 continue; 510 } 511 boolean isMatching = isInstalledPackageMatching(info); 512 wrappers.add(new AppBlockingPackageInfoWrapper(info, isMatching)); 513 } 514 return wrappers.toArray(new AppBlockingPackageInfoWrapper[wrappers.size()]); 515 } 516 isInstalledPackageMatching(AppBlockingPackageInfo info)517 boolean isInstalledPackageMatching(AppBlockingPackageInfo info) { 518 PackageInfo packageInfo; 519 try { 520 packageInfo = mPackageManager.getPackageInfo(info.packageName, 521 PackageManager.GET_SIGNATURES); 522 } catch (NameNotFoundException e) { 523 return false; 524 } 525 if (packageInfo == null) { 526 return false; 527 } 528 // if it is system app and client specified the flag, do not check signature 529 if ((info.flags & AppBlockingPackageInfo.FLAG_SYSTEM_APP) == 0 || 530 (!packageInfo.applicationInfo.isSystemApp() && 531 !packageInfo.applicationInfo.isUpdatedSystemApp())) { 532 Signature[] signatures = packageInfo.signatures; 533 if (!isAnySignatureMatching(signatures, info.signatures)) { 534 return false; 535 } 536 } 537 int version = packageInfo.versionCode; 538 if (info.minRevisionCode == 0) { 539 if (info.maxRevisionCode == 0) { // all versions 540 return true; 541 } else { // only max version matters 542 return info.maxRevisionCode > version; 543 } 544 } else { // min version matters 545 if (info.maxRevisionCode == 0) { 546 return info.minRevisionCode < version; 547 } else { 548 return (info.minRevisionCode < version) && (info.maxRevisionCode > version); 549 } 550 } 551 } 552 553 /** 554 * Any signature from policy matching with package's signatures is treated as matching. 555 */ isAnySignatureMatching(Signature[] fromPackage, Signature[] fromPolicy)556 boolean isAnySignatureMatching(Signature[] fromPackage, Signature[] fromPolicy) { 557 if (fromPackage == null) { 558 return false; 559 } 560 if (fromPolicy == null) { 561 return false; 562 } 563 ArraySet<Signature> setFromPackage = new ArraySet<Signature>(); 564 for (Signature sig : fromPackage) { 565 setFromPackage.add(sig); 566 } 567 for (Signature sig : fromPolicy) { 568 if (setFromPackage.contains(sig)) { 569 return true; 570 } 571 } 572 return false; 573 } 574 575 /** 576 * Generate a map of allowlisted packages and activities of the form {pkgName, Allowlisted 577 * activities}. The allowlist information can come from a configuration XML resource or from 578 * the apps marking their activities as distraction optimized. 579 * 580 * @param userId Generate allowlist based on packages installed for this user. 581 */ generateActivityWhitelistMap(int userId)582 private void generateActivityWhitelistMap(int userId) { 583 // Get the apps/activities that are allowlisted in the configuration XML resources. 584 Map<String, Set<String>> configWhitelist = generateConfigWhitelist(); 585 Map<String, Set<String>> configBlacklist = generateConfigBlacklist(); 586 587 Map<String, AppBlockingPackageInfoWrapper> activityWhitelist = 588 generateActivityWhitelistAsUser(UserHandle.USER_SYSTEM, 589 configWhitelist, configBlacklist); 590 // Also parse packages for current user. 591 if (userId != UserHandle.USER_SYSTEM) { 592 Map<String, AppBlockingPackageInfoWrapper> userWhitelistedPackages = 593 generateActivityWhitelistAsUser(userId, configWhitelist, configBlacklist); 594 for (String packageName : userWhitelistedPackages.keySet()) { 595 if (activityWhitelist.containsKey(packageName)) { 596 continue; 597 } 598 activityWhitelist.put(packageName, userWhitelistedPackages.get(packageName)); 599 } 600 } 601 synchronized (this) { 602 mActivityWhitelistMap.clear(); 603 mActivityWhitelistMap.putAll(activityWhitelist); 604 } 605 } 606 generateConfigWhitelist()607 private Map<String, Set<String>> generateConfigWhitelist() { 608 Map<String, Set<String>> configWhitelist = new HashMap<>(); 609 mConfiguredWhitelist = mContext.getString(R.string.activityWhitelist); 610 if (mConfiguredWhitelist == null) { 611 if (DBG_POLICY_CHECK) { 612 Log.w(CarLog.TAG_PACKAGE, "White list is null."); 613 } 614 } 615 parseConfigList(mConfiguredWhitelist, configWhitelist); 616 617 mConfiguredSystemWhitelist = mContext.getString(R.string.systemActivityWhitelist); 618 if (mConfiguredSystemWhitelist == null) { 619 if (DBG_POLICY_CHECK) { 620 Log.w(CarLog.TAG_PACKAGE, "System white list is null."); 621 } 622 } 623 parseConfigList(mConfiguredSystemWhitelist, configWhitelist); 624 625 // Add the blocking overlay activity to the allowlist, since that needs to run in a 626 // restricted state to communicate the reason an app was blocked. 627 Set<String> defaultActivity = new ArraySet<>(); 628 if (mActivityBlockingActivity != null) { 629 defaultActivity.add(mActivityBlockingActivity.getClassName()); 630 configWhitelist.put(mActivityBlockingActivity.getPackageName(), defaultActivity); 631 } 632 633 return configWhitelist; 634 } 635 generateConfigBlacklist()636 private Map<String, Set<String>> generateConfigBlacklist() { 637 Map<String, Set<String>> configBlacklist = new HashMap<>(); 638 mConfiguredBlacklist = mContext.getString(R.string.activityBlacklist); 639 if (mConfiguredBlacklist == null) { 640 if (DBG_POLICY_CHECK) { 641 Log.d(CarLog.TAG_PACKAGE, "Null blacklist in config"); 642 } 643 } 644 parseConfigList(mConfiguredBlacklist, configBlacklist); 645 646 return configBlacklist; 647 } 648 649 /** 650 * Generates allowlisted activities based on packages installed for system user and current 651 * user (if different). Factors affecting allowlist: 652 * - allowlist from resource config; 653 * - activity declared as Distraction Optimized (D.O.) in manifest; 654 * - denylist from resource config - package/activity denylisted will not exist 655 * in returned allowlist. 656 * 657 * @param userId Parse packages installed for user. 658 * @param configWhitelist Allowlist from config. 659 * @param configBlacklist Denylist from config. 660 */ generateActivityWhitelistAsUser(int userId, Map<String, Set<String>> configWhitelist, Map<String, Set<String>> configBlacklist)661 private Map<String, AppBlockingPackageInfoWrapper> generateActivityWhitelistAsUser(int userId, 662 Map<String, Set<String>> configWhitelist, Map<String, Set<String>> configBlacklist) { 663 HashMap<String, AppBlockingPackageInfoWrapper> activityWhitelist = new HashMap<>(); 664 665 List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser( 666 PackageManager.GET_SIGNATURES | PackageManager.GET_ACTIVITIES 667 | PackageManager.MATCH_DIRECT_BOOT_AWARE 668 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 669 userId); 670 for (PackageInfo info : packages) { 671 if (info.applicationInfo == null) { 672 continue; 673 } 674 675 int flags = 0; 676 Set<String> activities = new ArraySet<>(); 677 678 if (info.applicationInfo.isSystemApp() 679 || info.applicationInfo.isUpdatedSystemApp()) { 680 flags = AppBlockingPackageInfo.FLAG_SYSTEM_APP; 681 } 682 683 /* 1. Check if all or some of this app is in the <activityWhitelist> or 684 <systemActivityWhitelist> in config.xml */ 685 Set<String> configActivitiesForPackage = configWhitelist.get(info.packageName); 686 if (configActivitiesForPackage != null) { 687 if (DBG_POLICY_CHECK) { 688 Log.d(CarLog.TAG_PACKAGE, info.packageName + " whitelisted"); 689 } 690 if (configActivitiesForPackage.size() == 0) { 691 // Whole Pkg has been allowlisted 692 flags |= AppBlockingPackageInfo.FLAG_WHOLE_ACTIVITY; 693 // Add all activities to the allowlist 694 List<String> activitiesForPackage = getActivitiesInPackage(info); 695 if (activitiesForPackage != null) { 696 activities.addAll(activitiesForPackage); 697 } else { 698 if (DBG_POLICY_CHECK) { 699 Log.d(CarLog.TAG_PACKAGE, info.packageName + ": Activities null"); 700 } 701 } 702 } else { 703 if (DBG_POLICY_CHECK) { 704 Log.d(CarLog.TAG_PACKAGE, "Partially Whitelisted. WL Activities:"); 705 for (String a : configActivitiesForPackage) { 706 Log.d(CarLog.TAG_PACKAGE, a); 707 } 708 } 709 activities.addAll(configActivitiesForPackage); 710 } 711 } 712 /* 2. If app is not listed in the config.xml check their Manifest meta-data to 713 see if they have any Distraction Optimized(DO) activities. 714 For non system apps, we check if the app install source was a permittable 715 source. This prevents side-loaded apps to fake DO. Bypass the check 716 for debug builds for development convenience. */ 717 if (!isDebugBuild() 718 && !info.applicationInfo.isSystemApp() 719 && !info.applicationInfo.isUpdatedSystemApp()) { 720 try { 721 if (mAllowedAppInstallSources != null) { 722 String installerName = mPackageManager.getInstallerPackageName( 723 info.packageName); 724 if (installerName == null || (installerName != null 725 && !mAllowedAppInstallSources.contains(installerName))) { 726 Log.w(CarLog.TAG_PACKAGE, 727 info.packageName + " not installed from permitted sources " 728 + (installerName == null ? "NULL" : installerName)); 729 continue; 730 } 731 } 732 } catch (IllegalArgumentException e) { 733 Log.w(CarLog.TAG_PACKAGE, info.packageName + " not installed!"); 734 continue; 735 } 736 } 737 738 try { 739 String[] doActivities = 740 CarAppMetadataReader.findDistractionOptimizedActivitiesAsUser( 741 mContext, info.packageName, userId); 742 if (doActivities != null) { 743 // Some of the activities in this app are Distraction Optimized. 744 if (DBG_POLICY_CHECK) { 745 for (String activity : doActivities) { 746 Log.d(CarLog.TAG_PACKAGE, 747 "adding " + activity + " from " + info.packageName 748 + " to whitelist"); 749 } 750 } 751 activities.addAll(Arrays.asList(doActivities)); 752 } 753 } catch (NameNotFoundException e) { 754 Log.w(CarLog.TAG_PACKAGE, "Error reading metadata: " + info.packageName); 755 continue; 756 } 757 758 // Nothing to add to allowlist 759 if (activities.isEmpty()) { 760 continue; 761 } 762 763 /* 3. Check if parsed activity is in <activityBlacklist> in config.xml. Anything 764 in denylist should not be allowlisted, either as D.O. or by config. */ 765 if (configBlacklist.containsKey(info.packageName)) { 766 Set<String> configBlacklistActivities = configBlacklist.get(info.packageName); 767 if (configBlacklistActivities.isEmpty()) { 768 // Whole package should be denylisted. 769 continue; 770 } 771 activities.removeAll(configBlacklistActivities); 772 } 773 774 Signature[] signatures; 775 signatures = info.signatures; 776 AppBlockingPackageInfo appBlockingInfo = new AppBlockingPackageInfo( 777 info.packageName, 0, 0, flags, signatures, 778 activities.toArray(new String[activities.size()])); 779 AppBlockingPackageInfoWrapper wrapper = new AppBlockingPackageInfoWrapper( 780 appBlockingInfo, true); 781 activityWhitelist.put(info.packageName, wrapper); 782 } 783 return activityWhitelist; 784 } 785 isDebugBuild()786 private boolean isDebugBuild() { 787 return Build.IS_USERDEBUG || Build.IS_ENG; 788 } 789 790 /** 791 * Parses the given resource and updates the input map of packages and activities. 792 * 793 * Key is package name and value is list of activities. Empty set implies whole package is 794 * included. 795 * 796 * When there are multiple entries regarding one package, the entry with 797 * greater scope wins. Namely if there were 2 entires such that one whitelists 798 * an activity, and the other whitelists the entire package of the activity, 799 * the package is allowlisted, regardless of input order. 800 */ 801 @VisibleForTesting parseConfigList(String configList, @NonNull Map<String, Set<String>> packageToActivityMap)802 /* package */ void parseConfigList(String configList, 803 @NonNull Map<String, Set<String>> packageToActivityMap) { 804 if (configList == null) { 805 return; 806 } 807 String[] entries = configList.split(PACKAGE_DELIMITER); 808 for (String entry : entries) { 809 String[] packageActivityPair = entry.split(PACKAGE_ACTIVITY_DELIMITER); 810 Set<String> activities = packageToActivityMap.get(packageActivityPair[0]); 811 boolean newPackage = false; 812 if (activities == null) { 813 activities = new ArraySet<>(); 814 newPackage = true; 815 packageToActivityMap.put(packageActivityPair[0], activities); 816 } 817 if (packageActivityPair.length == 1) { // whole package 818 activities.clear(); 819 } else if (packageActivityPair.length == 2) { 820 // add class name only when the whole package is not allowlisted. 821 if (newPackage || (activities.size() > 0)) { 822 activities.add(packageActivityPair[1]); 823 } 824 } 825 } 826 } 827 828 @Nullable getActivitiesInPackage(PackageInfo info)829 private List<String> getActivitiesInPackage(PackageInfo info) { 830 if (info == null || info.activities == null) { 831 return null; 832 } 833 List<String> activityList = new ArrayList<>(); 834 for (ActivityInfo aInfo : info.activities) { 835 activityList.add(aInfo.name); 836 } 837 return activityList; 838 } 839 840 /** 841 * Checks if there are any {@link CarAppBlockingPolicyService} and creates a proxy to 842 * bind to them and retrieve the {@link CarAppBlockingPolicy} 843 */ 844 @VisibleForTesting startAppBlockingPolicies()845 public void startAppBlockingPolicies() { 846 Intent policyIntent = new Intent(); 847 policyIntent.setAction(CarAppBlockingPolicyService.SERVICE_INTERFACE); 848 List<ResolveInfo> policyInfos = mPackageManager.queryIntentServices(policyIntent, 0); 849 if (policyInfos == null) { //no need to wait for service binding and retrieval. 850 return; 851 } 852 LinkedList<AppBlockingPolicyProxy> proxies = new LinkedList<>(); 853 for (ResolveInfo resolveInfo : policyInfos) { 854 ServiceInfo serviceInfo = resolveInfo.serviceInfo; 855 if (serviceInfo == null) { 856 continue; 857 } 858 if (serviceInfo.isEnabled()) { 859 if (mPackageManager.checkPermission(Car.PERMISSION_CONTROL_APP_BLOCKING, 860 serviceInfo.packageName) != PackageManager.PERMISSION_GRANTED) { 861 continue; 862 } 863 Log.i(CarLog.TAG_PACKAGE, "found policy holding service:" + serviceInfo); 864 AppBlockingPolicyProxy proxy = new AppBlockingPolicyProxy(this, mContext, 865 serviceInfo); 866 proxy.connect(); 867 proxies.add(proxy); 868 } 869 } 870 synchronized (this) { 871 mProxies = proxies; 872 } 873 } 874 onPolicyConnectionAndSet(AppBlockingPolicyProxy proxy, CarAppBlockingPolicy policy)875 public void onPolicyConnectionAndSet(AppBlockingPolicyProxy proxy, 876 CarAppBlockingPolicy policy) { 877 doHandlePolicyConnection(proxy, policy); 878 } 879 onPolicyConnectionFailure(AppBlockingPolicyProxy proxy)880 public void onPolicyConnectionFailure(AppBlockingPolicyProxy proxy) { 881 doHandlePolicyConnection(proxy, null); 882 } 883 doHandlePolicyConnection(AppBlockingPolicyProxy proxy, CarAppBlockingPolicy policy)884 private void doHandlePolicyConnection(AppBlockingPolicyProxy proxy, 885 CarAppBlockingPolicy policy) { 886 synchronized (this) { 887 if (mProxies == null) { 888 proxy.disconnect(); 889 return; 890 } 891 mProxies.remove(proxy); 892 if (mProxies.size() == 0) { 893 mProxies = null; 894 } 895 } 896 try { 897 if (policy != null) { 898 if (DBG_POLICY_SET) { 899 Log.i(CarLog.TAG_PACKAGE, "policy setting from policy service:" + 900 proxy.getPackageName()); 901 } 902 doSetAppBlockingPolicy(proxy.getPackageName(), policy, 0); 903 } 904 } finally { 905 proxy.disconnect(); 906 } 907 } 908 909 @Override dump(PrintWriter writer)910 public void dump(PrintWriter writer) { 911 synchronized (this) { 912 writer.println("*CarPackageManagerService*"); 913 writer.println("mEnableActivityBlocking:" + mEnableActivityBlocking); 914 writer.println("mHasParsedPackages:" + mHasParsedPackages); 915 List<String> restrictions = new ArrayList<>(mUxRestrictionsListeners.size()); 916 for (int i = 0; i < mUxRestrictionsListeners.size(); i++) { 917 int displayId = mUxRestrictionsListeners.keyAt(i); 918 UxRestrictionsListener listener = mUxRestrictionsListeners.valueAt(i); 919 restrictions.add(String.format("Display %d is %s", 920 displayId, (listener.isRestricted() ? "restricted" : "unrestricted"))); 921 } 922 writer.println("Display Restrictions:\n" + String.join("\n", restrictions)); 923 writer.println(" Blocked activity log:"); 924 writer.println(String.join("\n", mBlockedActivityLogs)); 925 writer.print(dumpPoliciesLocked(true)); 926 } 927 } 928 929 @GuardedBy("this") dumpPoliciesLocked(boolean dumpAll)930 private String dumpPoliciesLocked(boolean dumpAll) { 931 StringBuilder sb = new StringBuilder(); 932 if (dumpAll) { 933 sb.append("**System whitelist**\n"); 934 for (AppBlockingPackageInfoWrapper wrapper : mActivityWhitelistMap.values()) { 935 sb.append(wrapper.toString() + "\n"); 936 } 937 } 938 sb.append("**Client Policies**\n"); 939 for (Entry<String, ClientPolicy> entry : mClientPolicies.entrySet()) { 940 sb.append("Client:" + entry.getKey() + "\n"); 941 sb.append(" whitelists:\n"); 942 for (AppBlockingPackageInfoWrapper wrapper : entry.getValue().whitelistsMap.values()) { 943 sb.append(wrapper.toString() + "\n"); 944 } 945 sb.append(" blacklists:\n"); 946 for (AppBlockingPackageInfoWrapper wrapper : entry.getValue().blacklistsMap.values()) { 947 sb.append(wrapper.toString() + "\n"); 948 } 949 } 950 sb.append("**Unprocessed policy services**\n"); 951 if (mProxies != null) { 952 for (AppBlockingPolicyProxy proxy : mProxies) { 953 sb.append(proxy.toString() + "\n"); 954 } 955 } 956 sb.append("**Whitelist string in resource**\n"); 957 sb.append(mConfiguredWhitelist + "\n"); 958 959 sb.append("**System whitelist string in resource**\n"); 960 sb.append(mConfiguredSystemWhitelist + "\n"); 961 962 sb.append("**Blacklist string in resource**\n"); 963 sb.append(mConfiguredBlacklist + "\n"); 964 965 return sb.toString(); 966 } 967 968 /** 969 * Returns display with physical address. 970 */ getPhysicalDisplays()971 private List<Display> getPhysicalDisplays() { 972 List<Display> displays = new ArrayList<>(); 973 for (Display display : mDisplayManager.getDisplays()) { 974 if (display.getAddress() instanceof DisplayAddress.Physical) { 975 displays.add(display); 976 } 977 } 978 return displays; 979 } 980 981 /** 982 * Returns whether UX restrictions is required for display. 983 * 984 * Non-physical display will use restrictions for {@link Display#DEFAULT_DISPLAY}. 985 */ isUxRestrictedOnDisplay(int displayId)986 private boolean isUxRestrictedOnDisplay(int displayId) { 987 UxRestrictionsListener listenerForTopTaskDisplay; 988 if (mUxRestrictionsListeners.indexOfKey(displayId) < 0) { 989 listenerForTopTaskDisplay = mUxRestrictionsListeners.get(Display.DEFAULT_DISPLAY); 990 if (listenerForTopTaskDisplay == null) { 991 // This should never happen. 992 Log.e(CarLog.TAG_PACKAGE, "Missing listener for default display."); 993 return true; 994 } 995 } else { 996 listenerForTopTaskDisplay = mUxRestrictionsListeners.get(displayId); 997 } 998 999 return listenerForTopTaskDisplay.isRestricted(); 1000 } 1001 blockTopActivitiesIfNecessary()1002 private void blockTopActivitiesIfNecessary() { 1003 List<TopTaskInfoContainer> topTasks = mSystemActivityMonitoringService.getTopTasks(); 1004 for (TopTaskInfoContainer topTask : topTasks) { 1005 if (topTask == null) { 1006 Log.e(CarLog.TAG_PACKAGE, "Top tasks contains null."); 1007 continue; 1008 } 1009 blockTopActivityIfNecessary(topTask); 1010 } 1011 } 1012 blockTopActivityIfNecessary(TopTaskInfoContainer topTask)1013 private void blockTopActivityIfNecessary(TopTaskInfoContainer topTask) { 1014 if (isUxRestrictedOnDisplay(topTask.displayId)) { 1015 doBlockTopActivityIfNotAllowed(topTask); 1016 } 1017 } 1018 doBlockTopActivityIfNotAllowed(TopTaskInfoContainer topTask)1019 private void doBlockTopActivityIfNotAllowed(TopTaskInfoContainer topTask) { 1020 if (topTask.topActivity == null) { 1021 return; 1022 } 1023 1024 // We are not handling the UI blocking until we know what is allowed and what is not. 1025 if (!mHasParsedPackages) { 1026 if (Log.isLoggable(CarLog.TAG_PACKAGE, Log.INFO)) { 1027 Log.i(CarLog.TAG_PACKAGE, "Packages not parsed, so ignoring block for " + topTask); 1028 } 1029 return; 1030 } 1031 1032 boolean allowed = isActivityDistractionOptimized( 1033 topTask.topActivity.getPackageName(), 1034 topTask.topActivity.getClassName()); 1035 if (DBG_POLICY_ENFORCEMENT) { 1036 Log.i(CarLog.TAG_PACKAGE, "new activity:" + topTask.toString() + " allowed:" + allowed); 1037 } 1038 if (allowed) { 1039 return; 1040 } 1041 synchronized (this) { 1042 if (!mEnableActivityBlocking) { 1043 Log.d(CarLog.TAG_PACKAGE, "Current activity " + topTask.topActivity + 1044 " not allowed, blocking disabled. Number of tasks in stack:" 1045 + topTask.stackInfo.taskIds.length); 1046 return; 1047 } 1048 } 1049 if (DBG_POLICY_ENFORCEMENT) { 1050 Log.i(CarLog.TAG_PACKAGE, "Current activity " + topTask.topActivity + 1051 " not allowed, will block, number of tasks in stack:" + 1052 topTask.stackInfo.taskIds.length); 1053 } 1054 1055 // Figure out the root activity of blocked task. 1056 String taskRootActivity = null; 1057 for (int i = 0; i < topTask.stackInfo.taskIds.length; i++) { 1058 // topTask.taskId is the task that should be blocked. 1059 if (topTask.stackInfo.taskIds[i] == topTask.taskId) { 1060 // stackInfo represents an ActivityStack. Its fields taskIds and taskNames 1061 // are 1:1 mapped, where taskNames is the name of root activity in this task. 1062 taskRootActivity = topTask.stackInfo.taskNames[i]; 1063 break; 1064 } 1065 } 1066 1067 boolean isRootDO = false; 1068 if (taskRootActivity != null) { 1069 ComponentName componentName = ComponentName.unflattenFromString(taskRootActivity); 1070 isRootDO = isActivityDistractionOptimized( 1071 componentName.getPackageName(), componentName.getClassName()); 1072 } 1073 1074 Intent newActivityIntent = createBlockingActivityIntent( 1075 mActivityBlockingActivity, topTask.displayId, 1076 topTask.topActivity.flattenToShortString(), topTask.taskId, taskRootActivity, 1077 isRootDO); 1078 1079 // Intent contains all info to debug what is blocked - log into both logcat and dumpsys. 1080 String log = "Starting blocking activity with intent: " + newActivityIntent.toUri(0); 1081 if (Log.isLoggable(CarLog.TAG_PACKAGE, Log.INFO)) { 1082 Log.i(CarLog.TAG_PACKAGE, log); 1083 } 1084 addLog(log); 1085 mSystemActivityMonitoringService.blockActivity(topTask, newActivityIntent); 1086 } 1087 1088 /** 1089 * Creates an intent to start blocking activity. 1090 * 1091 * @param blockingActivity the activity to launch 1092 * @param blockedActivity the activity being blocked 1093 * @param blockedTaskId the blocked task id, which contains the blocked activity 1094 * @param taskRootActivity root activity of the blocked task 1095 * @return an intent to launch the blocking activity. 1096 */ createBlockingActivityIntent(ComponentName blockingActivity, int displayId, String blockedActivity, int blockedTaskId, String taskRootActivity, boolean isRootDo)1097 private static Intent createBlockingActivityIntent(ComponentName blockingActivity, 1098 int displayId, String blockedActivity, int blockedTaskId, String taskRootActivity, 1099 boolean isRootDo) { 1100 Intent newActivityIntent = new Intent(); 1101 newActivityIntent.setFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); 1102 newActivityIntent.setComponent(blockingActivity); 1103 newActivityIntent.putExtra( 1104 BLOCKING_INTENT_EXTRA_DISPLAY_ID, displayId); 1105 newActivityIntent.putExtra( 1106 BLOCKING_INTENT_EXTRA_BLOCKED_ACTIVITY_NAME, blockedActivity); 1107 newActivityIntent.putExtra( 1108 BLOCKING_INTENT_EXTRA_BLOCKED_TASK_ID, blockedTaskId); 1109 newActivityIntent.putExtra( 1110 BLOCKING_INTENT_EXTRA_ROOT_ACTIVITY_NAME, taskRootActivity); 1111 newActivityIntent.putExtra( 1112 BLOCKING_INTENT_EXTRA_IS_ROOT_ACTIVITY_DO, isRootDo); 1113 1114 return newActivityIntent; 1115 } 1116 1117 /** 1118 * Enable/Disable activity blocking by correspondingly enabling/disabling broadcasting UXR 1119 * changes in {@link CarUxRestrictionsManagerService}. This is only available in 1120 * engineering builds for development convenience. 1121 */ 1122 @Override setEnableActivityBlocking(boolean enable)1123 public synchronized void setEnableActivityBlocking(boolean enable) { 1124 if (!isDebugBuild()) { 1125 Log.e(CarLog.TAG_PACKAGE, "Cannot enable/disable activity blocking"); 1126 return; 1127 } 1128 // Check if the caller has the same signature as that of the car service. 1129 if (mPackageManager.checkSignatures(Process.myUid(), Binder.getCallingUid()) 1130 != PackageManager.SIGNATURE_MATCH) { 1131 throw new SecurityException( 1132 "Caller " + mPackageManager.getNameForUid(Binder.getCallingUid()) 1133 + " does not have the right signature"); 1134 } 1135 mCarUxRestrictionsService.setUxRChangeBroadcastEnabled(enable); 1136 } 1137 1138 /** 1139 * Get the distraction optimized activities for the given package. 1140 * 1141 * @param pkgName Name of the package 1142 * @return Array of the distraction optimized activities in the package 1143 */ 1144 @Nullable getDistractionOptimizedActivities(String pkgName)1145 public String[] getDistractionOptimizedActivities(String pkgName) { 1146 try { 1147 return CarAppMetadataReader.findDistractionOptimizedActivitiesAsUser(mContext, pkgName, 1148 mActivityManager.getCurrentUser()); 1149 } catch (NameNotFoundException e) { 1150 return null; 1151 } 1152 } 1153 1154 /** 1155 * Append one line of log for dumpsys. 1156 * 1157 * <p>Maintains the size of log by {@link #LOG_SIZE} and appends tag and timestamp to the line. 1158 */ addLog(String log)1159 private void addLog(String log) { 1160 while (mBlockedActivityLogs.size() >= LOG_SIZE) { 1161 mBlockedActivityLogs.remove(); 1162 } 1163 StringBuffer sb = new StringBuffer() 1164 .append(CarLog.TAG_PACKAGE).append(':') 1165 .append(DateFormat.format( 1166 "MM-dd HH:mm:ss", System.currentTimeMillis())).append(": ") 1167 .append(log); 1168 mBlockedActivityLogs.add(sb.toString()); 1169 } 1170 1171 /** 1172 * Reading policy and setting policy can take time. Run it in a separate handler thread. 1173 */ 1174 private class PackageHandler extends Handler { 1175 private static final int MSG_INIT = 0; 1176 private static final int MSG_PARSE_PKG = 1; 1177 private static final int MSG_UPDATE_POLICY = 2; 1178 private static final int MSG_RELEASE = 3; 1179 PackageHandler(Looper looper)1180 private PackageHandler(Looper looper) { 1181 super(looper); 1182 } 1183 requestInit()1184 private void requestInit() { 1185 Message msg = obtainMessage(MSG_INIT); 1186 sendMessage(msg); 1187 } 1188 requestRelease()1189 private void requestRelease() { 1190 removeMessages(MSG_INIT); 1191 removeMessages(MSG_UPDATE_POLICY); 1192 Message msg = obtainMessage(MSG_RELEASE); 1193 sendMessage(msg); 1194 } 1195 requestUpdatingPolicy(String packageName, CarAppBlockingPolicy policy, int flags)1196 private void requestUpdatingPolicy(String packageName, CarAppBlockingPolicy policy, 1197 int flags) { 1198 Pair<String, CarAppBlockingPolicy> pair = new Pair<>(packageName, policy); 1199 Message msg = obtainMessage(MSG_UPDATE_POLICY, flags, 0, pair); 1200 sendMessage(msg); 1201 } 1202 requestParsingInstalledPkgs(long delayMs)1203 private void requestParsingInstalledPkgs(long delayMs) { 1204 // Parse packages for current user. 1205 removeMessages(MSG_PARSE_PKG); 1206 1207 Message msg = obtainMessage(MSG_PARSE_PKG); 1208 if (delayMs == 0) { 1209 sendMessage(msg); 1210 } else { 1211 sendMessageDelayed(msg, delayMs); 1212 } 1213 } 1214 1215 @Override handleMessage(Message msg)1216 public void handleMessage(Message msg) { 1217 switch (msg.what) { 1218 case MSG_INIT: 1219 doHandleInit(); 1220 break; 1221 case MSG_PARSE_PKG: 1222 doParseInstalledPackages(); 1223 break; 1224 case MSG_UPDATE_POLICY: 1225 Pair<String, CarAppBlockingPolicy> pair = 1226 (Pair<String, CarAppBlockingPolicy>) msg.obj; 1227 doUpdatePolicy(pair.first, pair.second, msg.arg1); 1228 break; 1229 case MSG_RELEASE: 1230 doHandleRelease(); 1231 break; 1232 } 1233 } 1234 } 1235 1236 private static class AppBlockingPackageInfoWrapper { 1237 private final AppBlockingPackageInfo info; 1238 /** 1239 * Whether the current info is matching with the target package in system. Mismatch can 1240 * happen for version out of range or signature mismatch. 1241 */ 1242 private boolean isMatching; 1243 AppBlockingPackageInfoWrapper(AppBlockingPackageInfo info, boolean isMatching)1244 private AppBlockingPackageInfoWrapper(AppBlockingPackageInfo info, boolean isMatching) { 1245 this.info = info; 1246 this.isMatching = isMatching; 1247 } 1248 1249 @Override toString()1250 public String toString() { 1251 return "AppBlockingPackageInfoWrapper [info=" + info + ", isMatching=" + isMatching + 1252 "]"; 1253 } 1254 } 1255 1256 /** 1257 * Client policy holder per each client. Should be accessed with CarpackageManagerService.this 1258 * held. 1259 */ 1260 private static class ClientPolicy { 1261 private final HashMap<String, AppBlockingPackageInfoWrapper> whitelistsMap = 1262 new HashMap<>(); 1263 private final HashMap<String, AppBlockingPackageInfoWrapper> blacklistsMap = 1264 new HashMap<>(); 1265 replaceWhitelists(AppBlockingPackageInfoWrapper[] whitelists)1266 private void replaceWhitelists(AppBlockingPackageInfoWrapper[] whitelists) { 1267 whitelistsMap.clear(); 1268 addToWhitelists(whitelists); 1269 } 1270 addToWhitelists(AppBlockingPackageInfoWrapper[] whitelists)1271 private void addToWhitelists(AppBlockingPackageInfoWrapper[] whitelists) { 1272 if (whitelists == null) { 1273 return; 1274 } 1275 for (AppBlockingPackageInfoWrapper wrapper : whitelists) { 1276 if (wrapper != null) { 1277 whitelistsMap.put(wrapper.info.packageName, wrapper); 1278 } 1279 } 1280 } 1281 removeWhitelists(AppBlockingPackageInfoWrapper[] whitelists)1282 private void removeWhitelists(AppBlockingPackageInfoWrapper[] whitelists) { 1283 if (whitelists == null) { 1284 return; 1285 } 1286 for (AppBlockingPackageInfoWrapper wrapper : whitelists) { 1287 if (wrapper != null) { 1288 whitelistsMap.remove(wrapper.info.packageName); 1289 } 1290 } 1291 } 1292 replaceBlacklists(AppBlockingPackageInfoWrapper[] blacklists)1293 private void replaceBlacklists(AppBlockingPackageInfoWrapper[] blacklists) { 1294 blacklistsMap.clear(); 1295 addToBlacklists(blacklists); 1296 } 1297 addToBlacklists(AppBlockingPackageInfoWrapper[] blacklists)1298 private void addToBlacklists(AppBlockingPackageInfoWrapper[] blacklists) { 1299 if (blacklists == null) { 1300 return; 1301 } 1302 for (AppBlockingPackageInfoWrapper wrapper : blacklists) { 1303 if (wrapper != null) { 1304 blacklistsMap.put(wrapper.info.packageName, wrapper); 1305 } 1306 } 1307 } 1308 removeBlacklists(AppBlockingPackageInfoWrapper[] blacklists)1309 private void removeBlacklists(AppBlockingPackageInfoWrapper[] blacklists) { 1310 if (blacklists == null) { 1311 return; 1312 } 1313 for (AppBlockingPackageInfoWrapper wrapper : blacklists) { 1314 if (wrapper != null) { 1315 blacklistsMap.remove(wrapper.info.packageName); 1316 } 1317 } 1318 } 1319 } 1320 1321 private class ActivityLaunchListener 1322 implements SystemActivityMonitoringService.ActivityLaunchListener { 1323 @Override onActivityLaunch(TopTaskInfoContainer topTask)1324 public void onActivityLaunch(TopTaskInfoContainer topTask) { 1325 if (topTask == null) { 1326 Log.e(CarLog.TAG_PACKAGE, "Received callback with null top task."); 1327 return; 1328 } 1329 blockTopActivityIfNecessary(topTask); 1330 } 1331 } 1332 1333 /** 1334 * Listens to the UX restrictions from {@link CarUxRestrictionsManagerService} and initiates 1335 * checking if the foreground Activity should be blocked. 1336 */ 1337 private class UxRestrictionsListener extends ICarUxRestrictionsChangeListener.Stub { 1338 @GuardedBy("this") 1339 @Nullable 1340 private CarUxRestrictions mCurrentUxRestrictions; 1341 private final CarUxRestrictionsManagerService uxRestrictionsService; 1342 UxRestrictionsListener(CarUxRestrictionsManagerService service)1343 public UxRestrictionsListener(CarUxRestrictionsManagerService service) { 1344 uxRestrictionsService = service; 1345 } 1346 1347 @Override onUxRestrictionsChanged(CarUxRestrictions restrictions)1348 public void onUxRestrictionsChanged(CarUxRestrictions restrictions) { 1349 if (DBG_POLICY_ENFORCEMENT) { 1350 Log.d(CarLog.TAG_PACKAGE, "Received uxr restrictions: " 1351 + restrictions.isRequiresDistractionOptimization() 1352 + " : " + restrictions.getActiveRestrictions()); 1353 } 1354 // We are not handling the restrictions until we know what is allowed and what is not. 1355 // This is to handle some situations, where car service is ready and getting sensor 1356 // data but we haven't received the boot complete intents. 1357 if (!mHasParsedPackages) { 1358 return; 1359 } 1360 1361 synchronized (this) { 1362 mCurrentUxRestrictions = new CarUxRestrictions(restrictions); 1363 } 1364 checkIfTopActivityNeedsBlocking(); 1365 } 1366 checkIfTopActivityNeedsBlocking()1367 private void checkIfTopActivityNeedsBlocking() { 1368 boolean shouldCheck = false; 1369 synchronized (this) { 1370 if (mCurrentUxRestrictions != null 1371 && mCurrentUxRestrictions.isRequiresDistractionOptimization()) { 1372 shouldCheck = true; 1373 } 1374 } 1375 if (DBG_POLICY_ENFORCEMENT) { 1376 Log.d(CarLog.TAG_PACKAGE, "Should check top tasks?: " + shouldCheck); 1377 } 1378 if (shouldCheck) { 1379 // Loop over all top tasks to ensure tasks on virtual display can also be blocked. 1380 blockTopActivitiesIfNecessary(); 1381 } 1382 } 1383 isRestricted()1384 private synchronized boolean isRestricted() { 1385 // if current restrictions is null, try querying the service, once. 1386 if (mCurrentUxRestrictions == null) { 1387 mCurrentUxRestrictions = uxRestrictionsService.getCurrentUxRestrictions(); 1388 } 1389 if (mCurrentUxRestrictions != null) { 1390 return mCurrentUxRestrictions.isRequiresDistractionOptimization(); 1391 } 1392 // If restriction information is still not available (could happen during bootup), 1393 // return not restricted. This maintains parity with previous implementation but needs 1394 // a revisit as we test more. 1395 return false; 1396 } 1397 } 1398 1399 /** 1400 * Listens to the Boot intent to initiate parsing installed packages. 1401 */ 1402 private class UserSwitchedEventReceiver extends BroadcastReceiver { 1403 @Override onReceive(Context context, Intent intent)1404 public void onReceive(Context context, Intent intent) { 1405 if (intent == null || intent.getAction() == null) { 1406 return; 1407 } 1408 if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) { 1409 mHandler.requestParsingInstalledPkgs(0); 1410 } 1411 } 1412 } 1413 1414 /** 1415 * Listens to the package install/uninstall events to know when to initiate parsing 1416 * installed packages. 1417 */ 1418 private class PackageParsingEventReceiver extends BroadcastReceiver { 1419 private static final long PACKAGE_PARSING_DELAY_MS = 500; 1420 1421 @Override onReceive(Context context, Intent intent)1422 public void onReceive(Context context, Intent intent) { 1423 if (intent == null || intent.getAction() == null) { 1424 return; 1425 } 1426 if (DBG_POLICY_CHECK) { 1427 Log.d(CarLog.TAG_PACKAGE, 1428 "PackageParsingEventReceiver Received " + intent.getAction()); 1429 } 1430 String action = intent.getAction(); 1431 if (isPackageManagerAction(action)) { 1432 // send a delayed message so if we received multiple related intents, we parse 1433 // only once. 1434 logEventChange(intent); 1435 mHandler.requestParsingInstalledPkgs(PACKAGE_PARSING_DELAY_MS); 1436 } 1437 } 1438 isPackageManagerAction(String action)1439 private boolean isPackageManagerAction(String action) { 1440 return mPackageManagerActions.contains(action); 1441 } 1442 1443 /** 1444 * Convenience log function to log what changed. Logs only when more debug logs 1445 * are needed - DBG_POLICY_CHECK needs to be true 1446 */ logEventChange(Intent intent)1447 private void logEventChange(Intent intent) { 1448 if (!DBG_POLICY_CHECK || intent == null) { 1449 return; 1450 } 1451 1452 String packageName = intent.getData().getSchemeSpecificPart(); 1453 Log.d(CarLog.TAG_PACKAGE, "Pkg Changed:" + packageName); 1454 String action = intent.getAction(); 1455 if (action == null) { 1456 return; 1457 } 1458 if (action.equals(Intent.ACTION_PACKAGE_CHANGED)) { 1459 Log.d(CarLog.TAG_PACKAGE, "Changed components"); 1460 String[] cc = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST); 1461 if (cc != null) { 1462 for (String c : cc) { 1463 Log.d(CarLog.TAG_PACKAGE, c); 1464 } 1465 } 1466 } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED) 1467 || action.equals(Intent.ACTION_PACKAGE_ADDED)) { 1468 Log.d(CarLog.TAG_PACKAGE, action + " Replacing?: " + intent.getBooleanExtra( 1469 Intent.EXTRA_REPLACING, false)); 1470 } 1471 } 1472 } 1473 } 1474