CarPackageManagerService.java revision 1b1247b5648975dd41ee73c25425825abb256234
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 */
16package com.android.car.pm;
17
18import android.app.ActivityManager.StackInfo;
19import android.car.Car;
20import android.car.content.pm.AppBlockingPackageInfo;
21import android.car.content.pm.CarAppBlockingPolicy;
22import android.car.content.pm.CarAppBlockingPolicyService;
23import android.car.content.pm.CarPackageManager;
24import android.car.content.pm.ICarPackageManager;
25import android.car.hardware.CarSensorEvent;
26import android.car.hardware.CarSensorManager;
27import android.car.hardware.ICarSensorEventListener;
28import android.content.ComponentName;
29import android.content.Context;
30import android.content.Intent;
31import android.content.pm.PackageInfo;
32import android.content.pm.PackageManager;
33import android.content.pm.PackageManager.NameNotFoundException;
34import android.content.pm.ServiceInfo;
35import android.content.pm.ResolveInfo;
36import android.content.pm.Signature;
37import android.content.res.Resources;
38import android.os.Handler;
39import android.os.HandlerThread;
40import android.os.Looper;
41import android.os.Message;
42import android.util.ArraySet;
43import android.util.Log;
44import android.util.Pair;
45
46import com.android.car.CarLog;
47import com.android.car.CarSensorService;
48import com.android.car.CarServiceBase;
49import com.android.car.CarServiceUtils;
50import com.android.car.R;
51import com.android.car.SystemActivityMonitoringService;
52import com.android.car.SystemActivityMonitoringService.TopTaskInfoContainer;
53import com.android.car.pm.CarAppMetadataReader.CarAppMetadataInfo;
54import com.android.internal.annotations.GuardedBy;
55
56import java.io.PrintWriter;
57import java.util.Arrays;
58import java.util.HashMap;
59import java.util.LinkedList;
60import java.util.List;
61import java.util.Map.Entry;
62import java.util.Set;
63
64//TODO monitor app installing and refresh policy
65
66public class CarPackageManagerService extends ICarPackageManager.Stub implements CarServiceBase {
67    static final boolean DBG_POLICY_SET = false;
68    static final boolean DBG_POLICY_CHECK = false;
69    static final boolean DBG_POLICY_ENFORCEMENT = false;
70
71    private final Context mContext;
72    private final SystemActivityMonitoringService mSystemActivityMonitoringService;
73    private final CarSensorService mSensorService;
74    private final PackageManager mPackageManager;
75
76    private final HandlerThread mHandlerThread;
77    private final PackageHandler mHandler;
78
79    /**
80     * Hold policy set from policy service or client.
81     * Key: packageName of policy service
82     */
83    @GuardedBy("this")
84    private final HashMap<String, ClientPolicy> mClientPolicies =
85            new HashMap<>();
86    @GuardedBy("this")
87    private HashMap<String, AppBlockingPackageInfoWrapper> mSystemWhitelists = new HashMap<>();
88    @GuardedBy("this")
89    private LinkedList<AppBlockingPolicyProxy> mProxies;
90    @GuardedBy("this")
91    private boolean mReleased = true;
92
93    @GuardedBy("this")
94    private final LinkedList<CarAppBlockingPolicy> mWaitingPolicies = new LinkedList<>();
95
96    private final boolean mEnableActivityBlocking;
97    private final ComponentName mActivityBlockingActivity;
98
99    private final ActivityLaunchListener mActivityLaunchListener = new ActivityLaunchListener();
100    private final SensorListener mDrivingStateListener = new SensorListener();
101
102    public CarPackageManagerService(Context context, CarSensorService sensorService,
103            SystemActivityMonitoringService systemActivityMonitoringService) {
104        mContext = context;
105        mSensorService = sensorService;
106        mSystemActivityMonitoringService = systemActivityMonitoringService;
107        mPackageManager = mContext.getPackageManager();
108        mHandlerThread = new HandlerThread(CarLog.TAG_PACKAGE);
109        mHandlerThread.start();
110        mHandler = new PackageHandler(mHandlerThread.getLooper());
111        Resources res = context.getResources();
112        mEnableActivityBlocking = res.getBoolean(R.bool.enableActivityBlockingForSafety);
113        String blockingActivity = res.getString(R.string.activityBlockingActivity);
114        mActivityBlockingActivity = ComponentName.unflattenFromString(blockingActivity);
115    }
116
117    @Override
118    public void setAppBlockingPolicy(String packageName, CarAppBlockingPolicy policy, int flags) {
119        if (DBG_POLICY_SET) {
120            Log.i(CarLog.TAG_PACKAGE, "policy setting from binder call, client:" + packageName);
121        }
122        doSetAppBlockingPolicy(packageName, policy, flags, true /*setNow*/);
123    }
124
125    private void doSetAppBlockingPolicy(String packageName, CarAppBlockingPolicy policy, int flags,
126            boolean setNow) {
127        if (mContext.checkCallingOrSelfPermission(Car.PERMISSION_CONTROL_APP_BLOCKING)
128                != PackageManager.PERMISSION_GRANTED) {
129            throw new SecurityException(
130                    "requires permission " + Car.PERMISSION_CONTROL_APP_BLOCKING);
131        }
132        CarServiceUtils.assertPakcageName(mContext, packageName);
133        if (policy == null) {
134            throw new IllegalArgumentException("policy cannot be null");
135        }
136        if ((flags & CarPackageManager.FLAG_SET_POLICY_ADD) != 0 &&
137                (flags & CarPackageManager.FLAG_SET_POLICY_REMOVE) != 0) {
138            throw new IllegalArgumentException(
139                    "Cannot set both FLAG_SET_POLICY_ADD and FLAG_SET_POLICY_REMOVE flag");
140        }
141        mHandler.requestUpdatingPolicy(packageName, policy, flags);
142        if (setNow) {
143            mHandler.requestPolicySetting();
144            if ((flags & CarPackageManager.FLAG_SET_POLICY_WAIT_FOR_CHANGE) != 0) {
145                synchronized (policy) {
146                    try {
147                        policy.wait();
148                    } catch (InterruptedException e) {
149                    }
150                }
151            }
152        }
153    }
154
155    @Override
156    public boolean isActivityAllowedWhileDriving(String packageName, String className) {
157        assertPackageAndClassName(packageName, className);
158        synchronized (this) {
159            if (DBG_POLICY_CHECK) {
160                Log.i(CarLog.TAG_PACKAGE, "isActivityAllowedWhileDriving" +
161                        dumpPoliciesLocked(false));
162            }
163            AppBlockingPackageInfo info = searchFromBlacklistsLocked(packageName);
164            if (info != null) {
165                return false;
166            }
167            return isActivityInWhitelistsLocked(packageName, className);
168        }
169    }
170
171    @Override
172    public boolean isServiceAllowedWhileDriving(String packageName, String className) {
173        if (packageName == null) {
174            throw new IllegalArgumentException("Package name null");
175        }
176        synchronized (this) {
177            if (DBG_POLICY_CHECK) {
178                Log.i(CarLog.TAG_PACKAGE, "isServiceAllowedWhileDriving" +
179                        dumpPoliciesLocked(false));
180            }
181            AppBlockingPackageInfo info = searchFromBlacklistsLocked(packageName);
182            if (info != null) {
183                return false;
184            }
185            info = searchFromWhitelistsLocked(packageName);
186            if (info != null) {
187                return true;
188            }
189        }
190        return false;
191    }
192
193    @Override
194    public boolean isActivityBackedBySafeActivity(ComponentName activityName) {
195        if (!mEnableActivityBlocking || !mDrivingStateListener.isRestricted()) {
196            return true;
197        }
198        StackInfo info = mSystemActivityMonitoringService.getFocusedStackForTopActivity(
199                activityName);
200        if (info == null) { // not top in focused stack
201            return true;
202        }
203        if (info.taskNames.length <= 1) { // nothing below this.
204            return false;
205        }
206        ComponentName activityBehind = ComponentName.unflattenFromString(
207                info.taskNames[info.taskNames.length - 2]);
208        return isActivityAllowedWhileDriving(activityBehind.getPackageName(),
209                activityBehind.getClassName());
210    }
211
212    public Looper getLooper() {
213        return mHandlerThread.getLooper();
214    }
215
216    private void assertPackageAndClassName(String packageName, String className) {
217        if (packageName == null) {
218            throw new IllegalArgumentException("Package name null");
219        }
220        if (className == null) {
221            throw new IllegalArgumentException("Class name null");
222        }
223    }
224
225    private AppBlockingPackageInfo searchFromBlacklistsLocked(String packageName) {
226        for (ClientPolicy policy : mClientPolicies.values()) {
227            AppBlockingPackageInfoWrapper wrapper = policy.blacklistsMap.get(packageName);
228            if (wrapper != null && wrapper.isMatching) {
229                return wrapper.info;
230            }
231        }
232        return null;
233    }
234
235    private AppBlockingPackageInfo searchFromWhitelistsLocked(String packageName) {
236        for (ClientPolicy policy : mClientPolicies.values()) {
237            AppBlockingPackageInfoWrapper wrapper = policy.whitelistsMap.get(packageName);
238            if (wrapper != null && wrapper.isMatching) {
239                return wrapper.info;
240            }
241        }
242        AppBlockingPackageInfoWrapper wrapper = mSystemWhitelists.get(packageName);
243        return (wrapper != null) ? wrapper.info : null;
244    }
245
246    private boolean isActivityInWhitelistsLocked(String packageName, String className) {
247        for (ClientPolicy policy : mClientPolicies.values()) {
248            if (isActivityInMapAndMatching(policy.whitelistsMap, packageName, className)) {
249                return true;
250            }
251        }
252        return isActivityInMapAndMatching(mSystemWhitelists, packageName, className);
253    }
254
255    private boolean isActivityInMapAndMatching(HashMap<String, AppBlockingPackageInfoWrapper> map,
256            String packageName, String className) {
257        AppBlockingPackageInfoWrapper wrapper = map.get(packageName);
258        if (wrapper == null || !wrapper.isMatching) {
259            return false;
260        }
261        return wrapper.info.isActivityCovered(className);
262    }
263
264    @Override
265    public void init() {
266        synchronized (this) {
267            mReleased = false;
268            mHandler.requestInit();
269        }
270        if (mEnableActivityBlocking) {
271            mSensorService.registerOrUpdateSensorListener(
272                    CarSensorManager.SENSOR_TYPE_DRIVING_STATUS, 0, mDrivingStateListener);
273            mDrivingStateListener.resetState();
274            mSystemActivityMonitoringService.registerActivityLaunchListener(
275                    mActivityLaunchListener);
276        }
277    }
278
279    @Override
280    public void release() {
281        synchronized (this) {
282            mReleased = true;
283            mHandler.requestRelease();
284            mSystemWhitelists.clear();
285            mClientPolicies.clear();
286            if (mProxies != null) {
287                for (AppBlockingPolicyProxy proxy : mProxies) {
288                    proxy.disconnect();
289                }
290                mProxies.clear();
291            }
292            wakeupClientsWaitingForPolicySetitngLocked();
293        }
294        if (mEnableActivityBlocking) {
295            mSensorService.unregisterSensorListener(CarSensorManager.SENSOR_TYPE_DRIVING_STATUS,
296                    mDrivingStateListener);
297            mSystemActivityMonitoringService.registerActivityLaunchListener(null);
298        }
299    }
300
301    // run from HandlerThread
302    private void doHandleInit() {
303        startAppBlockingPolicies();
304        generateSystemWhitelists();
305    }
306
307    private void wakeupClientsWaitingForPolicySetitngLocked() {
308        for (CarAppBlockingPolicy waitingPolicy : mWaitingPolicies) {
309            synchronized (waitingPolicy) {
310                waitingPolicy.notifyAll();
311            }
312        }
313        mWaitingPolicies.clear();
314    }
315
316    private void doSetPolicy() {
317        synchronized (this) {
318            wakeupClientsWaitingForPolicySetitngLocked();
319        }
320        blockTopActivitiesIfNecessary();
321    }
322
323    private void doUpdatePolicy(String packageName, CarAppBlockingPolicy policy, int flags) {
324        if (DBG_POLICY_SET) {
325            Log.i(CarLog.TAG_PACKAGE, "setting policy from:" + packageName + ",policy:" + policy +
326                    ",flags:0x" + Integer.toHexString(flags));
327        }
328        AppBlockingPackageInfoWrapper[] blacklistWrapper = verifyList(policy.blacklists);
329        AppBlockingPackageInfoWrapper[] whitelistWrapper = verifyList(policy.whitelists);
330        synchronized (this) {
331            ClientPolicy clientPolicy = mClientPolicies.get(packageName);
332            if (clientPolicy == null) {
333                clientPolicy = new ClientPolicy();
334                mClientPolicies.put(packageName, clientPolicy);
335            }
336            if ((flags & CarPackageManager.FLAG_SET_POLICY_ADD) != 0) {
337                clientPolicy.addToBlacklists(blacklistWrapper);
338                clientPolicy.addToWhitelists(whitelistWrapper);
339            } else if ((flags & CarPackageManager.FLAG_SET_POLICY_REMOVE) != 0) {
340                clientPolicy.removeBlacklists(blacklistWrapper);
341                clientPolicy.removeWhitelists(whitelistWrapper);
342            } else { //replace.
343                clientPolicy.replaceBlacklists(blacklistWrapper);
344                clientPolicy.replaceWhitelists(whitelistWrapper);
345            }
346            if ((flags & CarPackageManager.FLAG_SET_POLICY_WAIT_FOR_CHANGE) != 0) {
347                mWaitingPolicies.add(policy);
348            }
349            if (DBG_POLICY_SET) {
350                Log.i(CarLog.TAG_PACKAGE, "policy set:" + dumpPoliciesLocked(false));
351            }
352        }
353        blockTopActivitiesIfNecessary();
354    }
355
356    private AppBlockingPackageInfoWrapper[] verifyList(AppBlockingPackageInfo[] list) {
357        if (list == null) {
358            return null;
359        }
360        LinkedList<AppBlockingPackageInfoWrapper> wrappers = new LinkedList<>();
361        for (int i = 0; i < list.length; i++) {
362            AppBlockingPackageInfo info = list[i];
363            if (info == null) {
364                continue;
365            }
366            boolean isMatching = isInstalledPackageMatching(info);
367            wrappers.add(new AppBlockingPackageInfoWrapper(info, isMatching));
368        }
369        return wrappers.toArray(new AppBlockingPackageInfoWrapper[wrappers.size()]);
370    }
371
372    boolean isInstalledPackageMatching(AppBlockingPackageInfo info) {
373        PackageInfo packageInfo = null;
374        try {
375            packageInfo = mPackageManager.getPackageInfo(info.packageName,
376                    PackageManager.GET_SIGNATURES);
377        } catch (NameNotFoundException e) {
378            return false;
379        }
380        if (packageInfo == null) {
381            return false;
382        }
383        // if it is system app and client specified the flag, do not check signature
384        if ((info.flags & AppBlockingPackageInfo.FLAG_SYSTEM_APP) == 0 ||
385                (!packageInfo.applicationInfo.isSystemApp() &&
386                        !packageInfo.applicationInfo.isUpdatedSystemApp())) {
387            Signature[] signatires = packageInfo.signatures;
388            if (!isAnySignatureMatching(signatires, info.signatures)) {
389                return false;
390            }
391        }
392        int version = packageInfo.versionCode;
393        if (info.minRevisionCode == 0) {
394            if (info.maxRevisionCode == 0) { // all versions
395                return true;
396            } else { // only max version matters
397                return info.maxRevisionCode > version;
398            }
399        } else { // min version matters
400            if (info.maxRevisionCode == 0) {
401                return info.minRevisionCode < version;
402            } else {
403                return (info.minRevisionCode < version) && (info.maxRevisionCode > version);
404            }
405        }
406    }
407
408    /**
409     * Any signature from policy matching with package's signatures is treated as matching.
410     */
411    boolean isAnySignatureMatching(Signature[] fromPackage, Signature[] fromPolicy) {
412        if (fromPackage == null) {
413            return false;
414        }
415        if (fromPolicy == null) {
416            return false;
417        }
418        ArraySet<Signature> setFromPackage = new ArraySet<Signature>();
419        for (Signature sig : fromPackage) {
420            setFromPackage.add(sig);
421        }
422        for (Signature sig : fromPolicy) {
423            if (setFromPackage.contains(sig)) {
424                return true;
425            }
426        }
427        return false;
428    }
429
430    /**
431     * Return list of whitelist including default activity. Key is package name while
432     * value is list of activities. If list is empty, whole activities in the package
433     * are whitelisted.
434     * @return
435     */
436    private HashMap<String, Set<String>> parseConfigWhitelist() {
437        HashMap<String, Set<String>> packageToActivityMap = new HashMap<>();
438        Set<String> defaultActivity = new ArraySet<>();
439        defaultActivity.add(mActivityBlockingActivity.getClassName());
440        packageToActivityMap.put(mActivityBlockingActivity.getPackageName(), defaultActivity);
441        Resources res = mContext.getResources();
442        String whitelist = res.getString(R.string.defauiltActivityWhitelist);
443        String[] entries = whitelist.split(",");
444        for (String entry : entries) {
445            String[] packageActivityPair = entry.split("/");
446            Set<String> activities = packageToActivityMap.get(packageActivityPair[0]);
447            boolean newPackage = false;
448            if (activities == null) {
449                activities = new ArraySet<>();
450                newPackage = true;
451                packageToActivityMap.put(packageActivityPair[0], activities);
452            }
453            if (packageActivityPair.length == 1) { // whole package
454                activities.clear();
455            } else if (packageActivityPair.length == 2){
456                // add class name only when the whole package is not whitelisted.
457                if (newPackage || (activities.size() > 0)) {
458                    activities.add(packageActivityPair[1]);
459                }
460            }
461        }
462        return packageToActivityMap;
463    }
464
465    private void generateSystemWhitelists() {
466        HashMap<String, AppBlockingPackageInfoWrapper> systemWhitelists = new HashMap<>();
467        HashMap<String, Set<String>> configWhitelist = parseConfigWhitelist();
468        // trust all system apps for services and trust all activities with car app meta-data.
469        List<PackageInfo> packages = mPackageManager.getInstalledPackages(0);
470        for (PackageInfo info : packages) {
471            if (info.applicationInfo != null && (info.applicationInfo.isSystemApp() ||
472                    info.applicationInfo.isUpdatedSystemApp())) {
473                int flags = AppBlockingPackageInfo.FLAG_SYSTEM_APP;
474                Set<String> configActivitiesForPackage =
475                        configWhitelist.get(info.packageName);
476                if (configActivitiesForPackage != null) {
477                    if(configActivitiesForPackage.size() == 0) {
478                        flags |= AppBlockingPackageInfo.FLAG_WHOLE_ACTIVITY;
479                    }
480                } else {
481                    configActivitiesForPackage = new ArraySet<>();
482                }
483                String[] activities = null;
484                // Go through meta data if whole activities are allowed already
485                if ((flags & AppBlockingPackageInfo.FLAG_WHOLE_ACTIVITY) == 0) {
486                    CarAppMetadataInfo metadataInfo = CarAppMetadataReader.parseMetadata(mContext,
487                            info.packageName);
488                    if (metadataInfo != null) {
489                        if (metadataInfo.useAllActivities) {
490                            flags |= AppBlockingPackageInfo.FLAG_WHOLE_ACTIVITY;
491                        } else if(metadataInfo.activities != null) {
492                            for (String activity : metadataInfo.activities) {
493                                configActivitiesForPackage.add(activity);
494                            }
495                        }
496                    }
497                    if (configActivitiesForPackage.size() > 0) {
498                        activities = configActivitiesForPackage.toArray(
499                                new String[configActivitiesForPackage.size()]);
500                    }
501                }
502                AppBlockingPackageInfo appBlockingInfo = new AppBlockingPackageInfo(
503                        info.packageName, 0, 0, flags, null, activities);
504                AppBlockingPackageInfoWrapper wrapper = new AppBlockingPackageInfoWrapper(
505                        appBlockingInfo, true);
506                systemWhitelists.put(info.packageName, wrapper);
507            }
508        }
509        synchronized (this) {
510            mSystemWhitelists.putAll(systemWhitelists);
511        }
512    }
513
514    private void startAppBlockingPolicies() {
515        Intent policyIntent = new Intent();
516        policyIntent.setAction(CarAppBlockingPolicyService.SERVICE_INTERFACE);
517        List<ResolveInfo> policyInfos = mPackageManager.queryIntentServices(policyIntent, 0);
518        if (policyInfos == null) { //no need to wait for service binding and retrieval.
519            mHandler.requestPolicySetting();
520            return;
521        }
522        LinkedList<AppBlockingPolicyProxy> proxies = new LinkedList<>();
523        for (ResolveInfo resolveInfo : policyInfos) {
524            ServiceInfo serviceInfo = resolveInfo.serviceInfo;
525            if (serviceInfo == null) {
526                continue;
527            }
528            if (serviceInfo.isEnabled()) {
529                if (mPackageManager.checkPermission(Car.PERMISSION_CONTROL_APP_BLOCKING,
530                        serviceInfo.packageName) != PackageManager.PERMISSION_GRANTED) {
531                    continue;
532                }
533                Log.i(CarLog.TAG_PACKAGE, "found policy holding service:" + serviceInfo);
534                AppBlockingPolicyProxy proxy = new AppBlockingPolicyProxy(this, mContext,
535                        serviceInfo);
536                proxy.connect();
537                proxies.add(proxy);
538            }
539        }
540        synchronized (this) {
541            mProxies = proxies;
542        }
543    }
544
545    public void onPolicyConnectionAndSet(AppBlockingPolicyProxy proxy,
546            CarAppBlockingPolicy policy) {
547        doHandlePolicyConnection(proxy, policy);
548    }
549
550    public void onPolicyConnectionFailure(AppBlockingPolicyProxy proxy) {
551        doHandlePolicyConnection(proxy, null);
552    }
553
554    private void doHandlePolicyConnection(AppBlockingPolicyProxy proxy,
555            CarAppBlockingPolicy policy) {
556        boolean shouldSetPolicy = false;
557        synchronized (this) {
558            if (mProxies == null) {
559                proxy.disconnect();
560                return;
561            }
562            mProxies.remove(proxy);
563            if (mProxies.size() == 0) {
564                shouldSetPolicy = true;
565                mProxies = null;
566            }
567        }
568        try {
569            if (policy != null) {
570                if (DBG_POLICY_SET) {
571                    Log.i(CarLog.TAG_PACKAGE, "policy setting from policy service:" +
572                            proxy.getPackageName());
573                }
574                doSetAppBlockingPolicy(proxy.getPackageName(), policy, 0, false /*setNow*/);
575            }
576        } finally {
577            proxy.disconnect();
578            if (shouldSetPolicy) {
579                mHandler.requestPolicySetting();
580            }
581        }
582    }
583
584    @Override
585    public void dump(PrintWriter writer) {
586        synchronized (this) {
587            writer.println("*PackageManagementService*");
588            writer.println("mEnableActivityBlocking:" + mEnableActivityBlocking);
589            writer.println("ActivityRestricted:" + mDrivingStateListener.isRestricted());
590            writer.print(dumpPoliciesLocked(true));
591        }
592    }
593
594    private String dumpPoliciesLocked(boolean dumpAll) {
595        StringBuilder sb = new StringBuilder();
596        if (dumpAll) {
597            sb.append("**System white list**\n");
598            for (AppBlockingPackageInfoWrapper wrapper : mSystemWhitelists.values()) {
599                sb.append(wrapper.toString() + "\n");
600            }
601        }
602        sb.append("**Client Policies**\n");
603        for (Entry<String, ClientPolicy> entry : mClientPolicies.entrySet()) {
604            sb.append("Client:" + entry.getKey() + "\n");
605            sb.append("  whitelists:\n");
606            for (AppBlockingPackageInfoWrapper wrapper : entry.getValue().whitelistsMap.values()) {
607                sb.append(wrapper.toString() + "\n");
608            }
609            sb.append("  blacklists:\n");
610            for (AppBlockingPackageInfoWrapper wrapper : entry.getValue().blacklistsMap.values()) {
611                sb.append(wrapper.toString() + "\n");
612            }
613        }
614        sb.append("**Unprocessed policy services**\n");
615        if (mProxies != null) {
616            for (AppBlockingPolicyProxy proxy : mProxies) {
617                sb.append(proxy.toString() + "\n");
618            }
619        }
620        return sb.toString();
621    }
622
623    private void blockTopActivityIfNecessary(TopTaskInfoContainer topTask) {
624        boolean restricted = mDrivingStateListener.isRestricted();
625        if (!restricted) {
626            return;
627        }
628        doBlockTopActivityIfNotAllowed(topTask);
629    }
630
631    private void doBlockTopActivityIfNotAllowed(TopTaskInfoContainer topTask) {
632        boolean allowed = isActivityAllowedWhileDriving(
633                topTask.topActivity.getPackageName(),
634                topTask.topActivity.getClassName());
635        if (DBG_POLICY_ENFORCEMENT) {
636            Log.i(CarLog.TAG_PACKAGE, "new activity:" + topTask.toString() + " allowed:" + allowed);
637        }
638        if (!allowed) {
639            Log.i(CarLog.TAG_PACKAGE, "Current activity " + topTask.topActivity +
640                    " not allowed, will block, number of tasks in stack:" +
641                    topTask.stackInfo.taskIds.length);
642            Intent newActivityIntent = new Intent();
643            newActivityIntent.setComponent(mActivityBlockingActivity);
644            newActivityIntent.putExtra(
645                    ActivityBlockingActivity.INTENT_KEY_BLOCKED_ACTIVITY,
646                    topTask.topActivity.flattenToString());
647            mSystemActivityMonitoringService.blockActivity(topTask, newActivityIntent);
648        }
649    }
650
651    private void blockTopActivitiesIfNecessary() {
652        boolean restricted = mDrivingStateListener.isRestricted();
653        if (!restricted) {
654            return;
655        }
656        List<TopTaskInfoContainer> topTasks = mSystemActivityMonitoringService.getTopTasks();
657        for (TopTaskInfoContainer topTask : topTasks) {
658            doBlockTopActivityIfNotAllowed(topTask);
659        }
660    }
661
662    /**
663     * Reading policy and setting policy can take time. Run it in a separate handler thread.
664     */
665    private class PackageHandler extends Handler {
666        private final int MSG_INIT = 0;
667        private final int MSG_SET_POLICY = 1;
668        private final int MSG_UPDATE_POLICY = 2;
669
670        private PackageHandler(Looper looper) {
671            super(looper);
672        }
673
674        private void requestInit() {
675            Message msg = obtainMessage(MSG_INIT);
676            sendMessage(msg);
677        }
678
679        private void requestRelease() {
680            removeMessages(MSG_INIT);
681            removeMessages(MSG_SET_POLICY);
682            removeMessages(MSG_UPDATE_POLICY);
683        }
684
685        private void requestPolicySetting() {
686            Message msg = obtainMessage(MSG_SET_POLICY);
687            sendMessage(msg);
688        }
689
690        private void requestUpdatingPolicy(String packageName, CarAppBlockingPolicy policy,
691                int flags) {
692            Pair<String, CarAppBlockingPolicy> pair = new Pair<>(packageName, policy);
693            Message msg = obtainMessage(MSG_UPDATE_POLICY, flags, 0, pair);
694            sendMessage(msg);
695        }
696
697        @Override
698        public void handleMessage(Message msg) {
699            switch (msg.what) {
700                case MSG_INIT:
701                    doHandleInit();
702                    break;
703                case MSG_SET_POLICY:
704                    doSetPolicy();
705                    break;
706                case MSG_UPDATE_POLICY:
707                    Pair<String, CarAppBlockingPolicy> pair =
708                            (Pair<String, CarAppBlockingPolicy>) msg.obj;
709                    doUpdatePolicy(pair.first, pair.second, msg.arg1);
710                    break;
711            }
712        }
713    }
714
715    private static class AppBlockingPackageInfoWrapper {
716        private final AppBlockingPackageInfo info;
717        /**
718         * Whether the current info is matching with the target package in system. Mismatch can
719         * happen for version out of range or signature mismatch.
720         */
721        private boolean isMatching;
722
723        private AppBlockingPackageInfoWrapper(AppBlockingPackageInfo info, boolean isMatching) {
724            this.info =info;
725            this.isMatching = isMatching;
726        }
727
728        @Override
729        public String toString() {
730            return "AppBlockingPackageInfoWrapper [info=" + info + ", isMatching=" + isMatching +
731                    "]";
732        }
733    }
734
735    /**
736     * Client policy holder per each client. Should be accessed with CarpackageManagerService.this
737     * held.
738     */
739    private static class ClientPolicy {
740        private final HashMap<String, AppBlockingPackageInfoWrapper> whitelistsMap =
741                new HashMap<>();
742        private final HashMap<String, AppBlockingPackageInfoWrapper> blacklistsMap =
743                new HashMap<>();
744
745        private void replaceWhitelists(AppBlockingPackageInfoWrapper[] whitelists) {
746            whitelistsMap.clear();
747            addToWhitelists(whitelists);
748        }
749
750        private void addToWhitelists(AppBlockingPackageInfoWrapper[] whitelists) {
751            if (whitelists == null) {
752                return;
753            }
754            for (AppBlockingPackageInfoWrapper wrapper : whitelists) {
755                if (wrapper != null) {
756                    whitelistsMap.put(wrapper.info.packageName, wrapper);
757                }
758            }
759        }
760
761        private void removeWhitelists(AppBlockingPackageInfoWrapper[] whitelists) {
762            if (whitelists == null) {
763                return;
764            }
765            for (AppBlockingPackageInfoWrapper wrapper : whitelists) {
766                if (wrapper != null) {
767                    whitelistsMap.remove(wrapper.info.packageName);
768                }
769            }
770        }
771
772        private void replaceBlacklists(AppBlockingPackageInfoWrapper[] blacklists) {
773            blacklistsMap.clear();
774            addToBlacklists(blacklists);
775        }
776
777        private void addToBlacklists(AppBlockingPackageInfoWrapper[] blacklists) {
778            if (blacklists == null) {
779                return;
780            }
781            for (AppBlockingPackageInfoWrapper wrapper : blacklists) {
782                if (wrapper != null) {
783                    blacklistsMap.put(wrapper.info.packageName, wrapper);
784                }
785            }
786        }
787
788        private void removeBlacklists(AppBlockingPackageInfoWrapper[] blacklists) {
789            if (blacklists == null) {
790                return;
791            }
792            for (AppBlockingPackageInfoWrapper wrapper : blacklists) {
793                if (wrapper != null) {
794                    blacklistsMap.remove(wrapper.info.packageName);
795                }
796            }
797        }
798    }
799
800    private class ActivityLaunchListener
801        implements SystemActivityMonitoringService.ActivityLaunchListener {
802        @Override
803        public void onActivityLaunch(TopTaskInfoContainer topTask) {
804            blockTopActivityIfNecessary(topTask);
805        }
806    }
807
808    private class SensorListener extends ICarSensorEventListener.Stub {
809        private int mLatestDrivingState;
810
811        private void resetState() {
812            CarSensorEvent lastEvent = mSensorService.getLatestSensorEvent(
813                    CarSensorManager.SENSOR_TYPE_DRIVING_STATUS);
814            boolean shouldBlock = false;
815            synchronized (this) {
816                if (lastEvent == null) {
817                    // When driving status is not available yet, do not block.
818                    // This happens during bootup.
819                    mLatestDrivingState = CarSensorEvent.DRIVE_STATUS_UNRESTRICTED;
820                } else {
821                    mLatestDrivingState = lastEvent.intValues[0];
822                }
823                if (mLatestDrivingState != CarSensorEvent.DRIVE_STATUS_UNRESTRICTED) {
824                    shouldBlock = true;
825                }
826            }
827            if (shouldBlock) {
828                blockTopActivitiesIfNecessary();
829            }
830        }
831
832        private synchronized boolean isRestricted() {
833            return mLatestDrivingState != CarSensorEvent.DRIVE_STATUS_UNRESTRICTED;
834        }
835
836        @Override
837        public void onSensorChanged(List<CarSensorEvent> events) {
838            resetState();
839        }
840    }
841}
842