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