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