Home | History | Annotate | Download | only in pm
      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 
    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
    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
    169     public void restartTask(int taskId) {
    170         mSystemActivityMonitoringService.restartTask(taskId);
    171     }
    172 
    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
    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
    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
    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 
    260     public Looper getLooper() {
    261         return mHandlerThread.getLooper();
    262     }
    263 
    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")
    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")
    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")
    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 
    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
    320     public void init() {
    321         synchronized (this) {
    322             mHandler.requestInit();
    323         }
    324     }
    325 
    326     @Override
    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
    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 
    376     private void doParseInstalledPackages() {
    377         generateActivityWhitelistMap();
    378         generateActivityBlacklistMap();
    379         synchronized (this) {
    380             mHasParsedPackages = true;
    381         }
    382         mUxRestrictionsListener.checkIfTopActivityNeedsBlocking();
    383     }
    384 
    385     private synchronized void doHandleRelease() {
    386         notifyAll();
    387     }
    388 
    389     @GuardedBy("this")
    390     private void wakeupClientsWaitingForPolicySetitngLocked() {
    391         for (CarAppBlockingPolicy waitingPolicy : mWaitingPolicies) {
    392             synchronized (waitingPolicy) {
    393                 waitingPolicy.notifyAll();
    394             }
    395         }
    396         mWaitingPolicies.clear();
    397     }
    398 
    399     private void doSetPolicy() {
    400         synchronized (this) {
    401             wakeupClientsWaitingForPolicySetitngLocked();
    402         }
    403         blockTopActivitiesIfNecessary();
    404     }
    405 
    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 
    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 
    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      */
    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      */
    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      */
    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
    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
    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
    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 
    770     public void onPolicyConnectionAndSet(AppBlockingPolicyProxy proxy,
    771             CarAppBlockingPolicy policy) {
    772         doHandlePolicyConnection(proxy, policy);
    773     }
    774 
    775     public void onPolicyConnectionFailure(AppBlockingPolicyProxy proxy) {
    776         doHandlePolicyConnection(proxy, null);
    777     }
    778 
    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
    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")
    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 
    862     private void blockTopActivityIfNecessary(TopTaskInfoContainer topTask) {
    863         boolean restricted = mUxRestrictionsListener.isRestricted();
    864         if (!restricted) {
    865             return;
    866         }
    867         doBlockTopActivityIfNotAllowed(topTask);
    868     }
    869 
    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 
    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
    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
    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      */
    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 
   1000         private PackageHandler(Looper looper) {
   1001             super(looper);
   1002         }
   1003 
   1004         private void requestInit() {
   1005             Message msg = obtainMessage(MSG_INIT);
   1006             sendMessage(msg);
   1007         }
   1008 
   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 
   1017         private void requestPolicySetting() {
   1018             Message msg = obtainMessage(MSG_SET_POLICY);
   1019             sendMessage(msg);
   1020         }
   1021 
   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 
   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
   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 
   1071         private AppBlockingPackageInfoWrapper(AppBlockingPackageInfo info, boolean isMatching) {
   1072             this.info = info;
   1073             this.isMatching = isMatching;
   1074         }
   1075 
   1076         @Override
   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 
   1093         private void replaceWhitelists(AppBlockingPackageInfoWrapper[] whitelists) {
   1094             whitelistsMap.clear();
   1095             addToWhitelists(whitelists);
   1096         }
   1097 
   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 
   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 
   1120         private void replaceBlacklists(AppBlockingPackageInfoWrapper[] blacklists) {
   1121             blacklistsMap.clear();
   1122             addToBlacklists(blacklists);
   1123         }
   1124 
   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 
   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
   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 
   1166         public UxRestrictionsListener(CarUxRestrictionsManagerService service) {
   1167             uxRestrictionsService = service;
   1168             mCurrentUxRestrictions = uxRestrictionsService.getCurrentUxRestrictions();
   1169         }
   1170 
   1171         @Override
   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 
   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 
   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
   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
   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 
   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          */
   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