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