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