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