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