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 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.UserIdInt;
24 import android.app.ActivityManager;
25 import android.app.ActivityTaskManager.RootTaskInfo;
26 import android.app.PendingIntent;
27 import android.car.Car;
28 import android.car.content.pm.AppBlockingPackageInfo;
29 import android.car.content.pm.CarAppBlockingPolicy;
30 import android.car.content.pm.CarAppBlockingPolicyService;
31 import android.car.content.pm.CarPackageManager;
32 import android.car.content.pm.ICarPackageManager;
33 import android.car.drivingstate.CarUxRestrictions;
34 import android.car.drivingstate.ICarUxRestrictionsChangeListener;
35 import android.car.hardware.power.CarPowerPolicy;
36 import android.car.hardware.power.CarPowerPolicyFilter;
37 import android.car.hardware.power.ICarPowerPolicyListener;
38 import android.car.hardware.power.PowerComponent;
39 import android.car.user.CarUserManager;
40 import android.content.BroadcastReceiver;
41 import android.content.ComponentName;
42 import android.content.Context;
43 import android.content.Intent;
44 import android.content.IntentFilter;
45 import android.content.pm.ActivityInfo;
46 import android.content.pm.PackageInfo;
47 import android.content.pm.PackageManager;
48 import android.content.pm.PackageManager.NameNotFoundException;
49 import android.content.pm.ResolveInfo;
50 import android.content.pm.ServiceInfo;
51 import android.content.pm.Signature;
52 import android.content.res.Resources;
53 import android.hardware.display.DisplayManager;
54 import android.os.Binder;
55 import android.os.Build;
56 import android.os.Handler;
57 import android.os.HandlerThread;
58 import android.os.IBinder;
59 import android.os.Looper;
60 import android.os.Message;
61 import android.os.ParcelFileDescriptor;
62 import android.os.Process;
63 import android.os.RemoteException;
64 import android.os.ServiceManager;
65 import android.os.ServiceSpecificException;
66 import android.os.SystemProperties;
67 import android.os.UserHandle;
68 import android.text.TextUtils;
69 import android.util.ArraySet;
70 import android.util.IndentingPrintWriter;
71 import android.util.LocalLog;
72 import android.util.Log;
73 import android.util.Pair;
74 import android.util.Slog;
75 import android.util.SparseArray;
76 import android.view.Display;
77 import android.view.DisplayAddress;
78 
79 import com.android.car.CarLocalServices;
80 import com.android.car.CarLog;
81 import com.android.car.CarServiceBase;
82 import com.android.car.CarServiceUtils;
83 import com.android.car.CarUxRestrictionsManagerService;
84 import com.android.car.R;
85 import com.android.car.SystemActivityMonitoringService;
86 import com.android.car.SystemActivityMonitoringService.TopTaskInfoContainer;
87 import com.android.car.power.CarPowerManagementService;
88 import com.android.car.user.CarUserService;
89 import com.android.internal.annotations.GuardedBy;
90 import com.android.internal.annotations.VisibleForTesting;
91 import com.android.server.utils.Slogf;
92 
93 import com.google.android.collect.Sets;
94 
95 import java.io.BufferedReader;
96 import java.io.FileReader;
97 import java.io.IOException;
98 import java.lang.ref.WeakReference;
99 import java.util.ArrayList;
100 import java.util.Arrays;
101 import java.util.HashMap;
102 import java.util.HashSet;
103 import java.util.LinkedList;
104 import java.util.List;
105 import java.util.Map;
106 import java.util.Map.Entry;
107 import java.util.Objects;
108 import java.util.Set;
109 
110 public class CarPackageManagerService extends ICarPackageManager.Stub implements CarServiceBase {
111 
112     static final boolean DBG = false;
113 
114     private static final String TAG = CarLog.tagFor(CarPackageManagerService.class);
115 
116     // Delimiters to parse packages and activities in the configuration XML resource.
117     private static final String PACKAGE_DELIMITER = ",";
118     private static final String PACKAGE_ACTIVITY_DELIMITER = "/";
119     private static final int LOG_SIZE = 20;
120     private static final String[] WINDOW_DUMP_ARGUMENTS = new String[]{"windows"};
121 
122     private static final String PROPERTY_RO_DRIVING_SAFETY_REGION =
123             "ro.android.car.drivingsafetyregion";
124 
125     private final Context mContext;
126     private final SystemActivityMonitoringService mSystemActivityMonitoringService;
127     private final PackageManager mPackageManager;
128     private final ActivityManager mActivityManager;
129     private final DisplayManager mDisplayManager;
130     private final IBinder mWindowManagerBinder;
131 
132     private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
133             getClass().getSimpleName());
134     private final PackageHandler mHandler  = new PackageHandler(mHandlerThread.getLooper(), this);
135     private final Object mLock = new Object();
136 
137     // For dumpsys logging.
138     private final LocalLog mBlockedActivityLogs = new LocalLog(LOG_SIZE);
139 
140     // Store the allowlist and blocklist strings from the resource file.
141     private String mConfiguredAllowlist;
142     private String mConfiguredSystemAllowlist;
143     private String mConfiguredBlocklist;
144     @GuardedBy("mLock")
145     private Map<String, Set<String>> mConfiguredAllowlistMap;
146     @GuardedBy("mLock")
147     private Map<String, Set<String>> mConfiguredBlocklistMap;
148 
149     private final List<String> mAllowedAppInstallSources;
150 
151     @GuardedBy("mLock")
152     private final SparseArray<ComponentName> mTopActivityWithDialogPerDisplay = new SparseArray<>();
153 
154     /**
155      * Hold policy set from policy service or client.
156      * Key: packageName of policy service
157      */
158     @GuardedBy("mLock")
159     private final HashMap<String, ClientPolicy> mClientPolicies = new HashMap<>();
160     @GuardedBy("mLock")
161     private HashMap<String, AppBlockingPackageInfoWrapper> mActivityAllowlistMap = new HashMap<>();
162     @GuardedBy("mLock")
163     private  HashSet<String> mActivityDenylistPackages = new HashSet<String>();
164 
165     @GuardedBy("mLock")
166     private LinkedList<AppBlockingPolicyProxy> mProxies;
167 
168     @GuardedBy("mLock")
169     private final LinkedList<CarAppBlockingPolicy> mWaitingPolicies = new LinkedList<>();
170 
171     @GuardedBy("mLock")
172     private String mCurrentDrivingSafetyRegion = CarPackageManager.DRIVING_SAFETY_REGION_ALL;
173     // Package name + '/' + className format
174     @GuardedBy("mLock")
175     private final ArraySet<String> mTempAllowedActivities = new ArraySet<>();
176 
177     private final CarUxRestrictionsManagerService mCarUxRestrictionsService;
178     private final boolean mEnableActivityBlocking;
179 
180     private final ComponentName mActivityBlockingActivity;
181     private final boolean mPreventTemplatedAppsFromShowingDialog;
182     private final String mTemplateActivityClassName;
183 
184     private final ActivityLaunchListener mActivityLaunchListener = new ActivityLaunchListener();
185 
186     // K: (logical) display id of a physical display, V: UXR change listener of this display.
187     // For multi-display, monitor UXR change on each display.
188     private final SparseArray<UxRestrictionsListener> mUxRestrictionsListeners =
189             new SparseArray<>();
190     private final VendorServiceController mVendorServiceController;
191 
192     // Information related to when the installed packages should be parsed for building a allow and
193     // block list
194     private final Set<String> mPackageManagerActions = Sets.newArraySet(
195             Intent.ACTION_PACKAGE_ADDED,
196             Intent.ACTION_PACKAGE_CHANGED,
197             Intent.ACTION_PACKAGE_REMOVED,
198             Intent.ACTION_PACKAGE_REPLACED);
199 
200     private final PackageParsingEventReceiver mPackageParsingEventReceiver =
201             new PackageParsingEventReceiver();
202 
203     /**
204      * Name of blocked activity.
205      *
206      * @hide
207      */
208     public static final String BLOCKING_INTENT_EXTRA_BLOCKED_ACTIVITY_NAME = "blocked_activity";
209     /**
210      * int task id of the blocked task.
211      *
212      * @hide
213      */
214     public static final String BLOCKING_INTENT_EXTRA_BLOCKED_TASK_ID = "blocked_task_id";
215     /**
216      * Name of root activity of blocked task.
217      *
218      * @hide
219      */
220     public static final String BLOCKING_INTENT_EXTRA_ROOT_ACTIVITY_NAME = "root_activity_name";
221     /**
222      * Boolean indicating whether the root activity is distraction-optimized (DO).
223      * Blocking screen should show a button to restart the task if {@code true}.
224      *
225      * @hide
226      */
227     public static final String BLOCKING_INTENT_EXTRA_IS_ROOT_ACTIVITY_DO = "is_root_activity_do";
228 
229     /**
230      * int display id of the blocked task.
231      *
232      * @hide
233      */
234     public static final String BLOCKING_INTENT_EXTRA_DISPLAY_ID = "display_id";
235 
236     private final CarUserManager.UserLifecycleListener mUserLifecycleListener =
237             new CarUserManager.UserLifecycleListener() {
238                 @Override
239                 public void onEvent(CarUserManager.UserLifecycleEvent event) {
240                     if (event.getEventType()
241                             == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
242                         synchronized (mLock) {
243                             resetTempAllowedActivitiesLocked();
244                         }
245                     }
246                 }
247             };
248 
249     private final ICarPowerPolicyListener mDisplayPowerPolicyListener =
250             new ICarPowerPolicyListener.Stub() {
251                 @Override
252                 public void onPolicyChanged(CarPowerPolicy policy,
253                         CarPowerPolicy accumulatedPolicy) {
254                     if (!policy.isComponentEnabled(PowerComponent.DISPLAY)) {
255                         synchronized (mLock) {
256                             resetTempAllowedActivitiesLocked();
257                         }
258                     }
259                 }
260             };
261 
CarPackageManagerService(Context context, CarUxRestrictionsManagerService uxRestrictionsService, SystemActivityMonitoringService systemActivityMonitoringService)262     public CarPackageManagerService(Context context,
263             CarUxRestrictionsManagerService uxRestrictionsService,
264             SystemActivityMonitoringService systemActivityMonitoringService) {
265         mContext = context;
266         mCarUxRestrictionsService = uxRestrictionsService;
267         mSystemActivityMonitoringService = systemActivityMonitoringService;
268         mPackageManager = mContext.getPackageManager();
269         mActivityManager = mContext.getSystemService(ActivityManager.class);
270         mDisplayManager = mContext.getSystemService(DisplayManager.class);
271         mWindowManagerBinder = ServiceManager.getService(Context.WINDOW_SERVICE);
272         Resources res = context.getResources();
273         mEnableActivityBlocking = res.getBoolean(R.bool.enableActivityBlockingForSafety);
274         String blockingActivity = res.getString(R.string.activityBlockingActivity);
275         mActivityBlockingActivity = ComponentName.unflattenFromString(blockingActivity);
276         if (mEnableActivityBlocking && mActivityBlockingActivity == null) {
277             Slogf.wtf(TAG, "mActivityBlockingActivity can't be null when enabled");
278         }
279         mAllowedAppInstallSources = Arrays.asList(
280                 res.getStringArray(R.array.allowedAppInstallSources));
281         mVendorServiceController = new VendorServiceController(
282                 mContext, mHandler.getLooper());
283         mPreventTemplatedAppsFromShowingDialog =
284                 res.getBoolean(R.bool.config_preventTemplatedAppsFromShowingDialog);
285         mTemplateActivityClassName = res.getString(R.string.config_template_activity_class_name);
286     }
287 
288 
289     @Override
setAppBlockingPolicy(String packageName, CarAppBlockingPolicy policy, int flags)290     public void setAppBlockingPolicy(String packageName, CarAppBlockingPolicy policy, int flags) {
291         if (Log.isLoggable(TAG, Log.DEBUG)) {
292             Slog.d(TAG, "policy setting from binder call, client:" + packageName);
293         }
294         doSetAppBlockingPolicy(packageName, policy, flags);
295     }
296 
297     /**
298      * Restarts the requested task. If task with {@code taskId} does not exist, do nothing.
299      */
300     @Override
restartTask(int taskId)301     public void restartTask(int taskId) {
302         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.REAL_GET_TASKS)
303                 != PackageManager.PERMISSION_GRANTED) {
304             throw new SecurityException(
305                     "requires permission " + android.Manifest.permission.REAL_GET_TASKS);
306         }
307         mSystemActivityMonitoringService.restartTask(taskId);
308     }
309 
310     @Override
getCurrentDrivingSafetyRegion()311     public String getCurrentDrivingSafetyRegion() {
312         assertAppBlockingOrDrivingStatePermission();
313         synchronized (mLock) {
314             return mCurrentDrivingSafetyRegion;
315         }
316     }
317 
getComponentNameString(String packageName, String className)318     private String getComponentNameString(String packageName, String className) {
319         return packageName + '/' + className;
320     }
321 
322     @Override
controlOneTimeActivityBlockingBypassingAsUser(String packageName, String activityClassName, boolean bypass, @UserIdInt int userId)323     public void controlOneTimeActivityBlockingBypassingAsUser(String packageName,
324             String activityClassName, boolean bypass, @UserIdInt int userId) {
325         assertAppBlockingPermission();
326         if (!callerCanQueryPackage(packageName)) {
327             throw new SecurityException("cannot query other package");
328         }
329         try {
330             // Read this to check the validity of pkg / activity name. Not checking this can allow
331             // bad apps to be allowed later.
332             CarAppMetadataReader.getSupportedDrivingSafetyRegionsForActivityAsUser(mContext,
333                     packageName, activityClassName, userId);
334         } catch (NameNotFoundException e) {
335             throw new ServiceSpecificException(CarPackageManager.ERROR_CODE_NO_PACKAGE,
336                     e.getMessage());
337         }
338         String componentName = getComponentNameString(packageName, activityClassName);
339         synchronized (mLock) {
340             if (bypass) {
341                 mTempAllowedActivities.add(componentName);
342             } else {
343                 mTempAllowedActivities.remove(componentName);
344             }
345         }
346         if (!bypass) { // block top activities if bypassing is disabled.
347             blockTopActivitiesIfNecessary();
348         }
349     }
350 
351     @GuardedBy("mLock")
resetTempAllowedActivitiesLocked()352     private void resetTempAllowedActivitiesLocked() {
353         mTempAllowedActivities.clear();
354     }
355 
356     @Override
getSupportedDrivingSafetyRegionsForActivityAsUser(String packageName, String activityClassName, @UserIdInt int userId)357     public List<String> getSupportedDrivingSafetyRegionsForActivityAsUser(String packageName,
358             String activityClassName, @UserIdInt int userId) {
359         assertAppBlockingOrDrivingStatePermission();
360         if (!callerCanQueryPackage(packageName)) {
361             throw new SecurityException("cannot query other package");
362         }
363         long token = Binder.clearCallingIdentity();
364         try {
365             return CarAppMetadataReader.getSupportedDrivingSafetyRegionsForActivityAsUser(mContext,
366                     packageName, activityClassName, userId);
367         } catch (NameNotFoundException e) {
368             throw new ServiceSpecificException(CarPackageManager.ERROR_CODE_NO_PACKAGE,
369                     e.getMessage());
370         } finally {
371             Binder.restoreCallingIdentity(token);
372         }
373     }
374 
assertAppBlockingOrDrivingStatePermission()375     private void assertAppBlockingOrDrivingStatePermission() {
376         if (mContext.checkCallingOrSelfPermission(Car.PERMISSION_CONTROL_APP_BLOCKING)
377                 != PackageManager.PERMISSION_GRANTED && mContext.checkCallingOrSelfPermission(
378                 Car.PERMISSION_CAR_DRIVING_STATE) != PackageManager.PERMISSION_GRANTED) {
379             throw new SecurityException(
380                     "requires permission " + Car.PERMISSION_CONTROL_APP_BLOCKING + " or "
381                             + Car.PERMISSION_CAR_DRIVING_STATE);
382         }
383     }
384 
assertAppBlockingPermission()385     private void assertAppBlockingPermission() {
386         if (mContext.checkCallingOrSelfPermission(Car.PERMISSION_CONTROL_APP_BLOCKING)
387                 != PackageManager.PERMISSION_GRANTED) {
388             throw new SecurityException(
389                     "requires permission " + Car.PERMISSION_CONTROL_APP_BLOCKING);
390         }
391     }
392 
doSetAppBlockingPolicy(String packageName, CarAppBlockingPolicy policy, int flags)393     private void doSetAppBlockingPolicy(String packageName, CarAppBlockingPolicy policy,
394             int flags) {
395         assertAppBlockingPermission();
396         CarServiceUtils.assertPackageName(mContext, packageName);
397         if (policy == null) {
398             throw new IllegalArgumentException("policy cannot be null");
399         }
400         if ((flags & CarPackageManager.FLAG_SET_POLICY_ADD) != 0 &&
401                 (flags & CarPackageManager.FLAG_SET_POLICY_REMOVE) != 0) {
402             throw new IllegalArgumentException(
403                     "Cannot set both FLAG_SET_POLICY_ADD and FLAG_SET_POLICY_REMOVE flag");
404         }
405         synchronized (mLock) {
406             if ((flags & CarPackageManager.FLAG_SET_POLICY_WAIT_FOR_CHANGE) != 0) {
407                 mWaitingPolicies.add(policy);
408             }
409         }
410         mHandler.requestUpdatingPolicy(packageName, policy, flags);
411         if ((flags & CarPackageManager.FLAG_SET_POLICY_WAIT_FOR_CHANGE) != 0) {
412             synchronized (mLock) {
413                 try {
414                     while (mWaitingPolicies.contains(policy)) {
415                         mLock.wait();
416                     }
417                 } catch (InterruptedException e) {
418                     // Pass it over binder call
419                     throw new IllegalStateException(
420                             "Interrupted while waiting for policy completion", e);
421                 }
422             }
423         }
424     }
425 
426     @Override
isActivityDistractionOptimized(String packageName, String className)427     public boolean isActivityDistractionOptimized(String packageName, String className) {
428         if (!callerCanQueryPackage(packageName)) return false;
429         assertPackageAndClassName(packageName, className);
430         synchronized (mLock) {
431             if (Log.isLoggable(TAG, Log.DEBUG)) {
432                 Slog.d(TAG, "isActivityDistractionOptimized" + dumpPoliciesLocked(false));
433             }
434 
435             if (mTempAllowedActivities.contains(getComponentNameString(packageName,
436                     className))) {
437                 return true;
438             }
439 
440             for (int i = mTopActivityWithDialogPerDisplay.size() - 1; i >= 0; i--) {
441                 ComponentName activityWithDialog = mTopActivityWithDialogPerDisplay.get(
442                         mTopActivityWithDialogPerDisplay.keyAt(i));
443                 if (activityWithDialog.getClassName().equals(className)
444                         && activityWithDialog.getPackageName().equals(packageName)) {
445                     return false;
446                 }
447             }
448 
449             if (searchFromClientPolicyBlocklistsLocked(packageName)) {
450                 return false;
451             }
452 
453             if (isActivityInClientPolicyAllowlistsLocked(packageName, className)) {
454                 return true;
455             }
456 
457             // Check deny and allow list
458             boolean packageBlocked = mActivityDenylistPackages.contains(packageName);
459             AppBlockingPackageInfoWrapper infoWrapper = mActivityAllowlistMap.get(packageName);
460             if (!packageBlocked && infoWrapper == null) {
461                 // Update cache
462                 updateActivityAllowlistAndDenylistMap(packageName);
463                 packageBlocked = mActivityDenylistPackages.contains(packageName);
464                 infoWrapper = mActivityAllowlistMap.get(packageName);
465             }
466 
467             if (packageBlocked
468                     || !isActivityInMapAndMatching(infoWrapper, packageName, className)) {
469                 return false;
470             }
471 
472             return true;
473         }
474     }
475 
476     @VisibleForTesting
callerCanQueryPackage(String packageName)477     boolean callerCanQueryPackage(String packageName) {
478         int callingUid = Binder.getCallingUid();
479         if (hasPermissionGranted(QUERY_ALL_PACKAGES, callingUid)) {
480             return true;
481         }
482         String[] packages = mPackageManager.getPackagesForUid(callingUid);
483         if (packages != null && packages.length > 0) {
484             for (int i = 0; i < packages.length; i++) {
485                 if (Objects.equals(packageName, packages[i])) {
486                     return true;
487                 }
488             }
489         }
490 
491         Slog.w(TAG, QUERY_ALL_PACKAGES + " permission is needed to query other packages.");
492 
493         return false;
494     }
495 
hasPermissionGranted(String permission, int uid)496     private static boolean hasPermissionGranted(String permission, int uid) {
497         return ActivityManager.checkComponentPermission(permission, uid,
498                 /* owningUid= */ Process.INVALID_UID,
499                 /* exported= */ true) == PackageManager.PERMISSION_GRANTED;
500     }
501 
502     @Override
isPendingIntentDistractionOptimized(PendingIntent pendingIntent)503     public boolean isPendingIntentDistractionOptimized(PendingIntent pendingIntent) {
504         ResolveInfo info = mPackageManager.resolveActivity(
505                 pendingIntent.getIntent(), PackageManager.MATCH_DEFAULT_ONLY);
506         if (info == null) return false;
507         ActivityInfo activityInfo = info.activityInfo;
508         return isActivityDistractionOptimized(activityInfo.packageName, activityInfo.name);
509     }
510 
511     @Override
isServiceDistractionOptimized(String packageName, String className)512     public boolean isServiceDistractionOptimized(String packageName, String className) {
513         if (!callerCanQueryPackage(packageName)) return false;
514 
515         if (packageName == null) {
516             throw new IllegalArgumentException("Package name null");
517         }
518         synchronized (mLock) {
519             if (Log.isLoggable(TAG, Log.DEBUG)) {
520                 Slog.d(TAG, "isServiceDistractionOptimized" + dumpPoliciesLocked(false));
521             }
522 
523             if (searchFromClientPolicyBlocklistsLocked(packageName)) {
524                 return false;
525             }
526 
527             if (searchFromClientPolicyAllowlistsLocked(packageName)) {
528                 return true;
529             }
530 
531             // Check deny and allow list
532             boolean packageBlocked = mActivityDenylistPackages.contains(packageName);
533             AppBlockingPackageInfoWrapper infoWrapper = mActivityAllowlistMap.get(packageName);
534             if (!packageBlocked && infoWrapper == null) {
535                 // Update cache
536                 updateActivityAllowlistAndDenylistMap(packageName);
537                 packageBlocked = mActivityDenylistPackages.contains(packageName);
538                 infoWrapper = mActivityAllowlistMap.get(packageName);
539             }
540 
541             if (packageBlocked || infoWrapper == null || infoWrapper.info == null) {
542                 return false;
543             }
544 
545             return true;
546         }
547     }
548 
549     @Override
isActivityBackedBySafeActivity(ComponentName activityName)550     public boolean isActivityBackedBySafeActivity(ComponentName activityName) {
551         if (activityName == null) return false;
552         if (!callerCanQueryPackage(activityName.getPackageName())) return false;
553 
554         RootTaskInfo info = mSystemActivityMonitoringService.getFocusedStackForTopActivity(
555                 activityName);
556         if (info == null) { // not top in focused stack
557             return true;
558         }
559         if (!isUxRestrictedOnDisplay(info.displayId)) {
560             return true;
561         }
562         if (info.childTaskNames.length <= 1) { // nothing below this.
563             return false;
564         }
565         ComponentName activityBehind = ComponentName.unflattenFromString(
566                 info.childTaskNames[info.childTaskNames.length - 2]);
567         return isActivityDistractionOptimized(activityBehind.getPackageName(),
568                 activityBehind.getClassName());
569     }
570 
getLooper()571     public Looper getLooper() {
572         return mHandlerThread.getLooper();
573     }
574 
assertPackageAndClassName(String packageName, String className)575     private void assertPackageAndClassName(String packageName, String className) {
576         if (packageName == null) {
577             throw new IllegalArgumentException("Package name null");
578         }
579         if (className == null) {
580             throw new IllegalArgumentException("Class name null");
581         }
582     }
583 
584     @GuardedBy("mLock")
searchFromClientPolicyBlocklistsLocked(String packageName)585     private boolean searchFromClientPolicyBlocklistsLocked(String packageName) {
586         for (ClientPolicy policy : mClientPolicies.values()) {
587             AppBlockingPackageInfoWrapper wrapper = policy.mBlocklistsMap.get(packageName);
588             if (wrapper != null && wrapper.isMatching && wrapper.info != null) {
589                 return true;
590             }
591         }
592 
593         return false;
594     }
595 
596     @GuardedBy("mLock")
searchFromClientPolicyAllowlistsLocked(String packageName)597     private boolean searchFromClientPolicyAllowlistsLocked(String packageName) {
598         for (ClientPolicy policy : mClientPolicies.values()) {
599             AppBlockingPackageInfoWrapper wrapper = policy.mAllowlistsMap.get(packageName);
600             if (wrapper != null && wrapper.isMatching && wrapper.info != null) {
601                 return true;
602             }
603         }
604         return false;
605     }
606 
607     @GuardedBy("mLock")
isActivityInClientPolicyAllowlistsLocked(String packageName, String className)608     private boolean isActivityInClientPolicyAllowlistsLocked(String packageName, String className) {
609         for (ClientPolicy policy : mClientPolicies.values()) {
610             if (isActivityInMapAndMatching(policy.mAllowlistsMap.get(packageName), packageName,
611                     className)) {
612                 return true;
613             }
614         }
615         return false;
616     }
617 
isActivityInMapAndMatching(AppBlockingPackageInfoWrapper wrapper, String packageName, String className)618     private boolean isActivityInMapAndMatching(AppBlockingPackageInfoWrapper wrapper,
619             String packageName, String className) {
620         if (wrapper == null || !wrapper.isMatching) {
621             if (Log.isLoggable(TAG, Log.DEBUG)) {
622                 Slog.d(TAG, "Pkg not in allowlist:" + packageName);
623             }
624             return false;
625         }
626         return wrapper.info.isActivityCovered(className);
627     }
628 
629     @Override
init()630     public void init() {
631         String safetyRegion = SystemProperties.get(PROPERTY_RO_DRIVING_SAFETY_REGION, "");
632         synchronized (mLock) {
633             setDrivingSafetyRegionWithCheckLocked(safetyRegion);
634             mHandler.requestInit();
635         }
636         CarLocalServices.getService(CarUserService.class).addUserLifecycleListener(
637                 mUserLifecycleListener);
638         CarLocalServices.getService(CarPowerManagementService.class).addPowerPolicyListener(
639                 new CarPowerPolicyFilter.Builder().setComponents(PowerComponent.DISPLAY).build(),
640                 mDisplayPowerPolicyListener);
641     }
642 
643     @Override
release()644     public void release() {
645         CarLocalServices.getService(CarPowerManagementService.class).removePowerPolicyListener(
646                 mDisplayPowerPolicyListener);
647         CarLocalServices.getService(CarUserService.class).removeUserLifecycleListener(
648                 mUserLifecycleListener);
649         synchronized (mLock) {
650             mHandler.requestRelease();
651             // wait for release do be done. This guarantees that init is done.
652             try {
653                 mLock.wait();
654             } catch (InterruptedException e) {
655                 Slog.e(TAG, "Interrupted wait during release");
656                 Thread.currentThread().interrupt();
657             }
658             mActivityAllowlistMap.clear();
659             mActivityDenylistPackages.clear();
660             mClientPolicies.clear();
661             if (mProxies != null) {
662                 for (AppBlockingPolicyProxy proxy : mProxies) {
663                     proxy.disconnect();
664                 }
665                 mProxies.clear();
666             }
667             mWaitingPolicies.clear();
668             resetTempAllowedActivitiesLocked();
669             mLock.notifyAll();
670         }
671         mContext.unregisterReceiver(mPackageParsingEventReceiver);
672         mSystemActivityMonitoringService.registerActivityLaunchListener(null);
673         for (int i = 0; i < mUxRestrictionsListeners.size(); i++) {
674             UxRestrictionsListener listener = mUxRestrictionsListeners.valueAt(i);
675             mCarUxRestrictionsService.unregisterUxRestrictionsChangeListener(listener);
676         }
677     }
678 
679     @GuardedBy("mLock")
setDrivingSafetyRegionWithCheckLocked(String region)680     private void setDrivingSafetyRegionWithCheckLocked(String region) {
681         if (region.isEmpty()) {
682             mCurrentDrivingSafetyRegion = CarPackageManager.DRIVING_SAFETY_REGION_ALL;
683         } else {
684             mCurrentDrivingSafetyRegion = region;
685         }
686     }
687 
688     /**
689      * Reset driving stat and all dynamically added allow list so that region information for
690      * all packages are reset. This also resets one time allow list.
691      */
resetDrivingSafetyRegion(@onNull String region)692     public void resetDrivingSafetyRegion(@NonNull String region) {
693         synchronized (mLock) {
694             setDrivingSafetyRegionWithCheckLocked(region);
695             resetTempAllowedActivitiesLocked();
696             mActivityAllowlistMap.clear();
697             mActivityDenylistPackages.clear();
698         }
699     }
700 
701     // run from HandlerThread
doHandleInit()702     private void doHandleInit() {
703         startAppBlockingPolicies();
704         IntentFilter pkgParseIntent = new IntentFilter();
705         for (String action : mPackageManagerActions) {
706             pkgParseIntent.addAction(action);
707         }
708         pkgParseIntent.addDataScheme("package");
709         mContext.registerReceiverAsUser(mPackageParsingEventReceiver, UserHandle.ALL,
710                 pkgParseIntent, null, null);
711 
712         List<Display> physicalDisplays = getPhysicalDisplays();
713 
714         // Assume default display (display 0) is always a physical display.
715         Display defaultDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
716         if (!physicalDisplays.contains(defaultDisplay)) {
717             if (Log.isLoggable(TAG, Log.INFO)) {
718                 Slog.i(TAG, "Adding default display to physical displays.");
719             }
720             physicalDisplays.add(defaultDisplay);
721         }
722         for (Display physicalDisplay : physicalDisplays) {
723             int displayId = physicalDisplay.getDisplayId();
724             UxRestrictionsListener listener = new UxRestrictionsListener(mCarUxRestrictionsService);
725             mUxRestrictionsListeners.put(displayId, listener);
726             mCarUxRestrictionsService.registerUxRestrictionsChangeListener(listener, displayId);
727         }
728         mVendorServiceController.init();
729         mSystemActivityMonitoringService.registerActivityLaunchListener(mActivityLaunchListener);
730     }
731 
doParseInstalledPackage(String packageName)732     private void doParseInstalledPackage(String packageName) {
733         // Delete the package from allowlist and denylist mapping
734         synchronized (mLock) {
735             mActivityDenylistPackages.remove(packageName);
736             mActivityAllowlistMap.remove(packageName);
737         }
738 
739         // Generate allowlist and denylist mapping for the package
740         updateActivityAllowlistAndDenylistMap(packageName);
741         blockTopActivitiesIfNecessary();
742     }
743 
doHandleRelease()744     private void doHandleRelease() {
745         synchronized (mLock) {
746             mVendorServiceController.release();
747             mLock.notifyAll();
748         }
749     }
750 
doUpdatePolicy(String packageName, CarAppBlockingPolicy policy, int flags)751     private void doUpdatePolicy(String packageName, CarAppBlockingPolicy policy, int flags) {
752         if (Log.isLoggable(TAG, Log.DEBUG)) {
753             Slog.d(TAG, "setting policy from:" + packageName + ",policy:" + policy + ",flags:0x"
754                     + Integer.toHexString(flags));
755         }
756         AppBlockingPackageInfoWrapper[] blocklistWrapper = verifyList(policy.blacklists);
757         AppBlockingPackageInfoWrapper[] allowlistWrapper = verifyList(policy.whitelists);
758         synchronized (mLock) {
759             ClientPolicy clientPolicy = mClientPolicies.get(packageName);
760             if (clientPolicy == null) {
761                 clientPolicy = new ClientPolicy();
762                 mClientPolicies.put(packageName, clientPolicy);
763             }
764             if ((flags & CarPackageManager.FLAG_SET_POLICY_ADD) != 0) {
765                 clientPolicy.addToBlocklists(blocklistWrapper);
766                 clientPolicy.addToAllowlists(allowlistWrapper);
767             } else if ((flags & CarPackageManager.FLAG_SET_POLICY_REMOVE) != 0) {
768                 clientPolicy.removeBlocklists(blocklistWrapper);
769                 clientPolicy.removeAllowlists(allowlistWrapper);
770             } else { //replace.
771                 clientPolicy.replaceBlocklists(blocklistWrapper);
772                 clientPolicy.replaceAllowlists(allowlistWrapper);
773             }
774             if ((flags & CarPackageManager.FLAG_SET_POLICY_WAIT_FOR_CHANGE) != 0) {
775                 mWaitingPolicies.remove(policy);
776                 mLock.notifyAll();
777             }
778             if (Log.isLoggable(TAG, Log.DEBUG)) {
779                 Slog.d(TAG, "policy set:" + dumpPoliciesLocked(false));
780             }
781         }
782         blockTopActivitiesIfNecessary();
783     }
784 
verifyList(AppBlockingPackageInfo[] list)785     private AppBlockingPackageInfoWrapper[] verifyList(AppBlockingPackageInfo[] list) {
786         if (list == null) {
787             return null;
788         }
789         LinkedList<AppBlockingPackageInfoWrapper> wrappers = new LinkedList<>();
790         for (int i = 0; i < list.length; i++) {
791             AppBlockingPackageInfo info = list[i];
792             if (info == null) {
793                 continue;
794             }
795             boolean isMatching = isInstalledPackageMatching(info);
796             wrappers.add(new AppBlockingPackageInfoWrapper(info, isMatching));
797         }
798         return wrappers.toArray(new AppBlockingPackageInfoWrapper[wrappers.size()]);
799     }
800 
isInstalledPackageMatching(AppBlockingPackageInfo info)801     boolean isInstalledPackageMatching(AppBlockingPackageInfo info) {
802         PackageInfo packageInfo;
803         try {
804             packageInfo = mPackageManager.getPackageInfo(info.packageName,
805                     PackageManager.GET_SIGNATURES);
806         } catch (NameNotFoundException e) {
807             return false;
808         }
809         if (packageInfo == null) {
810             return false;
811         }
812         // if it is system app and client specified the flag, do not check signature
813         if ((info.flags & AppBlockingPackageInfo.FLAG_SYSTEM_APP) == 0 ||
814                 (!packageInfo.applicationInfo.isSystemApp() &&
815                         !packageInfo.applicationInfo.isUpdatedSystemApp())) {
816             Signature[] signatures = packageInfo.signatures;
817             if (!isAnySignatureMatching(signatures, info.signatures)) {
818                 return false;
819             }
820         }
821         int version = packageInfo.versionCode;
822         if (info.minRevisionCode == 0) {
823             if (info.maxRevisionCode == 0) { // all versions
824                 return true;
825             } else { // only max version matters
826                 return info.maxRevisionCode > version;
827             }
828         } else { // min version matters
829             if (info.maxRevisionCode == 0) {
830                 return info.minRevisionCode < version;
831             } else {
832                 return (info.minRevisionCode < version) && (info.maxRevisionCode > version);
833             }
834         }
835     }
836 
837     /**
838      * Any signature from policy matching with package's signatures is treated as matching.
839      */
isAnySignatureMatching(Signature[] fromPackage, Signature[] fromPolicy)840     boolean isAnySignatureMatching(Signature[] fromPackage, Signature[] fromPolicy) {
841         if (fromPackage == null) {
842             return false;
843         }
844         if (fromPolicy == null) {
845             return false;
846         }
847         ArraySet<Signature> setFromPackage = new ArraySet<Signature>();
848         for (Signature sig : fromPackage) {
849             setFromPackage.add(sig);
850         }
851         for (Signature sig : fromPolicy) {
852             if (setFromPackage.contains(sig)) {
853                 return true;
854             }
855         }
856         return false;
857     }
858 
getPackageInfoWrapperForUser(String packageName, @UserIdInt int userId, Map<String, Set<String>> configAllowlist, Map<String, Set<String>> configBlocklist)859     private AppBlockingPackageInfoWrapper getPackageInfoWrapperForUser(String packageName,
860             @UserIdInt int userId, Map<String, Set<String>> configAllowlist,
861             Map<String, Set<String>> configBlocklist) {
862         PackageInfo info;
863         try {
864             info = mPackageManager.getPackageInfoAsUser(packageName,
865                     PackageManager.GET_SIGNATURES | PackageManager.GET_ACTIVITIES
866                             | PackageManager.MATCH_DIRECT_BOOT_AWARE
867                             | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
868                             | PackageManager.MATCH_DISABLED_COMPONENTS,
869                     userId);
870         } catch (NameNotFoundException e) {
871             Slog.w(TAG, packageName + " not installed! User Id: " + userId);
872             return null;
873         }
874 
875 
876         if (info == null || info.applicationInfo == null) {
877             return null;
878         }
879 
880         int flags = 0;
881         Set<String> activities = new ArraySet<>();
882 
883         if (info.applicationInfo.isSystemApp()
884                 || info.applicationInfo.isUpdatedSystemApp()) {
885             flags = AppBlockingPackageInfo.FLAG_SYSTEM_APP;
886         }
887 
888         /* 1. Check if all or some of this app is in the <activityAllowlist> or
889               <systemActivityAllowlist> in config.xml */
890         Set<String> configActivitiesForPackage = configAllowlist.get(info.packageName);
891         if (configActivitiesForPackage != null) {
892             if (Log.isLoggable(TAG, Log.DEBUG)) {
893                 Slog.d(TAG, info.packageName + " allowlisted");
894             }
895 
896             if (configActivitiesForPackage.isEmpty()) {
897                 // Whole Pkg has been allowlisted
898                 flags |= AppBlockingPackageInfo.FLAG_WHOLE_ACTIVITY;
899                 // Add all activities to the allowlist
900                 List<String> activitiesForPackage = getActivitiesInPackage(info);
901                 if (activitiesForPackage != null) {
902                     activities.addAll(activitiesForPackage);
903                 } else {
904                     if (Log.isLoggable(TAG, Log.DEBUG)) {
905                         Slog.d(TAG, info.packageName + ": Activities null");
906                     }
907                 }
908             } else {
909                 if (Log.isLoggable(TAG, Log.DEBUG)) {
910                     Slog.d(TAG, "Partially Allowlisted. WL Activities: "
911                             + configActivitiesForPackage);
912                 }
913                 activities.addAll(configActivitiesForPackage);
914             }
915         }
916         /* 2. If app is not listed in the config.xml check their Manifest meta-data to
917           see if they have any Distraction Optimized(DO) activities.
918           For non system apps, we check if the app install source was a permittable
919           source. This prevents side-loaded apps to fake DO.  Bypass the check
920           for debug builds for development convenience. */
921         if (!isDebugBuild()
922                 && !info.applicationInfo.isSystemApp()
923                 && !info.applicationInfo.isUpdatedSystemApp()) {
924             try {
925                 if (mAllowedAppInstallSources != null) {
926                     String installerName = mPackageManager.getInstallerPackageName(
927                             info.packageName);
928                     if (installerName == null || (installerName != null
929                             && !mAllowedAppInstallSources.contains(installerName))) {
930                         Slog.w(TAG,
931                                 info.packageName + " not installed from permitted sources "
932                                         + (installerName == null ? "NULL" : installerName));
933                         return null;
934                     }
935                 }
936             } catch (IllegalArgumentException e) {
937                 Slog.w(TAG, info.packageName + " not installed!");
938                 return null;
939             }
940         }
941 
942         try {
943             String[] doActivities = findDistractionOptimizedActivitiesAsUser(info.packageName,
944                     userId);
945             if (doActivities != null) {
946                 // Some of the activities in this app are Distraction Optimized.
947                 if (Log.isLoggable(TAG, Log.DEBUG)) {
948                     for (String activity : doActivities) {
949                         Slog.d(TAG, "adding " + activity + " from " + info.packageName
950                                 + " to allowlist");
951                     }
952                 }
953 
954                 activities.addAll(Arrays.asList(doActivities));
955             }
956         } catch (NameNotFoundException e) {
957             Slog.w(TAG, "Error reading metadata: " + info.packageName);
958             return null;
959         }
960 
961         // Nothing to add to allowlist
962         if (activities.isEmpty()) {
963             return null;
964         }
965 
966         /* 3. Check if parsed activity is in <activityBlocklist> in config.xml. Anything
967               in blocklist should not be allowlisted, either as D.O. or by config. */
968         if (configBlocklist.containsKey(info.packageName)) {
969             Set<String> configBlocklistActivities = configBlocklist.get(info.packageName);
970             if (configBlocklistActivities.isEmpty()) {
971                 // Whole package should be blocklisted.
972                 return null;
973             }
974             activities.removeAll(configBlocklistActivities);
975         }
976 
977         Signature[] signatures;
978         signatures = info.signatures;
979         AppBlockingPackageInfo appBlockingInfo = new AppBlockingPackageInfo(info.packageName,
980                 /* minRevisionCode = */ 0, /* maxRevisionCode = */ 0, flags, signatures,
981                 activities.toArray(new String[activities.size()]));
982         AppBlockingPackageInfoWrapper wrapper = new AppBlockingPackageInfoWrapper(
983                 appBlockingInfo, true);
984         return wrapper;
985     }
986 
987     /**
988      * Update map of allowlisted packages and activities of the form {pkgName, Allowlisted
989      * activities} and set of denylisted packages. The information can come from a configuration XML
990      * resource or from the apps marking their activities as distraction optimized.
991      */
updateActivityAllowlistAndDenylistMap(String packageName)992     private void updateActivityAllowlistAndDenylistMap(String packageName) {
993         int userId = mActivityManager.getCurrentUser();
994         Slog.d(TAG, "Updating allowlist and denylist mapping for package: " + packageName
995                 + " for UserId: " + userId);
996         // Get the apps/activities that are allowlisted in the configuration XML resources.
997         Map<String, Set<String>> configAllowlist = generateConfigAllowlist();
998         Map<String, Set<String>> configBlocklist = generateConfigBlocklist();
999 
1000         AppBlockingPackageInfoWrapper wrapper =
1001                 getPackageInfoWrapperForUser(packageName, userId, configAllowlist, configBlocklist);
1002 
1003         if (wrapper == null && userId != UserHandle.USER_SYSTEM) {
1004             Slog.d(TAG, "Updating allowlist and denylist mapping for package: " + packageName
1005                     + " for UserId: " + UserHandle.USER_SYSTEM);
1006             // check package for system user, in case package is disabled for current user
1007             wrapper = getPackageInfoWrapperForUser(packageName, UserHandle.USER_SYSTEM,
1008                     configAllowlist, configBlocklist);
1009         }
1010 
1011         synchronized (mLock) {
1012             if (wrapper != null) {
1013                 if (DBG) {
1014                     Slog.d(TAG, "Package: " + packageName + " added in allowlist.");
1015                 }
1016                 mActivityAllowlistMap.put(packageName, wrapper);
1017             } else {
1018                 if (DBG) {
1019                     Slog.d(TAG, "Package: " + packageName + " added in denylist.");
1020                 }
1021                 mActivityDenylistPackages.add(packageName);
1022             }
1023         }
1024     }
1025 
generateConfigAllowlist()1026     private Map<String, Set<String>> generateConfigAllowlist() {
1027         synchronized (mLock) {
1028             if (mConfiguredAllowlistMap != null) return mConfiguredAllowlistMap;
1029 
1030             Map<String, Set<String>> configAllowlist = new HashMap<>();
1031             mConfiguredAllowlist = mContext.getString(R.string.activityAllowlist);
1032             if (mConfiguredAllowlist == null) {
1033                 Slog.w(TAG, "Allowlist is null.");
1034             }
1035             parseConfigList(mConfiguredAllowlist, configAllowlist);
1036 
1037             mConfiguredSystemAllowlist = mContext.getString(R.string.systemActivityAllowlist);
1038             if (mConfiguredSystemAllowlist == null) {
1039                 Slog.w(TAG, "System allowlist is null.");
1040             }
1041             parseConfigList(mConfiguredSystemAllowlist, configAllowlist);
1042 
1043             // Add the blocking overlay activity to the allowlist, since that needs to run in a
1044             // restricted state to communicate the reason an app was blocked.
1045             Set<String> defaultActivity = new ArraySet<>();
1046             if (mActivityBlockingActivity != null) {
1047                 defaultActivity.add(mActivityBlockingActivity.getClassName());
1048                 configAllowlist.put(mActivityBlockingActivity.getPackageName(), defaultActivity);
1049             }
1050 
1051             mConfiguredAllowlistMap = configAllowlist;
1052             return configAllowlist;
1053         }
1054     }
1055 
generateConfigBlocklist()1056     private Map<String, Set<String>> generateConfigBlocklist() {
1057         synchronized (mLock) {
1058             if (mConfiguredBlocklistMap != null) return mConfiguredBlocklistMap;
1059 
1060             Map<String, Set<String>> configBlocklist = new HashMap<>();
1061             mConfiguredBlocklist = mContext.getString(R.string.activityDenylist);
1062             if (mConfiguredBlocklist == null) {
1063                 if (Log.isLoggable(TAG, Log.DEBUG)) {
1064                     Slog.d(TAG, "Null blocklist in config");
1065                 }
1066             }
1067             parseConfigList(mConfiguredBlocklist, configBlocklist);
1068 
1069             mConfiguredBlocklistMap = configBlocklist;
1070             return configBlocklist;
1071         }
1072     }
1073 
isDebugBuild()1074     private boolean isDebugBuild() {
1075         return Build.IS_USERDEBUG || Build.IS_ENG;
1076     }
1077 
1078     /**
1079      * Parses the given resource and updates the input map of packages and activities.
1080      *
1081      * Key is package name and value is list of activities. Empty set implies whole package is
1082      * included.
1083      *
1084      * When there are multiple entries regarding one package, the entry with
1085      * greater scope wins. Namely if there were 2 entries such that one allowlists
1086      * an activity, and the other allowlists the entire package of the activity,
1087      * the package is allowlisted, regardless of input order.
1088      */
1089     @VisibleForTesting
parseConfigList(String configList, @NonNull Map<String, Set<String>> packageToActivityMap)1090     /* package */ void parseConfigList(String configList,
1091             @NonNull Map<String, Set<String>> packageToActivityMap) {
1092         if (configList == null) {
1093             return;
1094         }
1095         String[] entries = configList.split(PACKAGE_DELIMITER);
1096         for (String entry : entries) {
1097             String[] packageActivityPair = entry.split(PACKAGE_ACTIVITY_DELIMITER);
1098             Set<String> activities = packageToActivityMap.get(packageActivityPair[0]);
1099             boolean newPackage = false;
1100             if (activities == null) {
1101                 activities = new ArraySet<>();
1102                 newPackage = true;
1103                 packageToActivityMap.put(packageActivityPair[0], activities);
1104             }
1105             if (packageActivityPair.length == 1) { // whole package
1106                 activities.clear();
1107             } else if (packageActivityPair.length == 2) {
1108                 // add class name only when the whole package is not allowlisted.
1109                 if (newPackage || (activities.size() > 0)) {
1110                     activities.add(packageActivityPair[1]);
1111                 }
1112             }
1113         }
1114     }
1115 
1116     @Nullable
getActivitiesInPackage(PackageInfo info)1117     private List<String> getActivitiesInPackage(PackageInfo info) {
1118         if (info == null || info.activities == null) {
1119             return null;
1120         }
1121         List<String> activityList = new ArrayList<>();
1122         for (ActivityInfo aInfo : info.activities) {
1123             activityList.add(aInfo.name);
1124         }
1125         return activityList;
1126     }
1127 
1128     /**
1129      * Checks if there are any {@link CarAppBlockingPolicyService} and creates a proxy to
1130      * bind to them and retrieve the {@link CarAppBlockingPolicy}
1131      */
1132     @VisibleForTesting
startAppBlockingPolicies()1133     public void startAppBlockingPolicies() {
1134         Intent policyIntent = new Intent();
1135         policyIntent.setAction(CarAppBlockingPolicyService.SERVICE_INTERFACE);
1136         List<ResolveInfo> policyInfos = mPackageManager.queryIntentServices(policyIntent, 0);
1137         if (policyInfos == null) { //no need to wait for service binding and retrieval.
1138             return;
1139         }
1140         LinkedList<AppBlockingPolicyProxy> proxies = new LinkedList<>();
1141         for (ResolveInfo resolveInfo : policyInfos) {
1142             ServiceInfo serviceInfo = resolveInfo.serviceInfo;
1143             if (serviceInfo == null) {
1144                 continue;
1145             }
1146             if (serviceInfo.isEnabled()) {
1147                 if (mPackageManager.checkPermission(Car.PERMISSION_CONTROL_APP_BLOCKING,
1148                         serviceInfo.packageName) != PackageManager.PERMISSION_GRANTED) {
1149                     continue;
1150                 }
1151                 Slog.i(TAG, "found policy holding service:" + serviceInfo);
1152                 AppBlockingPolicyProxy proxy = new AppBlockingPolicyProxy(this, mContext,
1153                         serviceInfo);
1154                 proxy.connect();
1155                 proxies.add(proxy);
1156             }
1157         }
1158         synchronized (mLock) {
1159             mProxies = proxies;
1160         }
1161     }
1162 
onPolicyConnectionAndSet(AppBlockingPolicyProxy proxy, CarAppBlockingPolicy policy)1163     public void onPolicyConnectionAndSet(AppBlockingPolicyProxy proxy,
1164             CarAppBlockingPolicy policy) {
1165         doHandlePolicyConnection(proxy, policy);
1166     }
1167 
onPolicyConnectionFailure(AppBlockingPolicyProxy proxy)1168     public void onPolicyConnectionFailure(AppBlockingPolicyProxy proxy) {
1169         doHandlePolicyConnection(proxy, null);
1170     }
1171 
doHandlePolicyConnection(AppBlockingPolicyProxy proxy, CarAppBlockingPolicy policy)1172     private void doHandlePolicyConnection(AppBlockingPolicyProxy proxy,
1173             CarAppBlockingPolicy policy) {
1174         synchronized (mLock) {
1175             if (mProxies == null) {
1176                 proxy.disconnect();
1177                 return;
1178             }
1179             mProxies.remove(proxy);
1180             if (mProxies.size() == 0) {
1181                 mProxies = null;
1182             }
1183         }
1184         try {
1185             if (policy != null) {
1186                 if (Log.isLoggable(TAG, Log.DEBUG)) {
1187                     Slog.d(TAG, "policy setting from policy service:" + proxy.getPackageName());
1188                 }
1189                 doSetAppBlockingPolicy(proxy.getPackageName(), policy, 0);
1190             }
1191         } finally {
1192             proxy.disconnect();
1193         }
1194     }
1195 
1196     @Override
dump(IndentingPrintWriter writer)1197     public void dump(IndentingPrintWriter writer) {
1198         synchronized (mLock) {
1199             writer.println("*CarPackageManagerService*");
1200             writer.println("mEnableActivityBlocking:" + mEnableActivityBlocking);
1201             writer.println("mPreventTemplatedAppsFromShowingDialog:"
1202                     + mPreventTemplatedAppsFromShowingDialog);
1203             writer.println("mTemplateActivityClassName:" + mTemplateActivityClassName);
1204             List<String> restrictions = new ArrayList<>(mUxRestrictionsListeners.size());
1205             for (int i = 0; i < mUxRestrictionsListeners.size(); i++) {
1206                 int displayId = mUxRestrictionsListeners.keyAt(i);
1207                 UxRestrictionsListener listener = mUxRestrictionsListeners.valueAt(i);
1208                 restrictions.add(String.format("Display %d is %s",
1209                         displayId, (listener.isRestricted() ? "restricted" : "unrestricted")));
1210             }
1211             writer.println("Display Restrictions:\n" + String.join("\n", restrictions));
1212             writer.println(" Blocked activity log:");
1213             mBlockedActivityLogs.dump(writer);
1214             writer.print(dumpPoliciesLocked(true));
1215             writer.print("mCurrentDrivingSafetyRegion:");
1216             writer.println(mCurrentDrivingSafetyRegion);
1217             writer.print("mTempAllowedActivities:");
1218             writer.println(mTempAllowedActivities);
1219         }
1220     }
1221 
1222     @GuardedBy("mLock")
dumpPoliciesLocked(boolean dumpAll)1223     private String dumpPoliciesLocked(boolean dumpAll) {
1224         StringBuilder sb = new StringBuilder();
1225         if (dumpAll) {
1226             sb.append("**System allowlist**\n");
1227             for (AppBlockingPackageInfoWrapper wrapper : mActivityAllowlistMap.values()) {
1228                 sb.append(wrapper.toString() + "\n");
1229             }
1230         }
1231         sb.append("**Client Policies**\n");
1232         for (Entry<String, ClientPolicy> entry : mClientPolicies.entrySet()) {
1233             sb.append("Client:" + entry.getKey() + "\n");
1234             sb.append("  allowlists:\n");
1235             for (AppBlockingPackageInfoWrapper wrapper : entry.getValue().mAllowlistsMap.values()) {
1236                 sb.append(wrapper.toString() + "\n");
1237             }
1238             sb.append("  blocklists:\n");
1239             for (AppBlockingPackageInfoWrapper wrapper : entry.getValue().mBlocklistsMap.values()) {
1240                 sb.append(wrapper.toString() + "\n");
1241             }
1242         }
1243         sb.append("**Unprocessed policy services**\n");
1244         if (mProxies != null) {
1245             for (AppBlockingPolicyProxy proxy : mProxies) {
1246                 sb.append(proxy.toString() + "\n");
1247             }
1248         }
1249         sb.append("**Allowlist string in resource**\n");
1250         sb.append(mConfiguredAllowlist + "\n");
1251 
1252         sb.append("**System allowlist string in resource**\n");
1253         sb.append(mConfiguredSystemAllowlist + "\n");
1254 
1255         sb.append("**Blocklist string in resource**\n");
1256         sb.append(mConfiguredBlocklist + "\n");
1257 
1258         sb.append("**Allowlist map from resource**\n");
1259         sb.append(mConfiguredAllowlistMap + "\n");
1260 
1261         sb.append("**Blocklist from resource**\n");
1262         sb.append(mConfiguredBlocklist + "\n");
1263 
1264         return sb.toString();
1265     }
1266 
1267     /**
1268      * Returns display with physical address.
1269      */
getPhysicalDisplays()1270     private List<Display> getPhysicalDisplays() {
1271         List<Display> displays = new ArrayList<>();
1272         for (Display display : mDisplayManager.getDisplays()) {
1273             if (display.getAddress() instanceof DisplayAddress.Physical) {
1274                 displays.add(display);
1275             }
1276         }
1277         return displays;
1278     }
1279 
1280     /**
1281      * Returns whether UX restrictions is required for display.
1282      *
1283      * Non-physical display will use restrictions for {@link Display#DEFAULT_DISPLAY}.
1284      */
isUxRestrictedOnDisplay(int displayId)1285     private boolean isUxRestrictedOnDisplay(int displayId) {
1286         UxRestrictionsListener listenerForTopTaskDisplay;
1287         if (mUxRestrictionsListeners.indexOfKey(displayId) < 0) {
1288             listenerForTopTaskDisplay = mUxRestrictionsListeners.get(Display.DEFAULT_DISPLAY);
1289             if (listenerForTopTaskDisplay == null) {
1290                 // This should never happen.
1291                 Slog.e(TAG, "Missing listener for default display.");
1292                 return true;
1293             }
1294         } else {
1295             listenerForTopTaskDisplay = mUxRestrictionsListeners.get(displayId);
1296         }
1297 
1298         return listenerForTopTaskDisplay.isRestricted();
1299     }
1300 
blockTopActivitiesIfNecessary()1301     private void blockTopActivitiesIfNecessary() {
1302         List<TopTaskInfoContainer> topTasks = mSystemActivityMonitoringService.getTopTasks();
1303         for (TopTaskInfoContainer topTask : topTasks) {
1304             if (topTask == null) {
1305                 Slog.e(TAG, "Top tasks contains null.");
1306                 continue;
1307             }
1308             blockTopActivityIfNecessary(topTask);
1309         }
1310     }
1311 
blockTopActivityIfNecessary(TopTaskInfoContainer topTask)1312     private void blockTopActivityIfNecessary(TopTaskInfoContainer topTask) {
1313         synchronized (mLock) {
1314             if (!Objects.equals(mActivityBlockingActivity, topTask.topActivity)
1315                     && mTopActivityWithDialogPerDisplay.contains(topTask.displayId)
1316                     && !topTask.topActivity.equals(
1317                             mTopActivityWithDialogPerDisplay.get(topTask.displayId))) {
1318                 // Clear top activity-with-dialog if the activity has changed on this display.
1319                 mTopActivityWithDialogPerDisplay.remove(topTask.displayId);
1320             }
1321         }
1322         if (isUxRestrictedOnDisplay(topTask.displayId)) {
1323             doBlockTopActivityIfNotAllowed(topTask);
1324         }
1325     }
1326 
doBlockTopActivityIfNotAllowed(TopTaskInfoContainer topTask)1327     private void doBlockTopActivityIfNotAllowed(TopTaskInfoContainer topTask) {
1328         if (topTask.topActivity == null) {
1329             return;
1330         }
1331         boolean allowed = isActivityAllowed(topTask);
1332         if (Log.isLoggable(TAG, Log.DEBUG)) {
1333             Slog.d(TAG, "new activity:" + topTask.toString() + " allowed:" + allowed);
1334         }
1335         if (allowed) {
1336             return;
1337         }
1338         if (!mEnableActivityBlocking) {
1339             Slog.d(TAG, "Current activity " + topTask.topActivity
1340                     + " not allowed, blocking disabled. Number of tasks in stack:"
1341                     + topTask.taskInfo.childTaskIds.length);
1342             return;
1343         }
1344         if (Log.isLoggable(TAG, Log.DEBUG)) {
1345             Slog.d(TAG, "Current activity " + topTask.topActivity
1346                     + " not allowed, will block, number of tasks in stack:"
1347                     + topTask.taskInfo.childTaskIds.length);
1348         }
1349 
1350         // Figure out the root activity of blocked task.
1351         String taskRootActivity = null;
1352         for (int i = 0; i < topTask.taskInfo.childTaskIds.length; i++) {
1353             // topTask.taskId is the task that should be blocked.
1354             if (topTask.taskInfo.childTaskIds[i] == topTask.taskId) {
1355                 // stackInfo represents an ActivityStack. Its fields taskIds and taskNames
1356                 // are 1:1 mapped, where taskNames is the name of root activity in this task.
1357                 taskRootActivity = topTask.taskInfo.childTaskNames[i];
1358                 break;
1359             }
1360         }
1361 
1362         boolean isRootDO = false;
1363         if (taskRootActivity != null) {
1364             ComponentName taskRootComponentName =
1365                     ComponentName.unflattenFromString(taskRootActivity);
1366             isRootDO = isActivityDistractionOptimized(
1367                     taskRootComponentName.getPackageName(), taskRootComponentName.getClassName());
1368         }
1369 
1370         Intent newActivityIntent = createBlockingActivityIntent(
1371                 mActivityBlockingActivity, topTask.displayId,
1372                 topTask.topActivity.flattenToShortString(), topTask.taskId, taskRootActivity,
1373                 isRootDO);
1374 
1375         // Intent contains all info to debug what is blocked - log into both logcat and dumpsys.
1376         String log = "Starting blocking activity with intent: " + newActivityIntent.toUri(0);
1377         if (Log.isLoggable(TAG, Log.INFO)) {
1378             Slog.i(TAG, log);
1379         }
1380         mBlockedActivityLogs.log(log);
1381         mSystemActivityMonitoringService.blockActivity(topTask, newActivityIntent);
1382     }
1383 
isActivityAllowed(TopTaskInfoContainer topTaskInfoContainer)1384     private boolean isActivityAllowed(TopTaskInfoContainer topTaskInfoContainer) {
1385         ComponentName activityName = topTaskInfoContainer.topActivity;
1386         boolean isDistractionOptimized = isActivityDistractionOptimized(
1387                 activityName.getPackageName(),
1388                 activityName.getClassName());
1389         if (!isDistractionOptimized) {
1390             return false;
1391         }
1392         return !(mPreventTemplatedAppsFromShowingDialog
1393                 && isTemplateActivity(activityName)
1394                 && isActivityShowingADialogOnDisplay(activityName, topTaskInfoContainer.displayId));
1395     }
1396 
isTemplateActivity(ComponentName activityName)1397     private boolean isTemplateActivity(ComponentName activityName) {
1398         // TODO(b/191263486): Finalise on how to detect the templated activities.
1399         return activityName.getClassName().equals(mTemplateActivityClassName);
1400     }
1401 
isActivityShowingADialogOnDisplay(ComponentName activityName, int displayId)1402     private boolean isActivityShowingADialogOnDisplay(ComponentName activityName, int displayId) {
1403         String output = dumpWindows();
1404         List<WindowDumpParser.Window> appWindows =
1405                 WindowDumpParser.getParsedAppWindows(output, activityName.getPackageName());
1406         // TODO(b/192354699): Handle case where an activity can have multiple instances on the same
1407         //  display.
1408         int totalAppWindows = appWindows.size();
1409         String firstActivityRecord = null;
1410         int numTopActivityAppWindowsOnDisplay = 0;
1411         for (int i = 0; i < totalAppWindows; i++) {
1412             WindowDumpParser.Window appWindow = appWindows.get(i);
1413             if (appWindow.getDisplayId() != displayId) {
1414                 continue;
1415             }
1416             if (TextUtils.isEmpty(appWindow.getActivityRecord())) {
1417                 continue;
1418             }
1419             if (firstActivityRecord == null) {
1420                 firstActivityRecord = appWindow.getActivityRecord();
1421             }
1422             if (firstActivityRecord.equals(appWindow.getActivityRecord())) {
1423                 numTopActivityAppWindowsOnDisplay++;
1424             }
1425         }
1426         Slogf.d(TAG, "Top activity =  " + activityName);
1427         Slogf.d(TAG, "Number of app widows of top activity = " + numTopActivityAppWindowsOnDisplay);
1428         boolean isShowingADialog = numTopActivityAppWindowsOnDisplay > 1;
1429         synchronized (mLock) {
1430             if (isShowingADialog) {
1431                 mTopActivityWithDialogPerDisplay.put(displayId, activityName);
1432             } else {
1433                 mTopActivityWithDialogPerDisplay.remove(displayId);
1434             }
1435         }
1436         return isShowingADialog;
1437     }
1438 
dumpWindows()1439     private String dumpWindows() {
1440         try {
1441             ParcelFileDescriptor[] fileDescriptors = ParcelFileDescriptor.createSocketPair();
1442             mWindowManagerBinder.dump(
1443                     fileDescriptors[0].getFileDescriptor(), WINDOW_DUMP_ARGUMENTS);
1444             fileDescriptors[0].close();
1445             StringBuilder outputBuilder = new StringBuilder();
1446             BufferedReader reader = new BufferedReader(
1447                     new FileReader(fileDescriptors[1].getFileDescriptor()));
1448             String line;
1449             while ((line = reader.readLine()) != null) {
1450                 outputBuilder.append(line).append("\n");
1451             }
1452             reader.close();
1453             fileDescriptors[1].close();
1454             return outputBuilder.toString();
1455         } catch (IOException | RemoteException e) {
1456             throw new RuntimeException(e);
1457         }
1458     }
1459 
1460     /**
1461      * Creates an intent to start blocking activity.
1462      *
1463      * @param blockingActivity the activity to launch
1464      * @param blockedActivity  the activity being blocked
1465      * @param blockedTaskId    the blocked task id, which contains the blocked activity
1466      * @param taskRootActivity root activity of the blocked task
1467      * @param isRootDo         denotes if the root activity is distraction optimised
1468      * @return an intent to launch the blocking activity.
1469      */
createBlockingActivityIntent(ComponentName blockingActivity, int displayId, String blockedActivity, int blockedTaskId, String taskRootActivity, boolean isRootDo)1470     private static Intent createBlockingActivityIntent(ComponentName blockingActivity,
1471             int displayId, String blockedActivity, int blockedTaskId, String taskRootActivity,
1472             boolean isRootDo) {
1473         Intent newActivityIntent = new Intent();
1474         newActivityIntent.setFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
1475         newActivityIntent.setComponent(blockingActivity);
1476         newActivityIntent.putExtra(
1477                 BLOCKING_INTENT_EXTRA_DISPLAY_ID, displayId);
1478         newActivityIntent.putExtra(
1479                 BLOCKING_INTENT_EXTRA_BLOCKED_ACTIVITY_NAME, blockedActivity);
1480         newActivityIntent.putExtra(
1481                 BLOCKING_INTENT_EXTRA_BLOCKED_TASK_ID, blockedTaskId);
1482         newActivityIntent.putExtra(
1483                 BLOCKING_INTENT_EXTRA_ROOT_ACTIVITY_NAME, taskRootActivity);
1484         newActivityIntent.putExtra(
1485                 BLOCKING_INTENT_EXTRA_IS_ROOT_ACTIVITY_DO, isRootDo);
1486 
1487         return newActivityIntent;
1488     }
1489 
1490     /**
1491      * Enable/Disable activity blocking by correspondingly enabling/disabling broadcasting UXR
1492      * changes in {@link CarUxRestrictionsManagerService}. This is only available in
1493      * engineering builds for development convenience.
1494      */
1495     @Override
setEnableActivityBlocking(boolean enable)1496     public void setEnableActivityBlocking(boolean enable) {
1497         if (!isDebugBuild()) {
1498             Slog.e(TAG, "Cannot enable/disable activity blocking");
1499             return;
1500         }
1501 
1502         // Check if the caller has the same signature as that of the car service.
1503         if (mPackageManager.checkSignatures(Process.myUid(), Binder.getCallingUid())
1504                 != PackageManager.SIGNATURE_MATCH) {
1505             throw new SecurityException(
1506                     "Caller " + mPackageManager.getNameForUid(Binder.getCallingUid())
1507                     + " does not have the right signature");
1508         }
1509         mCarUxRestrictionsService.setUxRChangeBroadcastEnabled(enable);
1510     }
1511 
1512     /**
1513      * Get the distraction optimized activities for the given package.
1514      *
1515      * @param pkgName Name of the package
1516      * @return Array of the distraction optimized activities in the package
1517      */
1518     @Nullable
getDistractionOptimizedActivities(String pkgName)1519     public String[] getDistractionOptimizedActivities(String pkgName) {
1520         try {
1521             return findDistractionOptimizedActivitiesAsUser(pkgName,
1522                     mActivityManager.getCurrentUser());
1523         } catch (NameNotFoundException e) {
1524             return null;
1525         }
1526     }
1527 
findDistractionOptimizedActivitiesAsUser(String pkgName, int userId)1528     private String[] findDistractionOptimizedActivitiesAsUser(String pkgName, int userId)
1529             throws NameNotFoundException {
1530         String regionString;
1531         synchronized (mLock) {
1532             regionString = mCurrentDrivingSafetyRegion;
1533         }
1534         return CarAppMetadataReader.findDistractionOptimizedActivitiesAsUser(mContext, pkgName,
1535                 userId, regionString);
1536     }
1537 
1538     /**
1539      * Reading policy and setting policy can take time. Run it in a separate handler thread.
1540      */
1541     private static final class PackageHandler extends Handler {
1542         private static final String TAG = CarLog.tagFor(CarPackageManagerService.class);
1543 
1544         private static final int MSG_INIT = 0;
1545         private static final int MSG_PARSE_PKG = 1;
1546         private static final int MSG_UPDATE_POLICY = 2;
1547         private static final int MSG_RELEASE = 3;
1548 
1549         private final WeakReference<CarPackageManagerService> mService;
1550 
PackageHandler(Looper looper, CarPackageManagerService service)1551         private PackageHandler(Looper looper, CarPackageManagerService service) {
1552             super(looper);
1553             mService = new WeakReference<CarPackageManagerService>(service);
1554         }
1555 
requestInit()1556         private void requestInit() {
1557             Message msg = obtainMessage(MSG_INIT);
1558             sendMessage(msg);
1559         }
1560 
requestRelease()1561         private void requestRelease() {
1562             removeMessages(MSG_UPDATE_POLICY);
1563             Message msg = obtainMessage(MSG_RELEASE);
1564             sendMessage(msg);
1565         }
1566 
requestUpdatingPolicy(String packageName, CarAppBlockingPolicy policy, int flags)1567         private void requestUpdatingPolicy(String packageName, CarAppBlockingPolicy policy,
1568                 int flags) {
1569             Pair<String, CarAppBlockingPolicy> pair = new Pair<>(packageName, policy);
1570             Message msg = obtainMessage(MSG_UPDATE_POLICY, flags, 0, pair);
1571             sendMessage(msg);
1572         }
1573 
requestParsingInstalledPkg(String packageName)1574         private void requestParsingInstalledPkg(String packageName) {
1575             Message msg = obtainMessage(MSG_PARSE_PKG, packageName);
1576             sendMessage(msg);
1577         }
1578 
1579         @Override
handleMessage(Message msg)1580         public void handleMessage(Message msg) {
1581             CarPackageManagerService service = mService.get();
1582             if (service == null) {
1583                 Slog.i(TAG, "handleMessage null service");
1584                 return;
1585             }
1586             switch (msg.what) {
1587                 case MSG_INIT:
1588                     service.doHandleInit();
1589                     break;
1590                 case MSG_PARSE_PKG:
1591                     service.doParseInstalledPackage((String) msg.obj);
1592                     break;
1593                 case MSG_UPDATE_POLICY:
1594                     Pair<String, CarAppBlockingPolicy> pair =
1595                             (Pair<String, CarAppBlockingPolicy>) msg.obj;
1596                     service.doUpdatePolicy(pair.first, pair.second, msg.arg1);
1597                     break;
1598                 case MSG_RELEASE:
1599                     service.doHandleRelease();
1600                     break;
1601             }
1602         }
1603     }
1604 
1605     private static class AppBlockingPackageInfoWrapper {
1606         private final AppBlockingPackageInfo info;
1607         /**
1608          * Whether the current info is matching with the target package in system. Mismatch can
1609          * happen for version out of range or signature mismatch.
1610          */
1611         private boolean isMatching;
1612 
AppBlockingPackageInfoWrapper(AppBlockingPackageInfo info, boolean isMatching)1613         private AppBlockingPackageInfoWrapper(AppBlockingPackageInfo info, boolean isMatching) {
1614             this.info = info;
1615             this.isMatching = isMatching;
1616         }
1617 
1618         @Override
toString()1619         public String toString() {
1620             return "AppBlockingPackageInfoWrapper [info=" + info + ", isMatching=" + isMatching +
1621                     "]";
1622         }
1623     }
1624 
1625     /**
1626      * Client policy holder per each client. Should be accessed with CarpackageManagerService.this
1627      * held.
1628      */
1629     private static class ClientPolicy {
1630         private final HashMap<String, AppBlockingPackageInfoWrapper> mAllowlistsMap =
1631                 new HashMap<>();
1632         private final HashMap<String, AppBlockingPackageInfoWrapper> mBlocklistsMap =
1633                 new HashMap<>();
1634 
replaceAllowlists(AppBlockingPackageInfoWrapper[] allowlists)1635         private void replaceAllowlists(AppBlockingPackageInfoWrapper[] allowlists) {
1636             mAllowlistsMap.clear();
1637             addToAllowlists(allowlists);
1638         }
1639 
addToAllowlists(AppBlockingPackageInfoWrapper[] allowlists)1640         private void addToAllowlists(AppBlockingPackageInfoWrapper[] allowlists) {
1641             if (allowlists == null) {
1642                 return;
1643             }
1644             for (AppBlockingPackageInfoWrapper wrapper : allowlists) {
1645                 if (wrapper != null) {
1646                     mAllowlistsMap.put(wrapper.info.packageName, wrapper);
1647                 }
1648             }
1649         }
1650 
removeAllowlists(AppBlockingPackageInfoWrapper[] allowlists)1651         private void removeAllowlists(AppBlockingPackageInfoWrapper[] allowlists) {
1652             if (allowlists == null) {
1653                 return;
1654             }
1655             for (AppBlockingPackageInfoWrapper wrapper : allowlists) {
1656                 if (wrapper != null) {
1657                     mAllowlistsMap.remove(wrapper.info.packageName);
1658                 }
1659             }
1660         }
1661 
replaceBlocklists(AppBlockingPackageInfoWrapper[] blocklists)1662         private void replaceBlocklists(AppBlockingPackageInfoWrapper[] blocklists) {
1663             mBlocklistsMap.clear();
1664             addToBlocklists(blocklists);
1665         }
1666 
addToBlocklists(AppBlockingPackageInfoWrapper[] blocklists)1667         private void addToBlocklists(AppBlockingPackageInfoWrapper[] blocklists) {
1668             if (blocklists == null) {
1669                 return;
1670             }
1671             for (AppBlockingPackageInfoWrapper wrapper : blocklists) {
1672                 if (wrapper != null) {
1673                     mBlocklistsMap.put(wrapper.info.packageName, wrapper);
1674                 }
1675             }
1676         }
1677 
removeBlocklists(AppBlockingPackageInfoWrapper[] blocklists)1678         private void removeBlocklists(AppBlockingPackageInfoWrapper[] blocklists) {
1679             if (blocklists == null) {
1680                 return;
1681             }
1682             for (AppBlockingPackageInfoWrapper wrapper : blocklists) {
1683                 if (wrapper != null) {
1684                     mBlocklistsMap.remove(wrapper.info.packageName);
1685                 }
1686             }
1687         }
1688     }
1689 
1690     private class ActivityLaunchListener
1691             implements SystemActivityMonitoringService.ActivityLaunchListener {
1692         @Override
onActivityLaunch(TopTaskInfoContainer topTask)1693         public void onActivityLaunch(TopTaskInfoContainer topTask) {
1694             if (topTask == null) {
1695                 Slog.e(TAG, "Received callback with null top task.");
1696                 return;
1697             }
1698             blockTopActivityIfNecessary(topTask);
1699         }
1700     }
1701 
1702     /**
1703      * Listens to the UX restrictions from {@link CarUxRestrictionsManagerService} and initiates
1704      * checking if the foreground Activity should be blocked.
1705      */
1706     private class UxRestrictionsListener extends ICarUxRestrictionsChangeListener.Stub {
1707         @GuardedBy("mLock")
1708         @Nullable
1709         private CarUxRestrictions mCurrentUxRestrictions;
1710         private final CarUxRestrictionsManagerService uxRestrictionsService;
1711 
UxRestrictionsListener(CarUxRestrictionsManagerService service)1712         public UxRestrictionsListener(CarUxRestrictionsManagerService service) {
1713             uxRestrictionsService = service;
1714         }
1715 
1716         @Override
onUxRestrictionsChanged(CarUxRestrictions restrictions)1717         public void onUxRestrictionsChanged(CarUxRestrictions restrictions) {
1718             if (Log.isLoggable(TAG, Log.DEBUG)) {
1719                 Slog.d(TAG, "Received uxr restrictions: "
1720                         + restrictions.isRequiresDistractionOptimization() + " : "
1721                         + restrictions.getActiveRestrictions());
1722             }
1723 
1724             synchronized (mLock) {
1725                 mCurrentUxRestrictions = new CarUxRestrictions(restrictions);
1726             }
1727             checkIfTopActivityNeedsBlocking();
1728         }
1729 
checkIfTopActivityNeedsBlocking()1730         private void checkIfTopActivityNeedsBlocking() {
1731             boolean shouldCheck = false;
1732             synchronized (mLock) {
1733                 if (mCurrentUxRestrictions != null
1734                         && mCurrentUxRestrictions.isRequiresDistractionOptimization()) {
1735                     shouldCheck = true;
1736                 }
1737             }
1738             if (Log.isLoggable(TAG, Log.DEBUG)) {
1739                 Slog.d(TAG, "Should check top tasks?: " + shouldCheck);
1740             }
1741             if (shouldCheck) {
1742                 // Loop over all top tasks to ensure tasks on virtual display can also be blocked.
1743                 blockTopActivitiesIfNecessary();
1744             }
1745         }
1746 
isRestricted()1747         private boolean isRestricted() {
1748             // if current restrictions is null, try querying the service, once.
1749             synchronized (mLock) {
1750                 if (mCurrentUxRestrictions == null) {
1751                     mCurrentUxRestrictions = uxRestrictionsService.getCurrentUxRestrictions();
1752                 }
1753                 if (mCurrentUxRestrictions != null) {
1754                     return mCurrentUxRestrictions.isRequiresDistractionOptimization();
1755                 }
1756             }
1757 
1758             // If restriction information is still not available (could happen during bootup),
1759             // return not restricted.  This maintains parity with previous implementation but needs
1760             // a revisit as we test more.
1761             return false;
1762         }
1763     }
1764 
1765     /**
1766      * Called when a window change event is received by the {@link CarSafetyAccessibilityService}.
1767      */
1768     @VisibleForTesting
onWindowChangeEvent()1769     void onWindowChangeEvent() {
1770         Slogf.d(TAG, "onWindowChange event received");
1771         mHandlerThread.getThreadHandler().post(() -> blockTopActivitiesIfNecessary());
1772     }
1773 
1774     /**
1775      * Listens to the package install/uninstall events to know when to initiate parsing
1776      * installed packages.
1777      */
1778     private class PackageParsingEventReceiver extends BroadcastReceiver {
1779         @Override
onReceive(Context context, Intent intent)1780         public void onReceive(Context context, Intent intent) {
1781             if (intent == null || intent.getAction() == null) {
1782                 return;
1783             }
1784             if (Log.isLoggable(TAG, Log.DEBUG)) {
1785                 Slog.d(TAG, "PackageParsingEventReceiver Received " + intent.getAction());
1786             }
1787             String action = intent.getAction();
1788             if (isPackageManagerAction(action)) {
1789                 // send a delayed message so if we received multiple related intents, we parse
1790                 // only once.
1791                 logEventChange(intent);
1792                 String packageName = getPackageName(intent);
1793                 mHandler.requestParsingInstalledPkg(packageName);
1794             }
1795         }
1796 
getPackageName(Intent intent)1797         private String getPackageName(Intent intent) {
1798             // For mPackageManagerActions, data should contain package name.
1799             String dataString = intent.getDataString();
1800             if (dataString == null) return null;
1801 
1802             String scheme = intent.getScheme();
1803             if (!scheme.equals("package")) return null;
1804 
1805             String[] splitData = intent.getDataString().split(":");
1806             if (splitData.length < 2) return null;
1807 
1808             return splitData[1];
1809         }
1810 
isPackageManagerAction(String action)1811         private boolean isPackageManagerAction(String action) {
1812             return mPackageManagerActions.contains(action);
1813         }
1814 
1815         /**
1816          * Convenience log function to log what changed.  Logs only when more debug logs
1817          * are needed - DBG_POLICY_CHECK needs to be true
1818          */
logEventChange(Intent intent)1819         private void logEventChange(Intent intent) {
1820             if (intent == null) {
1821                 return;
1822             }
1823             if (Log.isLoggable(TAG, Log.DEBUG)) {
1824                 String packageName = intent.getData().getSchemeSpecificPart();
1825                 Slog.d(TAG, "Pkg Changed:" + packageName);
1826                 String action = intent.getAction();
1827                 if (action == null) {
1828                     return;
1829                 }
1830                 if (action.equals(Intent.ACTION_PACKAGE_CHANGED)) {
1831                     Slog.d(TAG, "Changed components");
1832                     String[] cc = intent
1833                             .getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
1834                     if (cc != null) {
1835                         for (String c : cc) {
1836                             Slog.d(TAG, c);
1837                         }
1838                     }
1839                 } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
1840                         || action.equals(Intent.ACTION_PACKAGE_ADDED)) {
1841                     Slog.d(TAG, action + " Replacing?: "
1842                             + intent.getBooleanExtra(Intent.EXTRA_REPLACING, false));
1843                 }
1844             }
1845         }
1846     }
1847 }
1848