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