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<ComponentName> 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
1003           see if they have any Distraction Optimized(DO) activities.
1004           For non system apps, we check if the app install source was a permittable
1005           source. This prevents side-loaded apps to fake DO.  Bypass the check
1006           for debug builds for development convenience. */
1007         if (!isDebugBuild()
1008                 && !PackageManagerHelper.isSystemApp(info.applicationInfo)
1009                 && !PackageManagerHelper.isUpdatedSystemApp(info.applicationInfo)) {
1010             try {
1011                 if (mAllowedAppInstallSources != null) {
1012                     String installerName = mPackageManager.getInstallerPackageName(
1013                             info.packageName);
1014                     if (installerName == null || (installerName != null
1015                             && !mAllowedAppInstallSources.contains(installerName))) {
1016                         Slogf.w(TAG, info.packageName + " not installed from permitted sources "
1017                                 + (installerName == null ? "NULL" : installerName));
1018                         return null;
1019                     }
1020                 }
1021             } catch (IllegalArgumentException e) {
1022                 Slogf.w(TAG, info.packageName + " not installed!");
1023                 return null;
1024             }
1025         }
1026 
1027         try {
1028             String[] doActivities = findDistractionOptimizedActivitiesAsUser(info.packageName,
1029                     userId);
1030             if (doActivities != null) {
1031                 // Some of the activities in this app are Distraction Optimized.
1032                 if (DBG) {
1033                     for (String activity : doActivities) {
1034                         Slogf.d(TAG, "adding " + activity + " from " + info.packageName
1035                                 + " to allowlist");
1036                     }
1037                 }
1038 
1039                 activities.addAll(Arrays.asList(doActivities));
1040             }
1041         } catch (NameNotFoundException e) {
1042             Slogf.w(TAG, "Error reading metadata: " + info.packageName);
1043             return null;
1044         }
1045 
1046         // Nothing to add to allowlist
1047         if (activities.isEmpty()) {
1048             return null;
1049         }
1050 
1051         /* 3. Check if parsed activity is in <activityBlocklist> in config.xml. Anything
1052               in blocklist should not be allowlisted, either as D.O. or by config. */
1053         if (configBlocklist.containsKey(info.packageName)) {
1054             Set<String> configBlocklistActivities = configBlocklist.get(info.packageName);
1055             if (configBlocklistActivities.isEmpty()) {
1056                 // Whole package should be blocklisted.
1057                 return null;
1058             }
1059             activities.removeAll(configBlocklistActivities);
1060         }
1061 
1062         Signature[] signatures;
1063         signatures = info.signatures;
1064         AppBlockingPackageInfo appBlockingInfo = new AppBlockingPackageInfo(info.packageName,
1065                 /* minRevisionCode = */ 0, /* maxRevisionCode = */ 0, flags, signatures,
1066                 activities.toArray(new String[activities.size()]));
1067         AppBlockingPackageInfoWrapper wrapper = new AppBlockingPackageInfoWrapper(
1068                 appBlockingInfo, true);
1069         return wrapper;
1070     }
1071 
1072     /**
1073      * Update map of allowlisted packages and activities of the form {pkgName, Allowlisted
1074      * activities} and set of denylisted packages. The information can come from a configuration XML
1075      * resource or from the apps marking their activities as distraction optimized.
1076      */
updateActivityAllowlistAndDenylistMap(String packageName)1077     private void updateActivityAllowlistAndDenylistMap(String packageName) {
1078         int userId = mActivityManager.getCurrentUser();
1079         Slogf.d(TAG, "Updating allowlist and denylist mapping for package: " + packageName
1080                 + " for UserId: " + userId);
1081         // Get the apps/activities that are allowlisted in the configuration XML resources.
1082         Map<String, Set<String>> configAllowlist = generateConfigAllowlist();
1083         Map<String, Set<String>> configBlocklist = generateConfigBlocklist();
1084 
1085         AppBlockingPackageInfoWrapper wrapper =
1086                 getPackageInfoWrapperForUser(packageName, userId, configAllowlist, configBlocklist);
1087 
1088         if (wrapper == null && userId != UserHandle.SYSTEM.getIdentifier()) {
1089             Slogf.d(TAG, "Updating allowlist and denylist mapping for package: " + packageName
1090                     + " for UserId: " + UserHandle.SYSTEM.getIdentifier());
1091             // check package for system user, in case package is disabled for current user
1092             wrapper = getPackageInfoWrapperForUser(packageName, UserHandle.SYSTEM.getIdentifier(),
1093                     configAllowlist, configBlocklist);
1094         }
1095 
1096         synchronized (mLock) {
1097             if (wrapper != null) {
1098                 if (DBG) {
1099                     Slogf.d(TAG, "Package: " + packageName + " added in allowlist.");
1100                 }
1101                 mActivityAllowlistMap.put(packageName, wrapper);
1102             } else {
1103                 if (DBG) {
1104                     Slogf.d(TAG, "Package: " + packageName + " added in denylist.");
1105                 }
1106                 mActivityDenylistPackages.add(packageName);
1107             }
1108         }
1109     }
1110 
generateConfigAllowlist()1111     private Map<String, Set<String>> generateConfigAllowlist() {
1112         synchronized (mLock) {
1113             if (mConfiguredAllowlistMap != null) return mConfiguredAllowlistMap;
1114 
1115             Map<String, Set<String>> configAllowlist = new HashMap<>();
1116             mConfiguredAllowlist = mContext.getString(R.string.activityAllowlist);
1117             if (mConfiguredAllowlist == null) {
1118                 Slogf.w(TAG, "Allowlist is null.");
1119             }
1120             parseConfigList(mConfiguredAllowlist, configAllowlist);
1121 
1122             mConfiguredSystemAllowlist = mContext.getString(R.string.systemActivityAllowlist);
1123             if (mConfiguredSystemAllowlist == null) {
1124                 Slogf.w(TAG, "System allowlist is null.");
1125             }
1126             parseConfigList(mConfiguredSystemAllowlist, configAllowlist);
1127 
1128             // Add the blocking overlay activity to the allowlist, since that needs to run in a
1129             // restricted state to communicate the reason an app was blocked.
1130             Set<String> defaultActivity = new ArraySet<>();
1131             if (mActivityBlockingActivity != null) {
1132                 defaultActivity.add(mActivityBlockingActivity.getClassName());
1133                 configAllowlist.put(mActivityBlockingActivity.getPackageName(), defaultActivity);
1134             }
1135 
1136             mConfiguredAllowlistMap = configAllowlist;
1137             return configAllowlist;
1138         }
1139     }
1140 
generateConfigBlocklist()1141     private Map<String, Set<String>> generateConfigBlocklist() {
1142         synchronized (mLock) {
1143             if (mConfiguredBlocklistMap != null) return mConfiguredBlocklistMap;
1144 
1145             Map<String, Set<String>> configBlocklist = new HashMap<>();
1146             mConfiguredBlocklist = mContext.getString(R.string.activityDenylist);
1147             if (mConfiguredBlocklist == null) {
1148                 if (DBG) {
1149                     Slogf.d(TAG, "Null blocklist in config");
1150                 }
1151             }
1152             parseConfigList(mConfiguredBlocklist, configBlocklist);
1153 
1154             mConfiguredBlocklistMap = configBlocklist;
1155             return configBlocklist;
1156         }
1157     }
1158 
isDebugBuild()1159     private boolean isDebugBuild() {
1160         return BuildHelper.isUserDebugBuild() || BuildHelper.isEngBuild();
1161     }
1162 
1163     /**
1164      * Parses the given resource and updates the input map of packages and activities.
1165      *
1166      * Key is package name and value is list of activities. Empty set implies whole package is
1167      * included.
1168      *
1169      * When there are multiple entries regarding one package, the entry with
1170      * greater scope wins. Namely if there were 2 entries such that one allowlists
1171      * an activity, and the other allowlists the entire package of the activity,
1172      * the package is allowlisted, regardless of input order.
1173      */
1174     @VisibleForTesting
parseConfigList(String configList, @NonNull Map<String, Set<String>> packageToActivityMap)1175     /* package */ void parseConfigList(String configList,
1176             @NonNull Map<String, Set<String>> packageToActivityMap) {
1177         if (configList == null) {
1178             return;
1179         }
1180         String[] entries = configList.split(PACKAGE_DELIMITER);
1181         for (String entry : entries) {
1182             String[] packageActivityPair = entry.split(PACKAGE_ACTIVITY_DELIMITER);
1183             Set<String> activities = packageToActivityMap.get(packageActivityPair[0]);
1184             boolean newPackage = false;
1185             if (activities == null) {
1186                 activities = new ArraySet<>();
1187                 newPackage = true;
1188                 packageToActivityMap.put(packageActivityPair[0], activities);
1189             }
1190             if (packageActivityPair.length == 1) { // whole package
1191                 activities.clear();
1192             } else if (packageActivityPair.length == 2) {
1193                 // add class name only when the whole package is not allowlisted.
1194                 if (newPackage || (activities.size() > 0)) {
1195                     activities.add(packageActivityPair[1]);
1196                 }
1197             }
1198         }
1199     }
1200 
1201     @Nullable
getActivitiesInPackage(PackageInfo info)1202     private List<String> getActivitiesInPackage(PackageInfo info) {
1203         if (info == null || info.activities == null) {
1204             return null;
1205         }
1206         List<String> activityList = new ArrayList<>();
1207         for (ActivityInfo aInfo : info.activities) {
1208             activityList.add(aInfo.name);
1209         }
1210         return activityList;
1211     }
1212 
1213     /**
1214      * Checks if there are any {@link CarAppBlockingPolicyService} and creates a proxy to
1215      * bind to them and retrieve the {@link CarAppBlockingPolicy}
1216      */
1217     @VisibleForTesting
startAppBlockingPolicies()1218     public void startAppBlockingPolicies() {
1219         Intent policyIntent = new Intent();
1220         policyIntent.setAction(CarAppBlockingPolicyService.SERVICE_INTERFACE);
1221         List<ResolveInfo> policyInfos = mPackageManager.queryIntentServices(policyIntent, 0);
1222         if (policyInfos == null) { //no need to wait for service binding and retrieval.
1223             return;
1224         }
1225         LinkedList<AppBlockingPolicyProxy> proxies = new LinkedList<>();
1226         for (ResolveInfo resolveInfo : policyInfos) {
1227             ServiceInfo serviceInfo = resolveInfo.serviceInfo;
1228             if (serviceInfo == null) {
1229                 continue;
1230             }
1231             if (serviceInfo.isEnabled()) {
1232                 if (mPackageManager.checkPermission(Car.PERMISSION_CONTROL_APP_BLOCKING,
1233                         serviceInfo.packageName) != PackageManager.PERMISSION_GRANTED) {
1234                     continue;
1235                 }
1236                 Slogf.i(TAG, "found policy holding service:" + serviceInfo);
1237                 AppBlockingPolicyProxy proxy = new AppBlockingPolicyProxy(this, mContext,
1238                         serviceInfo);
1239                 proxy.connect();
1240                 proxies.add(proxy);
1241             }
1242         }
1243         synchronized (mLock) {
1244             mProxies = proxies;
1245         }
1246     }
1247 
onPolicyConnectionAndSet(AppBlockingPolicyProxy proxy, CarAppBlockingPolicy policy)1248     public void onPolicyConnectionAndSet(AppBlockingPolicyProxy proxy,
1249             CarAppBlockingPolicy policy) {
1250         doHandlePolicyConnection(proxy, policy);
1251     }
1252 
onPolicyConnectionFailure(AppBlockingPolicyProxy proxy)1253     public void onPolicyConnectionFailure(AppBlockingPolicyProxy proxy) {
1254         doHandlePolicyConnection(proxy, null);
1255     }
1256 
doHandlePolicyConnection(AppBlockingPolicyProxy proxy, CarAppBlockingPolicy policy)1257     private void doHandlePolicyConnection(AppBlockingPolicyProxy proxy,
1258             CarAppBlockingPolicy policy) {
1259         synchronized (mLock) {
1260             if (mProxies == null) {
1261                 proxy.disconnect();
1262                 return;
1263             }
1264             mProxies.remove(proxy);
1265             if (mProxies.size() == 0) {
1266                 mProxies = null;
1267             }
1268         }
1269         try {
1270             if (policy != null) {
1271                 if (DBG) {
1272                     Slogf.d(TAG, "policy setting from policy service:" + proxy.getPackageName());
1273                 }
1274                 doSetAppBlockingPolicy(proxy.getPackageName(), policy, 0);
1275             }
1276         } finally {
1277             proxy.disconnect();
1278         }
1279     }
1280 
1281     @Override
1282     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
dump(IndentingPrintWriter writer)1283     public void dump(IndentingPrintWriter writer) {
1284         synchronized (mLock) {
1285             writer.println("*CarPackageManagerService*");
1286             writer.println("mEnableActivityBlocking:" + mEnableActivityBlocking);
1287             writer.println("mPreventTemplatedAppsFromShowingDialog:"
1288                     + mPreventTemplatedAppsFromShowingDialog);
1289             writer.println("mTemplateActivityClassName:" + mTemplateActivityClassName);
1290             List<String> restrictions = new ArrayList<>(mUxRestrictionsListeners.size());
1291             for (int i = 0; i < mUxRestrictionsListeners.size(); i++) {
1292                 int displayId = mUxRestrictionsListeners.keyAt(i);
1293                 UxRestrictionsListener listener = mUxRestrictionsListeners.valueAt(i);
1294                 restrictions.add(String.format("Display %d is %s",
1295                         displayId, (listener.isRestricted() ? "restricted" : "unrestricted")));
1296             }
1297             writer.println("Display Restrictions:\n" + String.join("\n", restrictions));
1298             writer.println(" Blocked activity log:");
1299             mBlockedActivityLogs.dump(writer);
1300             writer.print(dumpPoliciesLocked(true));
1301             writer.print("mCurrentDrivingSafetyRegion:");
1302             writer.println(mCurrentDrivingSafetyRegion);
1303             writer.print("mTempAllowedActivities:");
1304             writer.println(mTempAllowedActivities);
1305             writer.println("Car service overlay packages property name: "
1306                     + PackageManagerHelper.PROPERTY_CAR_SERVICE_OVERLAY_PACKAGES);
1307             writer.println("Car service overlay packages: "
1308                     + SystemProperties.get(
1309                             PackageManagerHelper.PROPERTY_CAR_SERVICE_OVERLAY_PACKAGES,
1310                             /* default= */ null));
1311             mVendorServiceController.dump(writer);
1312             mBlockingUiCommandListenerMediator.dump(writer);
1313         }
1314     }
1315 
1316     @Override
1317     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
dumpProto(ProtoOutputStream proto)1318     public void dumpProto(ProtoOutputStream proto) {}
1319 
1320     @GuardedBy("mLock")
dumpPoliciesLocked(boolean dumpAll)1321     private String dumpPoliciesLocked(boolean dumpAll) {
1322         StringBuilder sb = new StringBuilder();
1323         if (dumpAll) {
1324             sb.append("**System allowlist**\n");
1325             for (AppBlockingPackageInfoWrapper wrapper : mActivityAllowlistMap.values()) {
1326                 sb.append(wrapper.toString() + "\n");
1327             }
1328         }
1329         sb.append("**Client Policies**\n");
1330         for (Entry<String, ClientPolicy> entry : mClientPolicies.entrySet()) {
1331             sb.append("Client:" + entry.getKey() + "\n");
1332             sb.append("  allowlists:\n");
1333             for (AppBlockingPackageInfoWrapper wrapper : entry.getValue().mAllowlistsMap.values()) {
1334                 sb.append(wrapper.toString() + "\n");
1335             }
1336             sb.append("  blocklists:\n");
1337             for (AppBlockingPackageInfoWrapper wrapper : entry.getValue().mBlocklistsMap.values()) {
1338                 sb.append(wrapper.toString() + "\n");
1339             }
1340         }
1341         sb.append("**Unprocessed policy services**\n");
1342         if (mProxies != null) {
1343             for (AppBlockingPolicyProxy proxy : mProxies) {
1344                 sb.append(proxy.toString() + "\n");
1345             }
1346         }
1347         sb.append("**Allowlist string in resource**\n");
1348         sb.append(mConfiguredAllowlist + "\n");
1349 
1350         sb.append("**System allowlist string in resource**\n");
1351         sb.append(mConfiguredSystemAllowlist + "\n");
1352 
1353         sb.append("**Blocklist string in resource**\n");
1354         sb.append(mConfiguredBlocklist + "\n");
1355 
1356         sb.append("**Allowlist map from resource**\n");
1357         sb.append(mConfiguredAllowlistMap + "\n");
1358 
1359         sb.append("**Blocklist from resource**\n");
1360         sb.append(mConfiguredBlocklist + "\n");
1361 
1362         return sb.toString();
1363     }
1364 
1365     /**
1366      * Returns whether UX restrictions is required for the given display.
1367      *
1368      * Non-physical display will use restrictions for {@link Display#DEFAULT_DISPLAY}.
1369      */
isUxRestrictedOnDisplay(int displayId)1370     private boolean isUxRestrictedOnDisplay(int displayId) {
1371         UxRestrictionsListener listenerForTopTaskDisplay;
1372         synchronized (mLock) {
1373             if (mUxRestrictionsListeners.indexOfKey(displayId) < 0) {
1374                 Slogf.w(TAG,
1375                         "Cannot find UxR listener for display %d, using UxR on default display",
1376                         displayId);
1377                 listenerForTopTaskDisplay = mUxRestrictionsListeners.get(Display.DEFAULT_DISPLAY);
1378                 if (listenerForTopTaskDisplay == null) {
1379                     // This should never happen.
1380                     Slogf.e(TAG, "Missing listener for default display.");
1381                     return true;
1382                 }
1383             } else {
1384                 listenerForTopTaskDisplay = mUxRestrictionsListeners.get(displayId);
1385             }
1386         }
1387 
1388         return listenerForTopTaskDisplay.isRestricted();
1389     }
1390 
1391     /**
1392      * Blocks top activities on all displays if necessary.
1393      */
blockTopActivitiesOnAllDisplaysIfNecessary()1394     private void blockTopActivitiesOnAllDisplaysIfNecessary() {
1395         List<? extends TaskInfo> visibleTasks = mActivityService.getVisibleTasksInternal();
1396         ArrayList<Integer> restrictedDisplayIds = new ArrayList<>();
1397         synchronized (mLock) {
1398             for (int i = 0; i < mUxRestrictionsListeners.size(); i++) {
1399                 int displayId = mUxRestrictionsListeners.keyAt(i);
1400                 UxRestrictionsListener listener = mUxRestrictionsListeners.valueAt(i);
1401                 if (listener.isRestricted()) {
1402                     if (DBG) {
1403                         Slogf.d(TAG, "Display %d is in a UxRestricted state.",
1404                                 displayId);
1405                     }
1406                     restrictedDisplayIds.add(displayId);
1407                 } else {
1408                     if (DBG) {
1409                         Slogf.d(TAG, "Display %d is not in a UxRestricted state, not blocking.",
1410                                 displayId);
1411                     }
1412                 }
1413             }
1414         }
1415 
1416         // Block activities on a display if it is in a Ux restricted state.
1417         for (int i = 0; i < restrictedDisplayIds.size(); i++) {
1418             int displayId = restrictedDisplayIds.get(i);
1419             if (DBG) {
1420                 Slogf.d(TAG, "Initiating activity blocking on display %d.", displayId);
1421             }
1422             blockTopActivitiesOnDisplayIfNecessary(visibleTasks, displayId);
1423         }
1424     }
1425 
1426     /**
1427      * Blocks top activities on the given display if necessary.
1428      */
blockTopActivitiesOnDisplayIfNecessary(List<? extends TaskInfo> visibleTasks, int displayId)1429     private void blockTopActivitiesOnDisplayIfNecessary(List<? extends TaskInfo> visibleTasks,
1430             int displayId) {
1431         for (TaskInfo topTask : visibleTasks) {
1432             if (topTask == null) {
1433                 Slogf.e(TAG, "Top tasks contains null.");
1434                 continue;
1435             }
1436 
1437             int displayIdOfTask = TaskInfoHelper.getDisplayId(topTask);
1438             if (displayIdOfTask != displayId) {
1439                 // Only block activities on the given display. Skip if it's not the given
1440                 // display.
1441                 continue;
1442             }
1443 
1444             boolean blocked = blockTopActivity(topTask);
1445             if (blocked) {
1446                 if (DBG) {
1447                     Slogf.d(TAG, "Display %d has already been blocked.", displayIdOfTask);
1448                 }
1449                 break;
1450             }
1451         }
1452     }
1453 
1454     /**
1455      * Blocks the top activity if it's on a Ux restricted display.
1456      *
1457      * @return {@code true} if the {@code topTask} was blocked, {@code false} otherwise.
1458      */
blockTopActivityIfNecessary(TaskInfo topTask)1459     private boolean blockTopActivityIfNecessary(TaskInfo topTask) {
1460         int displayId = TaskInfoHelper.getDisplayId(topTask);
1461         synchronized (mLock) {
1462             if (!Objects.equals(mActivityBlockingActivity, topTask.topActivity)
1463                     && mTopActivityWithDialogPerDisplay.contains(displayId)
1464                     && !topTask.topActivity.equals(
1465                             mTopActivityWithDialogPerDisplay.get(displayId))) {
1466                 // Clear top activity-with-dialog if the activity has changed on this display.
1467                 mTopActivityWithDialogPerDisplay.remove(displayId);
1468             }
1469         }
1470         if (isUxRestrictedOnDisplay(displayId)) {
1471             return doBlockTopActivityIfNotAllowed(displayId, topTask);
1472         }
1473         return false;
1474     }
1475 
1476     /**
1477      * Blocks the top activity if not allowed.
1478      *
1479      * @return {@code true} if the {@code topTask} was blocked, {@code false} otherwise.
1480      */
blockTopActivity(TaskInfo topTask)1481     private boolean blockTopActivity(TaskInfo topTask) {
1482         int displayId = TaskInfoHelper.getDisplayId(topTask);
1483         synchronized (mLock) {
1484             if (!Objects.equals(mActivityBlockingActivity, topTask.topActivity)
1485                     && mTopActivityWithDialogPerDisplay.contains(displayId)
1486                     && !topTask.topActivity.equals(
1487                             mTopActivityWithDialogPerDisplay.get(displayId))) {
1488                 // Clear top activity-with-dialog if the activity has changed on this display.
1489                 mTopActivityWithDialogPerDisplay.remove(displayId);
1490             }
1491         }
1492 
1493         return doBlockTopActivityIfNotAllowed(displayId, topTask);
1494     }
1495 
1496     /**
1497      * @return {@code true} if the {@code topTask} was blocked, {@code false} otherwise.
1498      */
doBlockTopActivityIfNotAllowed(int displayId, TaskInfo topTask)1499     private boolean doBlockTopActivityIfNotAllowed(int displayId, TaskInfo topTask) {
1500         if (topTask.topActivity == null) {
1501             return false;
1502         }
1503         if (topTask.topActivity.equals(mActivityBlockingActivity)) {
1504             mBlockingActivityLaunchTimes.put(displayId, 0);
1505             mBlockingActivityTargets.put(displayId, null);
1506             // If topTask is already ActivityBlockingActivity, treat it as already blocked.
1507             return true;
1508         }
1509         boolean allowed = isActivityAllowed(topTask);
1510         if (DBG) {
1511             Slogf.d(TAG, "new activity:" + topTask.toString() + " allowed:" + allowed);
1512         }
1513         if (allowed) {
1514             return false;
1515         }
1516         if (!mEnableActivityBlocking) {
1517             Slogf.d(TAG, "Current activity " + topTask.topActivity
1518                     + " not allowed, blocking disabled.");
1519             return false;
1520         }
1521         if (DBG) {
1522             Slogf.d(TAG, "Current activity " + topTask.topActivity
1523                     + " not allowed, will block.");
1524         }
1525         // TaskMonitor based on TaskOrganizer reflects only the actually launched tasks,
1526         // (TaskStackChangeListener reflects the internal state of ActivityTaskManagerService)
1527         // So it takes some time to recognize the ActivityBlockingActivity is shown.
1528         // This guard is to prevent from launching ABA repeatedly until it is shown.
1529         ComponentName blockingActivityTarget = mBlockingActivityTargets.get(displayId);
1530         if (topTask.topActivity.equals(blockingActivityTarget)) {
1531             long blockingActivityLaunchTime = mBlockingActivityLaunchTimes.get(displayId);
1532             if (SystemClock.uptimeMillis() - blockingActivityLaunchTime < ABA_LAUNCH_TIMEOUT_MS) {
1533                 Slogf.d(TAG, "Waiting for BlockingActivity to be shown: displayId=%d", displayId);
1534                 return false;
1535             }
1536         }
1537 
1538         // Figure out the root task of blocked task.
1539         ComponentName rootTaskActivityName = topTask.baseActivity;
1540 
1541         boolean isRootDO = false;
1542         if (rootTaskActivityName != null) {
1543             isRootDO = isActivityDistractionOptimized(
1544                     rootTaskActivityName.getPackageName(), rootTaskActivityName.getClassName());
1545         }
1546 
1547         Intent newActivityIntent = createBlockingActivityIntent(
1548                 mActivityBlockingActivity, TaskInfoHelper.getDisplayId(topTask),
1549                 topTask.topActivity.flattenToShortString(), topTask.taskId,
1550                 rootTaskActivityName.flattenToString(), isRootDO);
1551 
1552         // Intent contains all info to debug what is blocked - log into both logcat and dumpsys.
1553         String log = "Starting blocking activity with intent: " + newActivityIntent.toUri(0);
1554         if (Slogf.isLoggable(TAG, Log.INFO)) {
1555             Slogf.i(TAG, log);
1556         }
1557         mBlockedActivityLogs.log(log);
1558         mBlockingActivityLaunchTimes.put(displayId, SystemClock.uptimeMillis());
1559         mBlockingActivityTargets.put(displayId, topTask.topActivity);
1560         mActivityService.blockActivity(topTask, newActivityIntent);
1561         return true;
1562     }
1563 
isActivityAllowed(TaskInfo topTaskInfoContainer)1564     private boolean isActivityAllowed(TaskInfo topTaskInfoContainer) {
1565         ComponentName activityName = topTaskInfoContainer.topActivity;
1566         boolean isDistractionOptimized = isActivityDistractionOptimized(
1567                 activityName.getPackageName(),
1568                 activityName.getClassName());
1569         if (!isDistractionOptimized) {
1570             return false;
1571         }
1572         return !(mPreventTemplatedAppsFromShowingDialog
1573                 && isTemplateActivity(activityName)
1574                 && isActivityShowingADialogOnDisplay(activityName,
1575                         TaskInfoHelper.getDisplayId(topTaskInfoContainer)));
1576     }
1577 
isTemplateActivity(ComponentName activityName)1578     private boolean isTemplateActivity(ComponentName activityName) {
1579         // TODO(b/191263486): Finalise on how to detect the templated activities.
1580         return activityName.getClassName().equals(mTemplateActivityClassName);
1581     }
1582 
isActivityShowingADialogOnDisplay(ComponentName activityName, int displayId)1583     private boolean isActivityShowingADialogOnDisplay(ComponentName activityName, int displayId) {
1584         String output = dumpWindows();
1585         List<WindowDumpParser.Window> appWindows =
1586                 WindowDumpParser.getParsedAppWindows(output, activityName.getPackageName());
1587         // TODO(b/192354699): Handle case where an activity can have multiple instances on the same
1588         //  display.
1589         int totalAppWindows = appWindows.size();
1590         String firstActivityRecord = null;
1591         int numTopActivityAppWindowsOnDisplay = 0;
1592         for (int i = 0; i < totalAppWindows; i++) {
1593             WindowDumpParser.Window appWindow = appWindows.get(i);
1594             if (appWindow.getDisplayId() != displayId) {
1595                 continue;
1596             }
1597             if (TextUtils.isEmpty(appWindow.getActivityRecord())) {
1598                 continue;
1599             }
1600             if (firstActivityRecord == null) {
1601                 firstActivityRecord = appWindow.getActivityRecord();
1602             }
1603             if (firstActivityRecord.equals(appWindow.getActivityRecord())) {
1604                 numTopActivityAppWindowsOnDisplay++;
1605             }
1606         }
1607         Slogf.d(TAG, "Top activity =  " + activityName);
1608         Slogf.d(TAG, "Number of app widows of top activity = " + numTopActivityAppWindowsOnDisplay);
1609         boolean isShowingADialog = numTopActivityAppWindowsOnDisplay > 1;
1610         synchronized (mLock) {
1611             if (isShowingADialog) {
1612                 mTopActivityWithDialogPerDisplay.put(displayId, activityName);
1613             } else {
1614                 mTopActivityWithDialogPerDisplay.remove(displayId);
1615             }
1616         }
1617         return isShowingADialog;
1618     }
1619 
dumpWindows()1620     private String dumpWindows() {
1621         try {
1622             ParcelFileDescriptor[] fileDescriptors = ParcelFileDescriptor.createSocketPair();
1623             mWindowManagerBinder.dump(
1624                     fileDescriptors[0].getFileDescriptor(), WINDOW_DUMP_ARGUMENTS);
1625             fileDescriptors[0].close();
1626             StringBuilder outputBuilder = new StringBuilder();
1627             try (BufferedReader reader = new BufferedReader(
1628                     new FileReader(fileDescriptors[1].getFileDescriptor()))) {
1629                 String line;
1630                 while ((line = reader.readLine()) != null) {
1631                     outputBuilder.append(line).append("\n");
1632                 }
1633             }
1634             fileDescriptors[1].close();
1635             return outputBuilder.toString();
1636         } catch (IOException | RemoteException e) {
1637             throw new RuntimeException(e);
1638         }
1639     }
1640 
1641     /**
1642      * Creates an intent to start blocking activity.
1643      *
1644      * @param blockingActivity the activity to launch
1645      * @param blockedActivity  the activity being blocked
1646      * @param blockedTaskId    the blocked task id, which contains the blocked activity
1647      * @param taskRootActivity root activity of the blocked task
1648      * @param isRootDo         denotes if the root activity is distraction optimised
1649      * @return an intent to launch the blocking activity.
1650      */
createBlockingActivityIntent(ComponentName blockingActivity, int displayId, String blockedActivity, int blockedTaskId, String taskRootActivity, boolean isRootDo)1651     private static Intent createBlockingActivityIntent(ComponentName blockingActivity,
1652             int displayId, String blockedActivity, int blockedTaskId, String taskRootActivity,
1653             boolean isRootDo) {
1654         Intent newActivityIntent = new Intent();
1655         newActivityIntent.setFlags(
1656                 Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
1657         newActivityIntent.setComponent(blockingActivity);
1658         newActivityIntent.putExtra(
1659                 BLOCKING_INTENT_EXTRA_DISPLAY_ID, displayId);
1660         newActivityIntent.putExtra(
1661                 BLOCKING_INTENT_EXTRA_BLOCKED_ACTIVITY_NAME, blockedActivity);
1662         newActivityIntent.putExtra(
1663                 BLOCKING_INTENT_EXTRA_BLOCKED_TASK_ID, blockedTaskId);
1664         newActivityIntent.putExtra(
1665                 BLOCKING_INTENT_EXTRA_ROOT_ACTIVITY_NAME, taskRootActivity);
1666         newActivityIntent.putExtra(
1667                 BLOCKING_INTENT_EXTRA_IS_ROOT_ACTIVITY_DO, isRootDo);
1668 
1669         return newActivityIntent;
1670     }
1671 
1672     /**
1673      * Enable/Disable activity blocking by correspondingly enabling/disabling broadcasting UXR
1674      * changes in {@link CarUxRestrictionsManagerService}. This is only available in
1675      * engineering builds for development convenience.
1676      */
1677     @Override
setEnableActivityBlocking(boolean enable)1678     public void setEnableActivityBlocking(boolean enable) {
1679         if (!isDebugBuild()) {
1680             Slogf.e(TAG, "Cannot enable/disable activity blocking");
1681             return;
1682         }
1683 
1684         // Check if the caller has the same signature as that of the car service.
1685         if (mPackageManager.checkSignatures(Process.myUid(), Binder.getCallingUid())
1686                 != PackageManager.SIGNATURE_MATCH) {
1687             throw new SecurityException(
1688                     "Caller " + mPackageManager.getNameForUid(Binder.getCallingUid())
1689                     + " does not have the right signature");
1690         }
1691         mCarUxRestrictionsService.setUxRChangeBroadcastEnabled(enable);
1692     }
1693 
1694     @Override
getTargetCarVersion(String packageName)1695     public CarVersion getTargetCarVersion(String packageName) {
1696         return getTargetCarVersion(Binder.getCallingUserHandle(), packageName);
1697     }
1698 
1699     @Override
getSelfTargetCarVersion(String packageName)1700     public CarVersion getSelfTargetCarVersion(String packageName) {
1701         checkCalledByPackage(mContext, packageName);
1702 
1703         return getTargetCarVersion(Binder.getCallingUserHandle(), packageName);
1704     }
1705 
1706     /**
1707      * Public, as it's also used by {@code ICarImpl}.
1708      */
getTargetCarVersion(UserHandle user, String packageName)1709     public CarVersion getTargetCarVersion(UserHandle user, String packageName) {
1710         Context context = mContext.createContextAsUser(user, /* flags= */ 0);
1711         return getTargetCarVersion(context, packageName);
1712     }
1713 
1714     /**
1715      * Used by {@code CarShellCommand} as well.
1716      */
1717     @Nullable
getTargetCarVersion(Context context, String packageName)1718     public static CarVersion getTargetCarVersion(Context context, String packageName) {
1719         String permission = android.Manifest.permission.QUERY_ALL_PACKAGES;
1720         if (context.checkCallingOrSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
1721             Slogf.w(TAG, "getTargetCarVersion(%s): UID %d doesn't have %s permission",
1722                     packageName, Binder.getCallingUid(), permission);
1723             throw new SecurityException("requires permission " + permission);
1724         }
1725         ApplicationInfo info = null;
1726         try {
1727             info = context.getPackageManager().getApplicationInfo(packageName,
1728                     PackageManager.ApplicationInfoFlags.of(PackageManager.GET_META_DATA));
1729         } catch (NameNotFoundException e) {
1730             if (DBG) {
1731                 Slogf.d(TAG, "getTargetCarVersion(%s, %s): not found: %s", context.getUser(),
1732                         packageName, e);
1733             }
1734             throw new ServiceSpecificException(CarPackageManager.ERROR_CODE_NO_PACKAGE,
1735                     e.getMessage());
1736         }
1737         return CarVersionParser.getTargetCarVersion(info);
1738     }
1739 
1740     /**
1741      * Get the distraction optimized activities for the given package.
1742      *
1743      * @param pkgName Name of the package
1744      * @return Array of the distraction optimized activities in the package
1745      */
1746     @Nullable
getDistractionOptimizedActivities(String pkgName)1747     public String[] getDistractionOptimizedActivities(String pkgName) {
1748         try {
1749             return findDistractionOptimizedActivitiesAsUser(pkgName,
1750                     mActivityManager.getCurrentUser());
1751         } catch (NameNotFoundException e) {
1752             return null;
1753         }
1754     }
1755 
1756     @Override
requiresDisplayCompat(String packageName)1757     public boolean requiresDisplayCompat(String packageName) {
1758         if (!callerCanQueryPackage(packageName)) {
1759             throw new SecurityException("requires permission " + QUERY_ALL_PACKAGES);
1760         }
1761         int callingUid = Binder.getCallingUid();
1762         if (!hasPermissionGranted(PERMISSION_MANAGE_DISPLAY_COMPATIBILITY, callingUid)) {
1763             throw new SecurityException("requires permission "
1764                     + PERMISSION_MANAGE_DISPLAY_COMPATIBILITY);
1765         }
1766         return CarServiceHelperWrapper.getInstance().requiresDisplayCompat(
1767                 Objects.requireNonNull(packageName, "packageName cannot be Null"));
1768     }
1769 
findDistractionOptimizedActivitiesAsUser(String pkgName, int userId)1770     private String[] findDistractionOptimizedActivitiesAsUser(String pkgName, int userId)
1771             throws NameNotFoundException {
1772         String regionString;
1773         synchronized (mLock) {
1774             regionString = mCurrentDrivingSafetyRegion;
1775         }
1776         return CarAppMetadataReader.findDistractionOptimizedActivitiesAsUser(mContext, pkgName,
1777                 userId, regionString);
1778     }
1779 
1780     /**
1781      * Reading policy and setting policy can take time. Run it in a separate handler thread.
1782      */
1783     private static final class PackageHandler extends Handler {
1784         private static final String TAG = CarLog.tagFor(CarPackageManagerService.class);
1785 
1786         private static final int MSG_INIT = 0;
1787         private static final int MSG_PARSE_PKG = 1;
1788         private static final int MSG_UPDATE_POLICY = 2;
1789         private static final int MSG_RELEASE = 3;
1790 
1791         private final WeakReference<CarPackageManagerService> mService;
1792 
PackageHandler(Looper looper, CarPackageManagerService service)1793         private PackageHandler(Looper looper, CarPackageManagerService service) {
1794             super(looper);
1795             mService = new WeakReference<CarPackageManagerService>(service);
1796         }
1797 
requestInit()1798         private void requestInit() {
1799             Message msg = obtainMessage(MSG_INIT);
1800             sendMessage(msg);
1801         }
1802 
requestRelease()1803         private void requestRelease() {
1804             removeMessages(MSG_UPDATE_POLICY);
1805             Message msg = obtainMessage(MSG_RELEASE);
1806             sendMessage(msg);
1807         }
1808 
requestUpdatingPolicy(String packageName, CarAppBlockingPolicy policy, int flags)1809         private void requestUpdatingPolicy(String packageName, CarAppBlockingPolicy policy,
1810                 int flags) {
1811             Pair<String, CarAppBlockingPolicy> pair = new Pair<>(packageName, policy);
1812             Message msg = obtainMessage(MSG_UPDATE_POLICY, flags, 0, pair);
1813             sendMessage(msg);
1814         }
1815 
requestParsingInstalledPkg(String packageName)1816         private void requestParsingInstalledPkg(String packageName) {
1817             Message msg = obtainMessage(MSG_PARSE_PKG, packageName);
1818             sendMessage(msg);
1819         }
1820 
1821         @Override
handleMessage(Message msg)1822         public void handleMessage(Message msg) {
1823             CarPackageManagerService service = mService.get();
1824             if (service == null) {
1825                 Slogf.i(TAG, "handleMessage null service");
1826                 return;
1827             }
1828             switch (msg.what) {
1829                 case MSG_INIT:
1830                     service.doHandleInit();
1831                     break;
1832                 case MSG_PARSE_PKG:
1833                     service.doParseInstalledPackage((String) msg.obj);
1834                     break;
1835                 case MSG_UPDATE_POLICY:
1836                     Pair<String, CarAppBlockingPolicy> pair =
1837                             (Pair<String, CarAppBlockingPolicy>) msg.obj;
1838                     service.doUpdatePolicy(pair.first, pair.second, msg.arg1);
1839                     break;
1840                 case MSG_RELEASE:
1841                     service.doHandleRelease();
1842                     break;
1843                 default:
1844                     break;
1845             }
1846         }
1847     }
1848 
1849     private static class AppBlockingPackageInfoWrapper {
1850         private final AppBlockingPackageInfo info;
1851         /**
1852          * Whether the current info is matching with the target package in system. Mismatch can
1853          * happen for version out of range or signature mismatch.
1854          */
1855         private boolean isMatching;
1856 
AppBlockingPackageInfoWrapper(AppBlockingPackageInfo info, boolean isMatching)1857         private AppBlockingPackageInfoWrapper(AppBlockingPackageInfo info, boolean isMatching) {
1858             this.info = info;
1859             this.isMatching = isMatching;
1860         }
1861 
1862         @Override
toString()1863         public String toString() {
1864             return "AppBlockingPackageInfoWrapper [info=" + info + ", isMatching=" + isMatching +
1865                     "]";
1866         }
1867     }
1868 
1869     /**
1870      * Client policy holder per each client. Should be accessed with CarpackageManagerService.this
1871      * held.
1872      */
1873     private static class ClientPolicy {
1874         private final HashMap<String, AppBlockingPackageInfoWrapper> mAllowlistsMap =
1875                 new HashMap<>();
1876         private final HashMap<String, AppBlockingPackageInfoWrapper> mBlocklistsMap =
1877                 new HashMap<>();
1878 
replaceAllowlists(AppBlockingPackageInfoWrapper[] allowlists)1879         private void replaceAllowlists(AppBlockingPackageInfoWrapper[] allowlists) {
1880             mAllowlistsMap.clear();
1881             addToAllowlists(allowlists);
1882         }
1883 
addToAllowlists(AppBlockingPackageInfoWrapper[] allowlists)1884         private void addToAllowlists(AppBlockingPackageInfoWrapper[] allowlists) {
1885             if (allowlists == null) {
1886                 return;
1887             }
1888             for (AppBlockingPackageInfoWrapper wrapper : allowlists) {
1889                 if (wrapper != null) {
1890                     mAllowlistsMap.put(wrapper.info.packageName, wrapper);
1891                 }
1892             }
1893         }
1894 
removeAllowlists(AppBlockingPackageInfoWrapper[] allowlists)1895         private void removeAllowlists(AppBlockingPackageInfoWrapper[] allowlists) {
1896             if (allowlists == null) {
1897                 return;
1898             }
1899             for (AppBlockingPackageInfoWrapper wrapper : allowlists) {
1900                 if (wrapper != null) {
1901                     mAllowlistsMap.remove(wrapper.info.packageName);
1902                 }
1903             }
1904         }
1905 
replaceBlocklists(AppBlockingPackageInfoWrapper[] blocklists)1906         private void replaceBlocklists(AppBlockingPackageInfoWrapper[] blocklists) {
1907             mBlocklistsMap.clear();
1908             addToBlocklists(blocklists);
1909         }
1910 
addToBlocklists(AppBlockingPackageInfoWrapper[] blocklists)1911         private void addToBlocklists(AppBlockingPackageInfoWrapper[] blocklists) {
1912             if (blocklists == null) {
1913                 return;
1914             }
1915             for (AppBlockingPackageInfoWrapper wrapper : blocklists) {
1916                 if (wrapper != null) {
1917                     mBlocklistsMap.put(wrapper.info.packageName, wrapper);
1918                 }
1919             }
1920         }
1921 
removeBlocklists(AppBlockingPackageInfoWrapper[] blocklists)1922         private void removeBlocklists(AppBlockingPackageInfoWrapper[] blocklists) {
1923             if (blocklists == null) {
1924                 return;
1925             }
1926             for (AppBlockingPackageInfoWrapper wrapper : blocklists) {
1927                 if (wrapper != null) {
1928                     mBlocklistsMap.remove(wrapper.info.packageName);
1929                 }
1930             }
1931         }
1932     }
1933 
1934     private class ActivityListener implements CarActivityService.ActivityListener {
1935         @Override
onActivityCameOnTop(TaskInfo topTask)1936         public void onActivityCameOnTop(TaskInfo topTask) {
1937             if (topTask == null) {
1938                 Slogf.e(TAG, "Received callback with null top task.");
1939                 return;
1940             }
1941             boolean isBlockingActivity = Objects.equals(mActivityBlockingActivity,
1942                     topTask.topActivity);
1943             synchronized (mLock) {
1944                 if (isBlockingActivity) {
1945                     // This is to keep track of the blocking ui taskInfo.
1946                     mBlockingUiTaskInfoPerDisplay.put(TaskInfoHelper.getDisplayId(topTask),
1947                             topTask);
1948                 }
1949                 mLastKnownDisplayIdForTask.put(topTask.taskId,
1950                         TaskInfoHelper.getDisplayId(topTask));
1951             }
1952             blockTopActivityIfNecessary(topTask);
1953         }
1954 
1955         @Override
onActivityChangedInBackstack(TaskInfo taskInfo)1956         public void onActivityChangedInBackstack(TaskInfo taskInfo) {
1957             if (taskInfo == null) {
1958                 Slogf.e(TAG, "Received callback with null task info.");
1959                 return;
1960             }
1961             int lastKnownDisplayId;
1962             synchronized (mLock) {
1963                 // Only update the array if display Id for the task is valid since display Id can
1964                 // often be invalid when the task has vanished.
1965                 if (TaskInfoHelper.getDisplayId(taskInfo) != Display.INVALID_DISPLAY) {
1966                     mLastKnownDisplayIdForTask.put(taskInfo.taskId,
1967                             TaskInfoHelper.getDisplayId(taskInfo));
1968                 }
1969                 lastKnownDisplayId = mLastKnownDisplayIdForTask.get(taskInfo.taskId);
1970             }
1971             if (DBG) {
1972                 Slogf.i(TAG, "Callback for task %s on display id %d.", taskInfo.taskId,
1973                         lastKnownDisplayId);
1974             }
1975             // Only finish the blocking ui if it is visible and there is some change in the
1976             // backstack for the activity that is being blocked. This is because the blocked
1977             // activity could have crashed due to which there is a need for blocking ui to finish.
1978             if (isBlockingUiVisible(lastKnownDisplayId) && isBlockedActivityTarget(
1979                     lastKnownDisplayId, taskInfo)) {
1980                 mHandler.post(() -> finishBlockingUi(taskInfo));
1981                 synchronized (mLock) {
1982                     mBlockingUiTaskInfoPerDisplay.delete(lastKnownDisplayId);
1983                 }
1984             }
1985         }
1986     }
1987 
1988     /**
1989      * Checks if blocking ui is visible on that {@code displayId}.
1990      *
1991      * @param displayId the display id of the {@link TaskInfo}.
1992      * @return {@code true} if the blocking ui is visible, {@code false} otherwise.
1993      */
isBlockingUiVisible(int displayId)1994     private boolean isBlockingUiVisible(int displayId) {
1995         synchronized (mLock) {
1996             return mBlockingUiTaskInfoPerDisplay.get(displayId) != null && TaskInfoHelper.isVisible(
1997                     mBlockingUiTaskInfoPerDisplay.get(displayId));
1998         }
1999     }
2000 
2001     /**
2002      * Check if this stack change came from the blocked {@code taskInfo} in
2003      * {@code mBlockingActivityTargets} for {@code displayId}. Ignore other activities since they
2004      * cannot can cause a visibility change for the blocked activity target.
2005      *
2006      * @param displayId the display id of the {@link TaskInfo}.
2007      * @param taskInfo  {@link TaskInfo} due to which the task stack changed.
2008      * @return {@code true} if this stack change came from blocked {@code taskInfo} for
2009      * {@code displayId}, {@code false} otherwise.
2010      */
isBlockedActivityTarget(int displayId, TaskInfo taskInfo)2011     private boolean isBlockedActivityTarget(int displayId, TaskInfo taskInfo) {
2012         return mBlockingActivityTargets.get(displayId) == taskInfo.topActivity;
2013     }
2014 
2015     /**
2016      * Registers the {@link ICarBlockingUiCommandListener} listening for the commands to control the
2017      * blocking ui.
2018      *
2019      * @param listener  listener to register.
2020      * @param displayId display Id with which the listener is associated.
2021      */
registerBlockingUiCommandListener(ICarBlockingUiCommandListener listener, int displayId)2022     public void registerBlockingUiCommandListener(ICarBlockingUiCommandListener listener,
2023             int displayId) {
2024         ensurePermission();
2025         mBlockingUiCommandListenerMediator.registerBlockingUiCommandListener(listener, displayId);
2026     }
2027 
2028     /**
2029      * Unregisters the {@link ICarBlockingUiCommandListener}.
2030      *
2031      * @param listener listener to unregister.
2032      */
unregisterBlockingUiCommandListener(ICarBlockingUiCommandListener listener)2033     public void unregisterBlockingUiCommandListener(ICarBlockingUiCommandListener listener) {
2034         ensurePermission();
2035         mBlockingUiCommandListenerMediator.unregisterBlockingUiCommandListener(listener);
2036     }
2037 
2038     /**
2039      * Broadcast the finish command to listeners.
2040      *
2041      * @param taskInfo the {@link TaskInfo} due to which finish is broadcast to the listeners.
2042      */
finishBlockingUi(TaskInfo taskInfo)2043     public void finishBlockingUi(TaskInfo taskInfo) {
2044         ensurePermission();
2045         int displayId = getLastKnownDisplayIdForTask(taskInfo.taskId);
2046         mBlockingUiCommandListenerMediator.finishBlockingUi(taskInfo, displayId);
2047         cleanUpLastKnownDisplayIdForTask(taskInfo);
2048     }
2049 
2050     /**
2051      * Returns the last known display Id for the given {@link TaskInfo}.
2052      */
getLastKnownDisplayIdForTask(int taskId)2053     private int getLastKnownDisplayIdForTask(int taskId) {
2054         synchronized (mLock) {
2055             return mLastKnownDisplayIdForTask.get(taskId);
2056         }
2057     }
2058 
2059     /**
2060      * Removes the task from {@code mLastKnownDisplayIdForTask}.
2061      */
cleanUpLastKnownDisplayIdForTask(TaskInfo taskInfo)2062     private void cleanUpLastKnownDisplayIdForTask(TaskInfo taskInfo) {
2063         synchronized (mLock) {
2064             // This can happen when the task has not been removed from mLastKnownDisplayIdForTask
2065             // when the task vanishes in onTaskVanished.
2066             mLastKnownDisplayIdForTask.delete(taskInfo.taskId);
2067         }
2068     }
2069 
2070     /**
2071      * Get number of registered callbacks for the display ID.
2072      *
2073      * @param displayId display Id with which the listener is associated.
2074      * @return number of registered callbacks for the given {@code displayId}.
2075      */
2076     @VisibleForTesting
getCarBlockingUiCommandListenerRegisteredCallbacksForDisplay(int displayId)2077     public int getCarBlockingUiCommandListenerRegisteredCallbacksForDisplay(int displayId) {
2078         return mBlockingUiCommandListenerMediator
2079                 .getCarBlockingUiCommandListenerRegisteredCallbacksForDisplay(displayId);
2080     }
2081 
2082     /** Ensure permission is granted. */
ensurePermission()2083     private void ensurePermission() {
2084         if (mContext.checkCallingOrSelfPermission(Car.PERMISSION_REGISTER_CAR_SYSTEM_UI_PROXY)
2085                 != PackageManager.PERMISSION_GRANTED) {
2086             throw new SecurityException(
2087                     "requires permission " + Car.PERMISSION_REGISTER_CAR_SYSTEM_UI_PROXY);
2088         }
2089     }
2090 
2091     /**
2092      * Listens to the UX restrictions from {@link CarUxRestrictionsManagerService} and initiates
2093      * checking if the foreground Activity should be blocked.
2094      */
2095     private class UxRestrictionsListener extends ICarUxRestrictionsChangeListener.Stub {
2096         @GuardedBy("mLock")
2097         @Nullable
2098         private CarUxRestrictions mCurrentUxRestrictions;
2099         private final CarUxRestrictionsManagerService uxRestrictionsService;
2100         private final int mDisplayId;
2101 
UxRestrictionsListener(CarUxRestrictionsManagerService service, int displayId)2102         UxRestrictionsListener(CarUxRestrictionsManagerService service, int displayId) {
2103             uxRestrictionsService = service;
2104             mDisplayId = displayId;
2105         }
2106 
2107         @Override
onUxRestrictionsChanged(CarUxRestrictions restrictions)2108         public void onUxRestrictionsChanged(CarUxRestrictions restrictions) {
2109             if (DBG) {
2110                 Slogf.d(TAG, "Received uxr restrictions: Requires DO? %b : %d on display %d",
2111                         restrictions.isRequiresDistractionOptimization(),
2112                         restrictions.getActiveRestrictions(), mDisplayId);
2113             }
2114 
2115             // Check if top activities need blocking on this display.
2116             boolean shouldCheck = false;
2117             synchronized (mLock) {
2118                 mCurrentUxRestrictions = new CarUxRestrictions(restrictions);
2119                 shouldCheck = mCurrentUxRestrictions.isRequiresDistractionOptimization();
2120             }
2121 
2122             if (DBG) {
2123                 Slogf.d(TAG, "Should check top tasks for blocking on display %d?: " + shouldCheck,
2124                         mDisplayId);
2125             }
2126 
2127             if (shouldCheck) {
2128                 // Each UxRestrictionsListener is only responsible for blocking activities on their
2129                 // own display.
2130                 mHandler.post(() -> blockTopActivitiesOnDisplayIfNecessary(
2131                         mActivityService.getVisibleTasksInternal(), mDisplayId));
2132             }
2133         }
2134 
isRestricted()2135         private boolean isRestricted() {
2136             // If current restrictions is null, try querying the service, once.
2137             synchronized (mLock) {
2138                 if (mCurrentUxRestrictions == null) {
2139                     mCurrentUxRestrictions = uxRestrictionsService.getCurrentUxRestrictions(
2140                             mDisplayId);
2141                 }
2142                 if (mCurrentUxRestrictions != null) {
2143                     return mCurrentUxRestrictions.isRequiresDistractionOptimization();
2144                 }
2145             }
2146 
2147             // If restriction information is still not available (could happen during bootup),
2148             // return not restricted.  This maintains parity with previous implementation but needs
2149             // a revisit as we test more.
2150             return false;
2151         }
2152     }
2153 
2154     /**
2155      * Called when a window change event is received by the {@link CarSafetyAccessibilityService}.
2156      */
2157     @VisibleForTesting
onWindowChangeEvent(@onNull AccessibilityEvent event)2158     void onWindowChangeEvent(@NonNull AccessibilityEvent event) {
2159         boolean receivedFromActivityBlockingActivity =
2160                 event.getPackageName() != null && event.getClassName() != null
2161                         && mActivityBlockingActivity.getPackageName().contentEquals(
2162                         event.getPackageName())
2163                         && mActivityBlockingActivity.getClassName().contentEquals(
2164                         event.getClassName());
2165         if (!receivedFromActivityBlockingActivity) {
2166             int displayId = event.getDisplayId();
2167             if (isUxRestrictedOnDisplay(displayId)) {
2168                 if (DBG) {
2169                     Slogf.d(TAG, "onWindowChange event from package %s on Ux restricted display %d,"
2170                             + " checking activity blocking", event.getPackageName(), displayId);
2171                 }
2172                 // Schedule activity blocking with mHandler to ensure there is no concurrent
2173                 // activity blocking.
2174                 mHandler.post(() ->
2175                         blockTopActivitiesOnDisplayIfNecessary(
2176                             mActivityService.getVisibleTasksInternal(), displayId));
2177             }
2178         } else {
2179             Slogf.d(TAG, "Discarded onWindowChangeEvent received from "
2180                     + "ActivityBlockingActivity");
2181         }
2182     }
2183 
2184     /**
2185      * Listens to the package install/uninstall events to know when to initiate parsing
2186      * installed packages.
2187      */
2188     private class PackageParsingEventReceiver extends BroadcastReceiver {
2189         @Override
onReceive(Context context, Intent intent)2190         public void onReceive(Context context, Intent intent) {
2191             if (intent == null || intent.getAction() == null) {
2192                 return;
2193             }
2194             if (DBG) {
2195                 Slogf.d(TAG, "PackageParsingEventReceiver Received " + intent.getAction());
2196             }
2197             String action = intent.getAction();
2198             if (isPackageManagerAction(action)) {
2199                 // send a delayed message so if we received multiple related intents, we parse
2200                 // only once.
2201                 logEventChange(intent);
2202                 String packageName = getPackageName(intent);
2203                 mHandler.requestParsingInstalledPkg(packageName);
2204             }
2205         }
2206 
getPackageName(Intent intent)2207         private String getPackageName(Intent intent) {
2208             // For mPackageManagerActions, data should contain package name.
2209             String dataString = intent.getDataString();
2210             if (dataString == null) return null;
2211 
2212             String scheme = intent.getScheme();
2213             if (!Objects.equals(scheme, "package")) return null;
2214 
2215             String[] splitData = intent.getDataString().split(":");
2216             if (splitData.length < 2) return null;
2217 
2218             return splitData[1];
2219         }
2220 
isPackageManagerAction(String action)2221         private boolean isPackageManagerAction(String action) {
2222             return mPackageManagerActions.contains(action);
2223         }
2224 
2225         /**
2226          * Convenience log function to log what changed.  Logs only when more debug logs
2227          * are needed - DBG needs to be true
2228          */
logEventChange(Intent intent)2229         private void logEventChange(Intent intent) {
2230             if (intent == null) {
2231                 return;
2232             }
2233             if (DBG) {
2234                 String packageName = intent.getData().getSchemeSpecificPart();
2235                 Slogf.d(TAG, "Pkg Changed:" + packageName);
2236                 String action = intent.getAction();
2237                 if (action == null) {
2238                     return;
2239                 }
2240                 if (action.equals(Intent.ACTION_PACKAGE_CHANGED)) {
2241                     Slogf.d(TAG, "Changed components");
2242                     String[] cc = intent
2243                             .getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
2244                     if (cc != null) {
2245                         for (String c : cc) {
2246                             Slogf.d(TAG, c);
2247                         }
2248                     }
2249                 } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
2250                         || action.equals(Intent.ACTION_PACKAGE_ADDED)) {
2251                     Slogf.d(TAG, action + " Replacing?: "
2252                             + intent.getBooleanExtra(Intent.EXTRA_REPLACING, false));
2253                 }
2254             }
2255         }
2256     }
2257 }
2258