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