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